diff options
396 files changed, 21028 insertions, 12898 deletions
diff --git a/.gitignore b/.gitignore index e79ba02cd..127a8ac7b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,6 +14,7 @@ Makefile Makefile.in aclocal.m4 autom4te.cache +config.cache config.guess config.log config.status diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a5bc4a0b..8ad8b4abe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,7 +148,9 @@ option(ENABLE_IPV6 "Define if you want to enable IPv6 support" OFF) mark_as_advanced(ENABLE_IPV6) if(WIN32) - list_spaces_append_once(CMAKE_C_STANDARD_LIBRARIES wsock32.lib ws2_32.lib) # bufferoverflowu.lib + find_library(WSOCK32_LIBRARY wsock32) + find_library(WS2_32_LIBRARY ws2_32) + list_spaces_append_once(CMAKE_C_STANDARD_LIBRARIES ${WSOCK32_LIBRARY} ${WS2_32_LIBRARY}) # bufferoverflowu.lib if(CURL_DISABLE_LDAP) # Remove wldap32.lib from space-separated list string(REPLACE " " ";" _LIST ${CMAKE_C_STANDARD_LIBRARIES}) @@ -861,4 +863,3 @@ install(DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/include/curl" DESTINATION include FILES_MATCHING PATTERN "*.h" PATTERN "curlbuild.h" EXCLUDE) -
\ No newline at end of file diff --git a/Makefile.dist b/Makefile.dist index 55bab370a..a4fbef15c 100644 --- a/Makefile.dist +++ b/Makefile.dist @@ -73,10 +73,15 @@ mingw32: mingw32-clean: $(MAKE) -C lib -f Makefile.m32 clean $(MAKE) -C src -f Makefile.m32 clean + $(MAKE) -C docs/examples -f Makefile.m32 clean mingw32-vclean mingw32-distclean: $(MAKE) -C lib -f Makefile.m32 vclean $(MAKE) -C src -f Makefile.m32 vclean + $(MAKE) -C docs/examples -f Makefile.m32 vclean + +mingw32-examples%: + $(MAKE) -C docs/examples -f Makefile.m32 CFG=$@ mingw32%: $(MAKE) -C lib -f Makefile.m32 CFG=$@ @@ -217,34 +222,27 @@ netware: $(MAKE) -C lib -f Makefile.netware $(MAKE) -C src -f Makefile.netware -netware-ares: - $(MAKE) -C lib -f Makefile.netware WITH_ARES=1 - $(MAKE) -C src -f Makefile.netware WITH_ARES=1 - -netware-ssl: - $(MAKE) -C lib -f Makefile.netware WITH_SSL=1 - $(MAKE) -C src -f Makefile.netware WITH_SSL=1 - -netware-ssl-zlib: - $(MAKE) -C lib -f Makefile.netware WITH_SSL=1 WITH_ZLIB=1 - $(MAKE) -C src -f Makefile.netware WITH_SSL=1 WITH_ZLIB=1 - -netware-ssh2-ssl-zlib: - $(MAKE) -C lib -f Makefile.netware WITH_SSH2=1 WITH_SSL=1 WITH_ZLIB=1 - $(MAKE) -C src -f Makefile.netware WITH_SSH2=1 WITH_SSL=1 WITH_ZLIB=1 - -netware-zlib: - $(MAKE) -C lib -f Makefile.netware WITH_ZLIB=1 - $(MAKE) -C src -f Makefile.netware WITH_ZLIB=1 - netware-clean: $(MAKE) -C lib -f Makefile.netware clean $(MAKE) -C src -f Makefile.netware clean + $(MAKE) -C docs/examples -f Makefile.netware clean + +netware-vclean netware-distclean: + $(MAKE) -C lib -f Makefile.netware vclean + $(MAKE) -C src -f Makefile.netware vclean + $(MAKE) -C docs/examples -f Makefile.netware vclean netware-install: $(MAKE) -C lib -f Makefile.netware install $(MAKE) -C src -f Makefile.netware install +netware-examples-%: + $(MAKE) -C docs/examples -f Makefile.netware CFG=$@ + +netware-%: + $(MAKE) -C lib -f Makefile.netware CFG=$@ + $(MAKE) -C src -f Makefile.netware CFG=$@ + unix: all unix-ssl: ssl diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 9ab87166a..404f70474 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -1,19 +1,45 @@ -Curl and libcurl 7.21.8 +Curl and libcurl 7.23.0 - Public curl releases: 124 - Command line options: 144 - curl_easy_setopt() options: 186 + Public curl releases: 125 + Command line options: 149 + curl_easy_setopt() options: 192 Public functions in libcurl: 58 Known libcurl bindings: 39 - Contributors: 868 + Contributors: 873 This release includes the following changes: - o + o Empty headers can be sent in HTTP requests by terminating with a semicolon + o SSL session sharing support added to curl_share_setopt() + o Added support to MAIL FROM for the optional SIZE parameter + o smtp: Added support for NTLM authentication + o curl tool: code split into tool_*.[ch] files This release includes the following bugfixes: - o curl_getdate: detect some illegal dates better + o handle HTTP redirects to "//hostname/path" + o SMTP without --mail-from caused segfault + o prevent extra progress meter headers between multiple files + o allow Content-Length to be replaced when sending HTTP requests + o curl now always sets postfieldsize to allow --data-binary and --data + to be mixed in the same command line + o curl_multi_fdset: avoid FD_SET out of bounds + o lots of MinGW build tweaks + o Curl_gethostname: return un-qualified machine name + o fixed the openssl version number configure check + o nss: certificates from files are no longer looked up by file base names + o returning abort from the progress function when using the multi interface + would not properly cancel the transfer and close the connection + o fix libcurl.m4 to not fail with modern gcc versions + o ftp: improved the failed PORT host name resolved error message + o TFTP timeout and unexpected block adjustments + o HTTP and GOPHER test server-side connection closing adjustments + o fix endless loop upon transport connection timeout + o don't clobber errno on failed connect + o typecheck: allow NULL to unset CURLOPT_ERRORBUFFER + o formdata: ack read callback abort + o make --show-error properly position independent + o set the ipv6-connection boolean correctly on connect This release includes the following known bugs: @@ -22,6 +48,11 @@ This release includes the following known bugs: This release would not have looked like this without help, code, reports and advice from friends like these: - Paolo Piacentini + Yukihiro Kawada, Dave Reisner, Gisle Vanem, Guenter Knauf, Steve Holme, + Yang Tse, Christopher Stone, Taneli Vahakangas, Albert Chin, + Alejandro Alvarez, Dan Fandrich, Julien Royer, Georg Lippitsch, + Vladimir Grishchenko, Dominique Leuenberger, Marcin Adamski, + Jerry Wu, Michal Marek, Frank Van Uffelen, Fabian Hiernaux, Anton Bychkov, + Andreas Olsson, Kamil Dudka, Thomas L. Shinnick Thanks! (and sorry if I forgot to mention someone) diff --git a/TODO-RELEASE b/TODO-RELEASE index a91c2c274..6c94376fc 100644 --- a/TODO-RELEASE +++ b/TODO-RELEASE @@ -1,15 +1,11 @@ -To be addressed in 7.21.6 +To be addressed in 7.22.1 ========================= -284 - bug 3172608 "No re-authentication when HTTP connecton is closed" - http://curl.haxx.se/bug/view.cgi?id=3172608 - Would be nice if someone could verify the suggested patch +295 - "RTSP Authentication (#22)" https://github.com/bagder/curl/pull/22 -285 - bug 3163118 "Allow programatic use of telnet on Windows" - http://curl.haxx.se/bug/view.cgi?id=3163118 - Would appreciate a Windows developer to give it a look before we apply - the suggested patch +296 - "OOM leak in multi code" (by Dan Fandrich) -287 - bug 3215314 Post quote operation to rename fails in Windows +300 - "Polling on stray socket on sequential transfers." Andrew S + http://curl.haxx.se/mail/lib-2011-07/0053.html -289 - +308 - diff --git a/acinclude.m4 b/acinclude.m4 index bf97b94cb..3a3122d58 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -51,7 +51,7 @@ CURL_DEF_TOKEN $1 ],[ 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/.*CURL_DEF_TOKEN[[ ]][[ ]]*//' 2>/dev/null | \ "$SED" 's/[["]][[ ]]*[["]]//g' 2>/dev/null` if test -z "$tmp_exp" || test "$tmp_exp" = "$1"; then tmp_exp="" @@ -80,7 +80,7 @@ removethis(){ # Ensure that buildconf runs from the subdirectory where configure.ac lives # if test ! -f configure.ac || - test ! -f src/main.c || + test ! -f src/tool_main.c || test ! -f lib/urldata.h || test ! -f include/curl/curl.h; then echo "Can not run buildconf from outside of curl's source subdirectory!" @@ -89,7 +89,9 @@ if test ! -f configure.ac || fi #-------------------------------------------------------------------------- -# autoconf 2.57 or newer +# autoconf 2.57 or newer. Unpatched version 2.67 does not generate proper +# configure script. Unpatched version 2.68 is simply unusable, we should +# disallow 2.68 usage. # need_autoconf="2.57" ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|head -n 1| sed -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` @@ -108,7 +110,15 @@ if test "$1" = "2" -a "$2" -lt "57" || test "$1" -lt "2"; then exit 1 fi -echo "buildconf: autoconf version $ac_version (ok)" +if test "$1" = "2" -a "$2" -eq "67"; then + echo "buildconf: autoconf version $ac_version (BAD)" + echo " Unpatched version generates broken configure script." +elif test "$1" = "2" -a "$2" -eq "68"; then + echo "buildconf: autoconf version $ac_version (BAD)" + echo " Unpatched version generates unusable configure script." +else + echo "buildconf: autoconf version $ac_version (ok)" +fi am4te_version=`${AUTOM4TE:-autom4te} --version 2>/dev/null|head -n 1| sed -e 's/autom4te\(.*\)/\1/' -e 's/^[^0-9]*//' -e 's/[a-z]* *$//'` if test -z "$am4te_version"; then diff --git a/buildconf.bat b/buildconf.bat index b845d6eed..b00364c47 100644 --- a/buildconf.bat +++ b/buildconf.bat @@ -27,6 +27,11 @@ if not exist include\curl\curlbuild.h.dist goto end_curlbuild_h copy /Y include\curl\curlbuild.h.dist include\curl\curlbuild.h :end_curlbuild_h +REM create src\config-win32.h +if not exist lib\config-win32.h goto end_config_win32_h +copy /Y lib\config-win32.h src\config-win32.h +:end_config_win32_h + REM setup c-ares git tree if not exist ares\buildconf.bat goto end_c_ares cd ares diff --git a/configure.ac b/configure.ac index e9b49c788..64ee1b7a6 100644 --- a/configure.ac +++ b/configure.ac @@ -314,6 +314,26 @@ if test "x$cross_compiling" != "xno" && 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 @@ -1330,7 +1350,7 @@ if test X"$OPT_SSL" != Xno; then dnl the user told us to look OPENSSL_PCDIR="$OPT_SSL/lib/pkgconfig" AC_MSG_NOTICE([PKG_CONFIG_LIBDIR will be set to "$OPENSSL_PCDIR"]) - if test -e "$OPENSSL_PCDIR/openssl.pc"; then + if test -f "$OPENSSL_PCDIR/openssl.pc"; then PKGTEST="yes" fi @@ -2419,6 +2439,7 @@ AC_CHECK_HEADERS( stdbool.h \ arpa/tftp.h \ sys/filio.h \ + sys/wait.h \ setjmp.h, dnl to do if not found [], @@ -2564,6 +2585,7 @@ 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_STRCASESTR CURL_CHECK_FUNC_STRCMPI @@ -2794,6 +2816,10 @@ AC_HELP_STRING([--disable-crypto-auth],[Disable cryptographic authentication]), AC_MSG_RESULT(yes) ) +CURL_CHECK_OPTION_NTLM_WB + +CURL_CHECK_NTLM_WB + dnl ************************************************************ dnl disable TLS-SRP authentication dnl @@ -2969,6 +2995,9 @@ if test "x$CURL_DISABLE_HTTP" != "x1"; then if test "x$USE_SSLEAY" = "x1" -o "x$USE_WINDOWS_SSPI" = "x1" \ -o "x$GNUTLS_ENABLED" = "x1" -o "x$NSS_ENABLED" = "x1"; then SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM" + if test "x$NTLM_WB_ENABLED" = "x1"; then + SUPPORT_FEATURES="$SUPPORT_FEATURES NTLM_WB" + fi fi fi if test "x$USE_TLS_SRP" = "x1"; then @@ -6,21 +6,34 @@ BUGS + 1. Bugs + 1.1 There are still bugs + 1.2 Where to report + 1.3 What to report + 1.4 libcurl problems + 1.5 Who will fix the problems + 1.6 How to get a stack trace + 1.7 Bugs in libcurl bindings + +============================================================================== + +1.1 There are still bugs + Curl and libcurl have grown substantially since the beginning. At the time - of writing (July 2007), there are about 47000 lines of source code, and by - the time you read this it has probably grown even more. + of writing (September 2011), there are about 66000 lines of source code, and + by the time you read this it has probably grown even more. Of course there are lots of bugs left. And lots of 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 +1.2 Where to report If you can't 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 should also post your bug/problem at curl's bug - tracking system over at + have a go at a solution. You can optionally also post your bug/problem at + curl's bug tracking system over at http://sourceforge.net/bugs/?group_id=976 @@ -29,16 +42,18 @@ WHERE TO REPORT If you feel you need to ask around first, find a suitable mailing list and post there. The lists are available on http://curl.haxx.se/mail/ -WHAT TO REPORT +1.3 What to report When reporting a bug, you should include all information that will help us understand what's 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 (uname -a under a unix - is fine) + - your operating system's name and version number + - what version of curl you're 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 @@ -59,7 +74,48 @@ WHAT TO REPORT The address and how to subscribe to the mailing lists are detailed in the MANUAL file. -HOW TO GET A STACK TRACE +1.4 libcurl problems + + First, post all libcurl problems on the curl-library mailing list. + + When you've 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're 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 adviced + 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. + +1.5 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. + + But 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've 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. + +1.6 How to get a stack trace First, you must make sure that you compile all sources with -g and that you don't 'strip' the final executable. Try to avoid optimizing the code as @@ -79,3 +135,12 @@ HOW TO GET A STACK TRACE crashed. Include the stack trace with your detailed bug report. It'll help a lot. +1.7 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. diff --git a/docs/INSTALL b/docs/INSTALL index 17550dc60..e0134e8a2 100644 --- a/docs/INSTALL +++ b/docs/INSTALL @@ -467,6 +467,34 @@ Win32 in the vc6libcurl.dsw/vc6libcurl.dsp Visual C++ 6 IDE project. + 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 definition of 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 lib/Makefile.vc6 + - Add definition to Project/Settings/C/C++/General/Preprocessor Definitions + in the vc6libcurl.dsw/vc6libcurl.dsp Visual C++ 6 IDE project. + + 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 <lwip/opt.h> (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 and contrib-1.4.0 from: + + http://download.savannah.gnu.org/releases/lwip/lwip-1.4.0.zip + http://download.savannah.gnu.org/releases/lwip/contrib-1.4.0.zip + + 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, caveat emptor. + Important static libcurl usage note ----------------------------------- diff --git a/docs/KNOWN_BUGS b/docs/KNOWN_BUGS index 96478917d..a05128446 100644 --- a/docs/KNOWN_BUGS +++ b/docs/KNOWN_BUGS @@ -12,12 +12,6 @@ may have been fixed since this was written! http://curl.haxx.se/mail/lib-2009-10/0024.html http://curl.haxx.se/bug/view.cgi?id=2944325 -74. The HTTP spec allows headers to be merged and become comma-separated - instead of being repeated several times. This also include Authenticate: and - Proxy-Authenticate: headers and while this hardly every happens in real life - it will confuse libcurl which does not properly support it for all headers - - like those Authenticate headers. - 73. if a connection is made to a FTP server but the server then just never sends the 220 response or otherwise is dead slow, libcurl will not acknowledge the connection timeout during that phase but only the "real" diff --git a/docs/THANKS b/docs/THANKS index 6e1bfd9fe..b93b1fe2e 100644 --- a/docs/THANKS +++ b/docs/THANKS @@ -5,10 +5,13 @@ If you have contributed but are missing here, please let us know! Aaron Oneal +Aaron Orenstein Adam D. Moss Adam Light Adam Piggott +Adam Tkac Adrian Schuur +Adriano Meirelles Akos Pasztory Alan Pinstein Albert Chin-A-Young @@ -80,6 +83,7 @@ Ben Greear Ben Madsen Ben Noordhuis Ben Van Hof +Ben Winslow Benbuck Nason Benjamin Gerard Bernard Leak @@ -125,6 +129,7 @@ Chris Gaukroger Chris Maltby Chris Mumford Chris Smowton +Christian Hagele Christian Krause Christian Kurz Christian Robottom Reis @@ -149,8 +154,10 @@ Craig A West Craig Davison Craig Markwardt Cris Bailiff +Cristian Rodriguez Curt Bogmine Cyrill Osterwalder +Dagobert Michelsen Damien Adant Dan Becker Dan C @@ -275,6 +282,7 @@ Fred New Fred Noz Frederic Lepied Gabriel Kuri +Garrett Holmstrom Gary Maxwell Gautam Kachroo Gautam Mani @@ -323,6 +331,7 @@ Heinrich Ko Hendrik Visage Henrik Storner Henry Ludemann +Herve Amblard Hidemoto Nakada Hoi-Ho Chan Hongli Lai @@ -389,6 +398,7 @@ Jesper Jensen Jesse Noller Jim Drash Jim Freeman +Jim Hollinger Jim Meyering Jocelyn Jaubert Joe Halpin @@ -503,6 +513,7 @@ Luke Call Luong Dinh Dung Maciej Karpiuk Maciej W. Rozycki +Mandy Wu Manfred Schwarb Manuel Massing Marc Boucher @@ -544,6 +555,7 @@ Matt Kraai Matt Veenstra Matt Witherspoon Matt Wixson +Matteo Rocco Matthew Blain Matthew Clarke Matthias Bolte @@ -563,6 +575,7 @@ Michael Goffioul Michael Jahn Michael Jerris Michael Mealling +Michael Mueller Michael Smith Michael Stillwell Michael Wallner @@ -615,7 +628,9 @@ Ofer Olaf Stueben Olaf Stüben Oren Tirosh +Ori Avtalion P R Schaffner +Paolo Piacentini Pascal Terjan Pasha Kuznetsov Pat Ray @@ -624,6 +639,7 @@ Patrick Monnerat Patrick Scott Patrick Smith Patrik Thunstrom +Pau Garcia i Quiles Paul Harrington Paul Howarth Paul Marquis @@ -641,6 +657,7 @@ Pete Su Peter Bray Peter Forret Peter Heuchert +Peter Hjalmarsson Peter Korsgaard Peter Lamberg Peter O'Gorman @@ -700,6 +717,7 @@ Richard Clayton Richard Cooper Richard Gorton Richard Prescott +Richard Silverman Rick Jones Rick Richardson Rob Crittenden @@ -778,6 +796,7 @@ Stephen Kick Stephen More Sterling Hughes Steve Green +Steve Holme Steve Lhomme Steve Little Steve Marx @@ -786,6 +805,7 @@ Steve Roskowski Steven Bazyl Steven G. Johnson Steven M. Schweda +Steven Parkes Stoned Elipot Sven Anders Sven Neuhaus @@ -861,6 +881,7 @@ Wesley Miaw Wez Furlong Wilfredo Sanchez Wojciech Zwiefka +Wu Yongzheng Xavier Bouchoux Yang Tse Yarram Sunil @@ -12,16 +12,15 @@ All bugs documented in the KNOWN_BUGS document are subject for fixing! 1. libcurl - 1.1 Zero-copy interface 1.2 More data sharing 1.3 struct lifreq 1.4 signal-based resolver timeouts 1.5 get rid of PATH_MAX + 1.6 progress callback without doubles 2. libcurl - multi interface 2.1 More non-blocking 2.2 Remove easy interface internally - 2.3 Avoid having to remove/readd handles 2.4 Fix HTTP Pipelining for PUT 3. Documentation @@ -54,12 +53,10 @@ 7.5 Export session ids 7.6 Provide callback for cert verification 7.7 Support other SSL libraries - 7.8 Support SRP on the TLS layer 7.9 improve configure --with-ssl 8. GnuTLS 8.1 SSL engine stuff - 8.2 SRP 8.3 check connection 8.4 non-gcrypt @@ -77,6 +74,7 @@ 11.6 url-specific options 11.7 metalink support 11.8 warning when setting an option + 11.9 IPv6 addresses with globbing 12. Build 12.1 roffit @@ -100,17 +98,13 @@ 15.5 remove CURLOPT_FAILONERROR 15.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE 15.7 remove progress meter from libcurl + 15.8 remove 'curl_httppost' from public + 15.9 have form functions use CURL handle argument ============================================================================== 1. libcurl -1.1 Zero-copy interface - - Introduce another callback interface for upload/download that makes one less - copy of data and thus a faster operation. - [http://curl.haxx.se/dev/no_copy_callbacks.txt] - 1.2 More data sharing curl_share_* functions already exist and work, and they can be extended to @@ -144,6 +138,15 @@ 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) doesn't. +1.6 progress callback without doubles + + The progress callback was introduced way back in the days and the choice to + use doubles in the arguments was possibly good at the time. Today the doubles + only confuse users and make the amounts less precise. We should introduce + another progress callback option that take precedence over the old one and + have both co-exist for a forseeable time until we can remove the double-using + one. + 2. libcurl - multi interface 2.1 More non-blocking @@ -170,23 +173,6 @@ internally use and assume the multi interface. The select()-loop should use curl_multi_socket(). -2.3 Avoid having to remove/readd handles - - curl_multi_handle_control() - this can control the easy handle (while) added - to a multi handle in various ways: - - o RESTART, unconditionally restart this easy handle's transfer from the - start, re-init the state - - o RESTART_COMPLETED, restart this easy handle's transfer but only if the - existing transfer has already completed and it is in a "finished state". - - o STOP, just stop this transfer and consider it completed - - o PAUSE? - - o RESUME? - 2.4 Fix HTTP Pipelining for PUT HTTP Pipelining can be a way to greatly enhance performance for multiple @@ -334,12 +320,6 @@ to provide the data to send. Make curl's SSL layer capable of using other free SSL libraries. Such as MatrixSSL (http://www.matrixssl.org/). -7.8 Support SRP on the TLS layer - - Peter Sylvester's patch for SRP on the TLS layer. Awaits OpenSSL support for - this, no need to support this in libcurl before there's an OpenSSL release - that does it. - 7.9 improve configure --with-ssl make the configure --with-ssl option first check for OpenSSL, then GnuTLS, @@ -351,11 +331,6 @@ to provide the data to send. Is this even possible? -8.2 SRP - - Work out a common method with Peter Sylvester's OpenSSL-patch for SRP on the - TLS to provide name and password. GnuTLS already supports it... - 8.3 check connection Add a way to check if the connection seems to be alive, to correspond to the @@ -451,6 +426,13 @@ to provide the data to send. This can be useful to tell when support for a particular feature hasn't been compiled into the library. +11.9 IPv6 addresses with globbing + + Currently the command line client needs to get url globbing disabled (with + -g) for it to support IPv6 numerical addresses. This is a rather silly flaw + that should be corrected. It probably involves a smarter detection of the + '[' and ']' letters. + 12. Build 12.1 roffit @@ -569,3 +551,20 @@ to provide the data to send. The progress callback should then be bumped as well to get proper 64bit variable types passed to it instead of doubles so that big files work correctly. + +15.8 remove 'curl_httppost' from public + + curl_formadd() was made to fill in a public struct, but the fact that the + struct is public is never really used by application for their own advantage + but instead often restricts how the form functions can or can't be modified. + + Changing them to return a private handle will benefit the implementation and + allow us much greater freedoms while still maintining a solid API and ABI. + +15.9 have form functions use CURL handle argument + + curl_formadd() and curl_formget() both currently have no CURL handle + argument, but both can use a callback that is set in the easy handle, and + thus curl_formget() with callback cannot function without first having + curl_easy_perform() (or similar) called - which is hard to grasp and a design + mistake. diff --git a/docs/VERSIONS b/docs/VERSIONS index 21c0d901a..0670089bd 100644 --- a/docs/VERSIONS +++ b/docs/VERSIONS @@ -11,32 +11,25 @@ Version Numbers and Releases The version numbering is always built up using the same system: - X.Y[.Z][-preN] + X.Y[.Z] Where X is main version number Y is release number Z is patch number - N is pre-release number 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. If Z is zero, it may not be - included in the version number. The pre release number is only included in - pre releases (they're never used in public, official, releases). + included in the version number. The main version number will get bumped when *really* big, world colliding - changes are made. The release number is bumped when big changes are - performed. The patch number is bumped when the changes are mere bugfixes and - only minor feature changes. The pre-release is a counter, to identify which - pre-release a certain release is. - - When reaching the end of a pre-release period, the version without the - pre-release part will be released as a public release. + 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 if something really big has been made, 1.3 if not that big changes were made or 1.2.4 if mostly bugs - were fixed. Before 1.2.4 is released, we might release a 1.2.4-pre1 release - for the brave people to try before the actual release. + 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 @@ -56,12 +49,12 @@ Version Numbers and Releases #define LIBCURL_VERSION_NUM 0xXXYYZZ Where XX, YY and ZZ are the main version, release and patch numbers in - hexadecimal. All three numbers are always represented using two digits. 1.2 - would appear as "0x010200" while version 9.11.7 appears as "0x090b07". + 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 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. + 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/curl.1 b/docs/curl.1 index 812b2ebce..95828bfad 100644 --- a/docs/curl.1 +++ b/docs/curl.1 @@ -194,7 +194,10 @@ no file will be written. The file will be written using the Netscape cookie file format. If you set the file name to a single dash, "-", the cookies will be written to stdout. -.B NOTE +This command line option will activate the cookie engine that makes curl +record and use cookies. Another way to activate it is to use the \fI-b, +--cookie\fP option. + If the cookie jar can't be created or written to, the whole curl operation won't fail or even report an error clearly. Using -v will get a warning displayed, but that is the only visible feedback you get about this possibly @@ -320,6 +323,18 @@ URL-encode that data and pass it on in the POST. The name part gets an equal sign appended, resulting in \fIname=urlencoded-file-content\fP. Note that the name is expected to be URL-encoded already. .RE +.IP "--delegation LEVEL" +Set \fILEVEL\fP to tell the server what it is allowed to delegate when it +comes to user credentials. Used with GSS/kerberos. +.RS +.IP "none" +Don't allow any delegation. +.IP "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. +.IP "always" +Unconditionally allow the server to delegate. +.RE .IP "--digest" (HTTP) Enables HTTP Digest authentication. This is a authentication that prevents the password from being sent over the wire in clear text. Use this in @@ -348,7 +363,7 @@ passive mode you need to not use \fI-P, --ftp-port\fP or force it with transfers. Curl will normally always first attempt to use EPSV before PASV, but with this option, it will not try using EPSV. -\fB--epsv\fP can be used to explicitly enable EPRT again and \fB--no-epsv\fP +\fB--epsv\fP can be used to explicitly enable EPSV again and \fB--no-epsv\fP is an alias for \fB--disable-epsv\fP. Disabling EPSV only changes the passive behavior. If you want to switch to @@ -577,7 +592,9 @@ header will be used instead of the internal one. This allows you to make even trickier stuff than curl would normally do. You should not replace internally set headers without knowing perfectly well what you're doing. Remove an internal header by giving a replacement without content on the right side of -the colon, as in: -H \&"Host:". +the colon, as in: -H \&"Host:". If you send the custom header with no-value then +its header must be terminated with a semicolon, such as \-H "X-Custom-Header;" +to send "X-Custom-Header:". curl will make sure that each header you add/replace is sent with the proper end-of-line marker, you should thus \fBnot\fP add that as a part of the header @@ -1068,16 +1085,18 @@ file will not be read and used. See the \fI-K, --config\fP for details on the default config file search path. .IP "-Q, --quote <command>" (FTP/SFTP) Send an arbitrary command to the remote FTP or SFTP server. Quote -commands are sent BEFORE the transfer takes place (just after the -initial PWD command in an FTP transfer, to be exact). To make commands -take place after a successful transfer, prefix them with a dash '-'. -To make commands be sent after libcurl has changed the working directory, -just before the transfer command(s), prefix the command with a '+' (this -is only supported for FTP). You may specify any number of commands. If -the server returns failure for one of the commands, the entire operation -will be aborted. You must send syntactically correct FTP commands as -RFC 959 defines to FTP servers, or one of the commands listed below to -SFTP servers. This option can be used multiple times. +commands are sent BEFORE the transfer takes place (just after the initial PWD +command in an FTP transfer, to be exact). To make commands take place after a +successful transfer, prefix them with a dash '-'. To make commands be sent +after libcurl has changed the working directory, just before the transfer +command(s), prefix the command with a '+' (this is only supported for +FTP). You may specify any number of commands. If the server returns failure +for one of the commands, the entire operation will be aborted. You must send +syntactically correct FTP commands as RFC 959 defines to FTP servers, or one +of the commands listed below to SFTP servers. This option can be used +multiple times. When speaking to a FTP server, prefix the command with an +asterisk (*) to make libcurl continue even if the command fails as by default +curl will stop at first failure. SFTP is a binary protocol. Unlike for FTP, libcurl interprets SFTP quote commands itself before sending them to the server. File names may be quoted @@ -1266,9 +1285,8 @@ the port number is not specified, it is assumed at port 1080. (Added in This option overrides any previous use of \fI-x, --proxy\fP, as they are mutually exclusive. -Since 7.21.7, this option is superfluous since you can specify a -socks5-hostnamae proxy with \fI-x, --proxy\fP using a socks5h:// protocol -prefix. +Since 7.21.7, this option is superfluous since you can specify a socks5 +hostname proxy with \fI-x, --proxy\fP using a socks5h:// protocol prefix. If this option is used several times, the last one will be used. (This option was previously wrongly documented and used as --socks without the number @@ -1576,6 +1594,14 @@ Specifies a custom FTP command to use instead of LIST when doing file lists with FTP. If this option is used several times, the last one will be used. + +.IP "--xattr" +When saving output to a file, this option tells curl to store certain file +metadata in extened file attributes. Currently, the URL is stored in the +xdg.origin.url attribute and, for HTTP, the content type is stored in +the mime_type attribute. If the file system does not support extended +attributes, a warning is issued. + .IP "-y, --speed-time <time>" If a download is slower than speed-limit bytes per second during a speed-time period, the download gets aborted. If speed-time is used, the default @@ -1656,22 +1682,39 @@ Default config file, see \fI-K, --config\fP for details. 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 \fI--proxy\fP option. + .IP "http_proxy [protocol://]<host>[:port]" Sets the proxy server to use for HTTP. .IP "HTTPS_PROXY [protocol://]<host>[:port]" Sets the proxy server to use for HTTPS. -.IP "FTP_PROXY [protocol://]<host>[:port]" -Sets the proxy server to use for FTP. +.IP "[url-protocol]_PROXY [protocol://]<host>[: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. .IP "ALL_PROXY [protocol://]<host>[:port]" Sets the proxy server to use if no protocol-specific proxy is set. .IP "NO_PROXY <comma-separated list of hosts>" list of host names that shouldn't go through any proxy. If set to a asterisk \&'*' only, it matches all hosts. - -Since 7.21.7, the proxy string may be specified with a protocol:// prefix to -specify alternative proxy protocols. Use socks4://, socks4a:// or socks5:// to -request the specific SOCKS version to be used. No protocol specified, http:// -and all others will be treated as HTTP proxies. +.SH "PROXY PROTOCOL PREFIXES" +Since curl version 7.21.7, the proxy string may be specified with a +protocol:// prefix to specify alternative proxy protocols. + +If no protocol is specified in the proxy string or if the string doesn't match +a supported one, the proxy will be treated as a HTTP proxy. + +The supported proxy protocol prefixes are as follows: +.IP "socks4://" +Makes it the equivalent of \fI--socks4\fP +.IP "socks4a://" +Makes it the equivalent of \fI--socks4a\fP +.IP "socks5://" +Makes it the equivalent of \fI--socks5\fP +.IP "socks5h://" +Makes it the equivalent of \fI--socks5-hostname\fP .SH EXIT CODES There are a bunch of different error codes and their corresponding error messages that may appear during bad conditions. At the time of this writing, @@ -1852,4 +1895,3 @@ ftp://ftp.sunet.se/pub/www/utilities/curl/ .SH "SEE ALSO" .BR ftp (1), .BR wget (1) - diff --git a/docs/examples/.gitignore b/docs/examples/.gitignore index 8836a7b98..2ee9df154 100644 --- a/docs/examples/.gitignore +++ b/docs/examples/.gitignore @@ -4,6 +4,7 @@ certinfo chkspeed cookie_interface debug +externalsocket fileupload fopen ftp-wildcard @@ -25,6 +26,9 @@ multi-single persistant post-callback postit2 +progressfunc +resolve +rtsp sendrecv sepheaders simple diff --git a/docs/examples/Makefile.am b/docs/examples/Makefile.am index 6cf55f181..735942e78 100644 --- a/docs/examples/Makefile.am +++ b/docs/examples/Makefile.am @@ -23,7 +23,7 @@ AUTOMAKE_OPTIONS = foreign nostdinc EXTRA_DIST = README Makefile.example Makefile.inc Makefile.m32 \ - makefile.dj $(COMPLICATED_EXAMPLES) + Makefile.netware makefile.dj printf_macro.h $(COMPLICATED_EXAMPLES) # 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 diff --git a/docs/examples/Makefile.inc b/docs/examples/Makefile.inc index 9a2b48ea1..bf7337dd8 100644 --- a/docs/examples/Makefile.inc +++ b/docs/examples/Makefile.inc @@ -4,7 +4,8 @@ check_PROGRAMS = 10-at-a-time anyauthput cookie_interface debug fileupload \ https multi-app multi-debugcallback multi-double multi-post multi-single \ persistant post-callback postit2 sepheaders simple simplepost simplessl \ sendrecv httpcustomheader certinfo chkspeed ftpgetinfo ftp-wildcard \ - smtp-multi simplesmtp smtp-tls + smtp-multi simplesmtp smtp-tls rtsp externalsocket resolve \ + progressfunc # These examples require external dependencies that may not be commonly # available on POSIX systems, so don't bother attempting to compile them here. diff --git a/docs/examples/Makefile.m32 b/docs/examples/Makefile.m32 index 4ab596e26..e744c5b30 100644 --- a/docs/examples/Makefile.m32 +++ b/docs/examples/Makefile.m32 @@ -19,31 +19,50 @@ # KIND, either express or implied. # ########################################################################### -######################################################################### # -## Makefile for building curl examples with MingW32 -## and optionally OpenSSL (0.9.8), libssh2 (0.18), zlib (1.2.3) +## Makefile for building curl examples with MingW (GCC-3.2 or later) +## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3) ## -## Usage: -## mingw32-make -f Makefile.m32 [SSL=1] [SSH2=1] [ZLIB=1] [SSPI=1] [IPV6=1] [DYN=1] +## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] +## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn ## ## Hint: you can also set environment vars to control the build, f.e.: -## set ZLIB_PATH=c:/zlib-1.2.3 +## set ZLIB_PATH=c:/zlib-1.2.5 ## set ZLIB=1 -## -######################################################################### +# +########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH -ZLIB_PATH = ../../zlib-1.2.3 +ZLIB_PATH = ../../../zlib-1.2.5 endif # Edit the path below to point to the base of your OpenSSL package. ifndef OPENSSL_PATH -OPENSSL_PATH = ../../openssl-0.9.8k +OPENSSL_PATH = ../../../openssl-0.9.8r +endif +ifndef OPENSSL_LIBPATH +OPENSSL_LIBPATH = $(OPENSSL_PATH)/out +endif +ifndef OPENSSL_LIBS +OPENSSL_LIBS = -leay32 -lssl32 endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2 +LIBSSH2_PATH = ../../../libssh2-1.3.0 +endif +# Edit the path below to point to the base of your librtmp package. +ifndef LIBRTMP_PATH +LIBRTMP_PATH = ../../../librtmp-2.3 +endif +# Edit the path below to point to the base of your libidn package. +ifndef LIBIDN_PATH +LIBIDN_PATH = ../../../libidn-1.18 +endif +# Edit the path below to point to the base of your MS idndlpackage. +# Microsoft Internationalized Domain Names (IDN) Mitigation APIs 1.1 +# http://www.microsoft.com/downloads/en/details.aspx?FamilyID=ad6158d7-ddba-416a-9109-07607425a815 +ifndef WINIDN_PATH +WINIDN_PATH = ../../../Microsoft IDN Mitigation APIs endif # Edit the path below to point to the base of your Novell LDAP NDK. ifndef LDAP_SDK @@ -51,25 +70,76 @@ LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif PROOT = ../.. -ARES_LIB = $(PROOT)/ares -SSL = 1 -ZLIB = 1 +# Edit the path below to point to the base of your c-ares package. +ifndef LIBCARES_PATH +LIBCARES_PATH = $(PROOT)/ares +endif + +# Edit the var below to set to your architecture or set environment var. +ifndef ARCH +ARCH = w32 +endif CC = gcc CFLAGS = -g -O2 -Wall +CFLAGS += -fno-strict-aliasing +ifeq ($(ARCH),w64) +CFLAGS += -D_AMD64_ +endif # comment LDFLAGS below to keep debug info LDFLAGS = -s RC = windres RCFLAGS = --include-dir=$(PROOT)/include -O COFF -i -RM = del /q /f > NUL 2>&1 + +RM = del /q /f 2>NUL CP = copy ######################################################## ## Nothing more to do below this line! +ifeq ($(findstring -dyn,$(CFG)),-dyn) +DYN = 1 +endif +ifeq ($(findstring -ares,$(CFG)),-ares) +ARES = 1 +endif +ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +RTMP = 1 +SSL = 1 +ZLIB = 1 +endif +ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +SSH2 = 1 +SSL = 1 +ZLIB = 1 +endif +ifeq ($(findstring -ssl,$(CFG)),-ssl) +SSL = 1 +endif +ifeq ($(findstring -zlib,$(CFG)),-zlib) +ZLIB = 1 +endif +ifeq ($(findstring -idn,$(CFG)),-idn) +IDN = 1 +endif +ifeq ($(findstring -winidn,$(CFG)),-winidn) +WINIDN = 1 +endif +ifeq ($(findstring -sspi,$(CFG)),-sspi) +SSPI = 1 +endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +SPNEGO = 1 +endif +ifeq ($(findstring -ldaps,$(CFG)),-ldaps) +LDAPS = 1 +endif +ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +IPV6 = 1 +endif + INCLUDES = -I. -I$(PROOT) -I$(PROOT)/include -I$(PROOT)/lib -LINK = $(CC) $(LDFLAGS) -o $@ ifdef DYN curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll @@ -81,34 +151,45 @@ else endif ifdef ARES ifndef DYN - curl_DEPENDENCIES += $(ARES_LIB)/libcares.a + curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a endif CFLAGS += -DUSE_ARES - curl_LDADD += -L$(ARES_LIB) -lcares + curl_LDADD += -L"$(LIBCARES_PATH)" -lcares +endif +ifdef RTMP + CFLAGS += -DUSE_LIBRTMP + curl_LDADD += -L"$(LIBRTMP_PATH)/librtmp" -lrtmp -lwinmm endif ifdef SSH2 CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - curl_LDADD += -L$(LIBSSH2_PATH)/win32 -lssh2 + curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2 endif ifdef SSL - INCLUDES += -I"$(OPENSSL_PATH)/outinc" CFLAGS += -DUSE_SSLEAY -DHAVE_OPENSSL_ENGINE_H - ifdef DYN - curl_LDADD += -L$(OPENSSL_PATH)/out -leay32 -lssl32 - else - curl_LDADD += -L$(OPENSSL_PATH)/out -lssl -lcrypto -lgdi32 - endif + curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - curl_LDADD += -L$(ZLIB_PATH) -lz + curl_LDADD += -L"$(ZLIB_PATH)" -lz +endif +ifdef IDN + CFLAGS += -DUSE_LIBIDN + curl_LDADD += -L"$(LIBIDN_PATH)/lib" -lidn +else +ifdef WINIDN + CFLAGS += -DUSE_WIN32_IDN + curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz +endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif +ifdef SPNEGO + CFLAGS += -DHAVE_SPNEGO +endif ifdef IPV6 - CFLAGS += -DENABLE_IPV6 + CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL @@ -123,32 +204,32 @@ ifdef USE_LDAP_OPENLDAP endif ifndef USE_LDAP_NOVELL ifndef USE_LDAP_OPENLDAP -curl_LDADD += -lwldap32 + curl_LDADD += -lwldap32 endif endif curl_LDADD += -lws2_32 -COMPILE = $(CC) $(INCLUDES) $(CFLAGS) # Makefile.inc provides the check_PROGRAMS and COMPLICATED_EXAMPLES defines include Makefile.inc -example_PROGRAMS := $(patsubst %,%.exe,$(strip $(check_PROGRAMS))) - -.SUFFIXES: .rc .res .o .exe +check_PROGRAMS := $(patsubst %,%.exe,$(strip $(check_PROGRAMS))) +check_PROGRAMS += ftpuploadresume.exe synctime.exe -all: $(example_PROGRAMS) +all: $(check_PROGRAMS) -.o.exe: $(curl_DEPENDENCIES) - $(LINK) $< $(curl_LDADD) +%.exe: %.o $(curl_DEPENDENCIES) + $(CC) $(LDFLAGS) -o $@ $< $(curl_LDADD) -.c.o: - $(COMPILE) -c $< +%.o: %.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< -.rc.res: +%.res: %.rc $(RC) $(RCFLAGS) $< -o $@ clean: - $(RM) $(example_PROGRAMS) + -$(RM) $(check_PROGRAMS:.exe=.o) +distclean vclean: clean + -$(RM) $(check_PROGRAMS) diff --git a/docs/examples/Makefile.netware b/docs/examples/Makefile.netware new file mode 100644 index 000000000..fdea6b81b --- /dev/null +++ b/docs/examples/Makefile.netware @@ -0,0 +1,441 @@ +################################################################# +# +## Makefile for building curl.nlm (NetWare version - gnu make) +## Use: make -f Makefile.netware +## +## Comments to: Guenter Knauf http://www.gknw.net/phpbb +# +################################################################# + +# Edit the path below to point to the base of your Novell NDK. +ifndef NDKBASE +NDKBASE = c:/novell +endif + +# Edit the path below to point to the base of your Zlib sources. +ifndef ZLIB_PATH +ZLIB_PATH = ../../../zlib-1.2.5 +endif + +# Edit the path below to point to the base of your OpenSSL package. +ifndef OPENSSL_PATH +OPENSSL_PATH = ../../../openssl-0.9.8r +endif + +# Edit the path below to point to the base of your LibSSH2 package. +ifndef LIBSSH2_PATH +LIBSSH2_PATH = ../../../libssh2-1.3.0 +endif + +# Edit the path below to point to the base of your axTLS package. +ifndef AXTLS_PATH +AXTLS_PATH = ../../../axTLS-1.2.7 +endif + +# Edit the path below to point to the base of your libidn package. +ifndef LIBIDN_PATH +LIBIDN_PATH = ../../../libidn-1.18 +endif + +# Edit the path below to point to the base of your librtmp package. +ifndef LIBRTMP_PATH +LIBRTMP_PATH = ../../../librtmp-2.3 +endif + +# Edit the path below to point to the base of your fbopenssl package. +ifndef FBOPENSSL_PATH +FBOPENSSL_PATH = ../../fbopenssl-0.4 +endif + +# Edit the path below to point to the base of your c-ares package. +ifndef LIBCARES_PATH +LIBCARES_PATH = ../../ares +endif + +ifndef INSTDIR +INSTDIR = ..$(DS)..$(DS)curl-$(LIBCURL_VERSION_STR)-bin-nw +endif + +# Edit the vars below to change NLM target settings. +TARGET = examples +VERSION = $(LIBCURL_VERSION) +COPYR = Copyright (C) $(LIBCURL_COPYRIGHT_STR) +DESCR = cURL ($(LIBARCH)) +MTSAFE = YES +STACK = 8192 +SCREEN = Example Program +# Comment the line below if you dont want to load protected automatically. +# LDRING = 3 + +# Uncomment the next line to enable linking with POSIX semantics. +# POSIXFL = 1 + +# Edit the var below to point to your lib architecture. +ifndef LIBARCH +LIBARCH = LIBC +endif + +# must be equal to NDEBUG or DEBUG, CURLDEBUG +ifndef DB +DB = NDEBUG +endif +# Optimization: -O<n> or debugging: -g +ifeq ($(DB),NDEBUG) + OPT = -O2 + OBJDIR = release +else + OPT = -g + OBJDIR = debug +endif + +# The following lines defines your compiler. +ifdef CWFolder + METROWERKS = $(CWFolder) +endif +ifdef METROWERKS + # MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support + MWCW_PATH = $(subst \,/,$(METROWERKS))/Novell Support/Metrowerks Support + CC = mwccnlm +else + CC = gcc +endif +PERL = perl +# Here you can find a native Win32 binary of the original awk: +# http://www.gknw.net/development/prgtools/awk-20100523.zip +AWK = awk +CP = cp -afv +MKDIR = mkdir +# RM = rm -f +# If you want to mark the target as MTSAFE you will need a tool for +# generating the xdc data for the linker; here's a minimal tool: +# http://www.gknw.net/development/prgtools/mkxdc.zip +MPKXDC = mkxdc + +# LIBARCH_U = $(shell $(AWK) 'BEGIN {print toupper(ARGV[1])}' $(LIBARCH)) +LIBARCH_L = $(shell $(AWK) 'BEGIN {print tolower(ARGV[1])}' $(LIBARCH)) + +# Include the version info retrieved from curlver.h +-include $(OBJDIR)/version.inc + +# Global flags for all compilers +CFLAGS += $(OPT) -D$(DB) -DNETWARE -DHAVE_CONFIG_H -nostdinc + +ifeq ($(CC),mwccnlm) +LD = mwldnlm +LDFLAGS = -nostdlib $< $(PRELUDE) $(LDLIBS) -o $@ -commandfile +LIBEXT = lib +CFLAGS += -gccinc -inline off -opt nointrinsics -proc 586 +CFLAGS += -relax_pointers +#CFLAGS += -w on +ifeq ($(LIBARCH),LIBC) +ifeq ($(POSIXFL),1) + PRELUDE = $(NDK_LIBC)/imports/posixpre.o +else + PRELUDE = $(NDK_LIBC)/imports/libcpre.o +endif + CFLAGS += -align 4 +else + # PRELUDE = $(NDK_CLIB)/imports/clibpre.o + # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK + PRELUDE = "$(MWCW_PATH)/libraries/runtime/prelude.obj" + # CFLAGS += -include "$(MWCW_PATH)/headers/nlm_clib_prefix.h" + CFLAGS += -align 1 +endif +else +LD = nlmconv +LDFLAGS = -T +LIBEXT = a +CFLAGS += -m32 +CFLAGS += -fno-builtin -fno-strict-aliasing +ifeq ($(findstring gcc,$(CC)),gcc) +CFLAGS += -fpcc-struct-return +endif +CFLAGS += -Wall # -pedantic +ifeq ($(LIBARCH),LIBC) +ifeq ($(POSIXFL),1) + PRELUDE = $(NDK_LIBC)/imports/posixpre.gcc.o +else + PRELUDE = $(NDK_LIBC)/imports/libcpre.gcc.o +endif +else + # PRELUDE = $(NDK_CLIB)/imports/clibpre.gcc.o + # to avoid the __init_* / __deinit_* whoes dont use prelude from NDK + # http://www.gknw.net/development/mk_nlm/gcc_pre.zip + PRELUDE = $(NDK_ROOT)/pre/prelude.o + CFLAGS += -include $(NDKBASE)/nlmconv/genlm.h +endif +endif + +NDK_ROOT = $(NDKBASE)/ndk +ifndef NDK_CLIB +NDK_CLIB = $(NDK_ROOT)/nwsdk +endif +ifndef NDK_LIBC +NDK_LIBC = $(NDK_ROOT)/libc +endif +ifndef NDK_LDAP +NDK_LDAP = $(NDK_ROOT)/cldapsdk/netware +endif +CURL_INC = ../../include +CURL_LIB = ../../lib + +INCLUDES = -I$(CURL_INC) + +ifeq ($(findstring -static,$(CFG)),-static) +LINK_STATIC = 1 +endif +ifeq ($(findstring -ares,$(CFG)),-ares) +WITH_ARES = 1 +endif +ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +WITH_RTMP = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +WITH_SSH2 = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -axtls,$(CFG)),-axtls) +WITH_AXTLS = 1 +WITH_SSL = +else +ifeq ($(findstring -ssl,$(CFG)),-ssl) +WITH_SSL = 1 +endif +endif +ifeq ($(findstring -zlib,$(CFG)),-zlib) +WITH_ZLIB = 1 +endif +ifeq ($(findstring -idn,$(CFG)),-idn) +WITH_IDN = 1 +endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +WITH_SPNEGO = 1 +endif +ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +ENABLE_IPV6 = 1 +endif + +ifdef LINK_STATIC + LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT) +ifdef WITH_ARES + LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) +endif +else + MODULES = libcurl.nlm + IMPORTS = @$(CURL_LIB)/libcurl.imp +endif +ifdef WITH_SSH2 + # INCLUDES += -I$(LIBSSH2_PATH)/include +ifdef LINK_STATIC + LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) +else + MODULES += libssh2.nlm + IMPORTS += @$(LIBSSH2_PATH)/nw/libssh2.imp +endif +endif +ifdef WITH_RTMP + # INCLUDES += -I$(LIBRTMP_PATH) +ifdef LINK_STATIC + LDLIBS += $(LIBRTMP_PATH)/librtmp/librtmp.$(LIBEXT) +endif +endif +ifdef WITH_SSL + INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) + LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) + LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) + IMPORTS += GetProcessSwitchCount RunningProcess +ifdef WITH_SPNEGO + # INCLUDES += -I$(FBOPENSSL_PATH)/include + LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT) +endif +else +ifdef WITH_AXTLS + INCLUDES += -I$(AXTLS_PATH)/inc +ifdef LINK_STATIC + LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT) +else + MODULES += libaxtls.nlm + IMPORTS += $(AXTLS_PATH)/lib/libaxtls.imp +endif +endif +endif +ifdef WITH_ZLIB + # INCLUDES += -I$(ZLIB_PATH) +ifdef LINK_STATIC + LDLIBS += $(ZLIB_PATH)/nw/$(LIBARCH)/libz.$(LIBEXT) +else + MODULES += libz.nlm + IMPORTS += @$(ZLIB_PATH)/nw/$(LIBARCH)/libz.imp +endif +endif +ifdef WITH_IDN + # INCLUDES += -I$(LIBIDN_PATH)/include + LDLIBS += $(LIBIDN_PATH)/lib/libidn.$(LIBEXT) +endif + +ifeq ($(LIBARCH),LIBC) + INCLUDES += -I$(NDK_LIBC)/include + # INCLUDES += -I$(NDK_LIBC)/include/nks + # INCLUDES += -I$(NDK_LIBC)/include/winsock + CFLAGS += -D_POSIX_SOURCE +else + INCLUDES += -I$(NDK_CLIB)/include/nlm + # INCLUDES += -I$(NDK_CLIB)/include +endif +ifndef DISABLE_LDAP + # INCLUDES += -I$(NDK_LDAP)/$(LIBARCH_L)/inc +endif +CFLAGS += $(INCLUDES) + +ifeq ($(MTSAFE),YES) + XDCOPT = -n +endif +ifeq ($(MTSAFE),NO) + XDCOPT = -u +endif +ifdef XDCOPT + XDCDATA = $(OBJDIR)/$(TARGET).xdc +endif + +ifeq ($(findstring /sh,$(SHELL)),/sh) +DL = ' +DS = / +PCT = % +#-include $(NDKBASE)/nlmconv/ncpfs.inc +else +DS = \\ +PCT = %% +endif + +# Makefile.inc provides the CSOURCES and HHEADERS defines +include Makefile.inc + +check_PROGRAMS := $(patsubst %,%.nlm,$(strip $(check_PROGRAMS))) + +.PRECIOUS: $(OBJDIR)/%.o $(OBJDIR)/%.def $(OBJDIR)/%.xdc + + +all: prebuild $(check_PROGRAMS) + +prebuild: $(OBJDIR) $(OBJDIR)/version.inc + +$(OBJDIR)/%.o: %.c + @echo Compiling $< + $(CC) $(CFLAGS) -c $< -o $@ + +$(OBJDIR)/version.inc: $(CURL_INC)/curl/curlver.h $(OBJDIR) + @echo Creating $@ + @$(AWK) -f ../../packages/NetWare/get_ver.awk $< > $@ + +install: $(INSTDIR) all + @$(CP) $(check_PROGRAMS) $(INSTDIR) + +clean: + -$(RM) -r $(OBJDIR) + +distclean vclean: clean + -$(RM) $(check_PROGRAMS) + +$(OBJDIR) $(INSTDIR): + @$(MKDIR) $@ + +%.nlm: $(OBJDIR)/%.o $(OBJDIR)/%.def $(XDCDATA) + @echo Linking $@ + @-$(RM) $@ + @$(LD) $(LDFLAGS) $(OBJDIR)/$(@:.nlm=.def) + +$(OBJDIR)/%.xdc: Makefile.netware + @echo Creating $@ + @$(MPKXDC) $(XDCOPT) $@ + +$(OBJDIR)/%.def: Makefile.netware + @echo $(DL)# DEF file for linking with $(LD)$(DL) > $@ + @echo $(DL)# Do not edit this file - it is created by Make!$(DL) >> $@ + @echo $(DL)# All your changes will be lost!!$(DL) >> $@ + @echo $(DL)#$(DL) >> $@ + @echo $(DL)copyright "$(COPYR)"$(DL) >> $@ + @echo $(DL)description "$(DESCR) $(notdir $(@:.def=)) Example"$(DL) >> $@ + @echo $(DL)version $(VERSION)$(DL) >> $@ +ifdef NLMTYPE + @echo $(DL)type $(NLMTYPE)$(DL) >> $@ +endif +ifdef STACK + @echo $(DL)stack $(STACK)$(DL) >> $@ +endif +ifdef SCREEN + @echo $(DL)screenname "$(DESCR) $(notdir $(@:.def=)) $(SCREEN)"$(DL) >> $@ +else + @echo $(DL)screenname "DEFAULT"$(DL) >> $@ +endif +ifneq ($(DB),NDEBUG) + @echo $(DL)debug$(DL) >> $@ +endif + @echo $(DL)threadname "_$(notdir $(@:.def=))"$(DL) >> $@ +ifdef XDCDATA + @echo $(DL)xdcdata $(XDCDATA)$(DL) >> $@ +endif +ifeq ($(LDRING),0) + @echo $(DL)flag_on 16$(DL) >> $@ +endif +ifeq ($(LDRING),3) + @echo $(DL)flag_on 512$(DL) >> $@ +endif +ifeq ($(LIBARCH),CLIB) + @echo $(DL)start _Prelude$(DL) >> $@ + @echo $(DL)exit _Stop$(DL) >> $@ + @echo $(DL)import @$(NDK_CLIB)/imports/clib.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_CLIB)/imports/threads.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_CLIB)/imports/nlmlib.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_CLIB)/imports/socklib.imp$(DL) >> $@ + @echo $(DL)module clib$(DL) >> $@ +ifndef DISABLE_LDAP + @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapsdk.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapssl.imp$(DL) >> $@ +# @echo $(DL)import @$(NDK_LDAP)/clib/imports/ldapx.imp$(DL) >> $@ + @echo $(DL)module ldapsdk ldapssl$(DL) >> $@ +endif +else +ifeq ($(POSIXFL),1) + @echo $(DL)flag_on 4194304$(DL) >> $@ +endif + @echo $(DL)flag_on 64$(DL) >> $@ + @echo $(DL)pseudopreemption$(DL) >> $@ +ifeq ($(findstring posixpre,$(PRELUDE)),posixpre) + @echo $(DL)start POSIX_Start$(DL) >> $@ + @echo $(DL)exit POSIX_Stop$(DL) >> $@ + @echo $(DL)check POSIX_CheckUnload$(DL) >> $@ +else + @echo $(DL)start _LibCPrelude$(DL) >> $@ + @echo $(DL)exit _LibCPostlude$(DL) >> $@ + @echo $(DL)check _LibCCheckUnload$(DL) >> $@ +endif + @echo $(DL)import @$(NDK_LIBC)/imports/libc.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_LIBC)/imports/netware.imp$(DL) >> $@ + @echo $(DL)module libc$(DL) >> $@ +ifndef DISABLE_LDAP + @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapsdk.imp$(DL) >> $@ + @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapssl.imp$(DL) >> $@ +# @echo $(DL)import @$(NDK_LDAP)/libc/imports/lldapx.imp$(DL) >> $@ + @echo $(DL)module lldapsdk lldapssl$(DL) >> $@ +endif +endif +ifdef MODULES + @echo $(DL)module $(MODULES)$(DL) >> $@ +endif +ifdef EXPORTS + @echo $(DL)export $(EXPORTS)$(DL) >> $@ +endif +ifdef IMPORTS + @echo $(DL)import $(IMPORTS)$(DL) >> $@ +endif +ifeq ($(findstring nlmconv,$(LD)),nlmconv) + @echo $(DL)input $(PRELUDE)$(DL) >> $@ + @echo $(DL)input $(@:.def=.o)$(DL) >> $@ +ifdef LDLIBS + @echo $(DL)input $(LDLIBS)$(DL) >> $@ +endif + @echo $(DL)output $(notdir $(@:.def=.nlm))$(DL) >> $@ +endif diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c index 76fa15853..bab36c57b 100644 --- a/docs/examples/anyauthput.c +++ b/docs/examples/anyauthput.c @@ -41,6 +41,7 @@ #endif #include <curl/curl.h> +#include "printf_macro.h" #if LIBCURL_VERSION_NUM < 0x070c03 #error "upgrade your libcurl to no less than 7.12.3" @@ -92,7 +93,7 @@ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) retcode = read(fd, ptr, size * nmemb); - fprintf(stderr, "*** We read %d bytes from file\n", retcode); + fprintf(stderr, "*** We read %" _FMT_SIZE_T " bytes from file\n", retcode); return retcode; } diff --git a/docs/examples/certinfo.c b/docs/examples/certinfo.c index 02558d98c..ffcec6356 100644 --- a/docs/examples/certinfo.c +++ b/docs/examples/certinfo.c @@ -22,8 +22,6 @@ #include <stdio.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> static size_t wrfu(void *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/docs/examples/chkspeed.c b/docs/examples/chkspeed.c index fbcb1f764..b5c397ab7 100644 --- a/docs/examples/chkspeed.c +++ b/docs/examples/chkspeed.c @@ -35,8 +35,6 @@ #include <time.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> #define URL_BASE "http://speedtest.your.domain/" #define URL_1M URL_BASE "file_1M.bin" diff --git a/docs/examples/curlgtk.c b/docs/examples/curlgtk.c index 2c4428083..8cb9914c6 100644 --- a/docs/examples/curlgtk.c +++ b/docs/examples/curlgtk.c @@ -13,8 +13,6 @@ #include <gtk/gtk.h> #include <curl/curl.h> -#include <curl/types.h> /* new for v7 */ -#include <curl/easy.h> /* new for v7 */ GtkWidget *Bar; diff --git a/docs/examples/externalsocket.c b/docs/examples/externalsocket.c new file mode 100644 index 000000000..5951c078e --- /dev/null +++ b/docs/examples/externalsocket.c @@ -0,0 +1,142 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +/* + * This is an example demonstrating how an application can pass in a custom + * socket to libcurl to use. This example also handles the connect itself. + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <curl/curl.h> + +#ifdef WIN32 +#include <windows.h> +#include <winsock2.h> +#include <ws2tcpip.h> +#define close closesocket +#else +#include <sys/types.h> /* socket types */ +#include <sys/socket.h> /* socket definitions */ +#include <arpa/inet.h> /* inet (3) funtions */ +#include <unistd.h> /* misc. UNIX functions */ +#endif + +#include <errno.h> + +/* The IP address and port number to connect to */ +#define IPADDR "127.0.0.1" +#define PORTNUM 80 + +static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) +{ + int written = fwrite(ptr, size, nmemb, (FILE *)stream); + return written; +} + +static curl_socket_t opensocket(void *clientp, + curlsocktype purpose, + struct curl_sockaddr *address) +{ + curl_socket_t 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; + CURLcode res; + struct sockaddr_in servaddr; /* socket address structure */ + curl_socket_t sockfd; + +#ifdef WIN32 + WSADATA wsaData; + int initwsa; + + if((initwsa = WSAStartup(MAKEWORD(2,0), &wsaData)) != 0) { + 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" */ + if( (sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0 ) { + printf("Error creating listening socket.\n"); + return 3; + } + + memset(&servaddr, 0, sizeof(servaddr)); + servaddr.sin_family = AF_INET; + servaddr.sin_port = htons(PORTNUM); + + if (INADDR_NONE == (servaddr.sin_addr.s_addr = inet_addr(IPADDR))) + 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 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); + + if(res) { + printf("libcurl error: %d\n", res); + return 4; + } + } + return 0; +} diff --git a/docs/examples/ftpget.c b/docs/examples/ftpget.c index 7b5e0d7cf..bcb42bb30 100644 --- a/docs/examples/ftpget.c +++ b/docs/examples/ftpget.c @@ -22,8 +22,6 @@ #include <stdio.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> /* * This is an example showing how to get a single file from an FTP server. diff --git a/docs/examples/ftpgetinfo.c b/docs/examples/ftpgetinfo.c index 52f87d633..f0746693b 100644 --- a/docs/examples/ftpgetinfo.c +++ b/docs/examples/ftpgetinfo.c @@ -23,8 +23,6 @@ #include <string.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> /* * This is an example showing how to check a single file's size and mtime diff --git a/docs/examples/ftpgetresp.c b/docs/examples/ftpgetresp.c index ea882a00f..29290a31d 100644 --- a/docs/examples/ftpgetresp.c +++ b/docs/examples/ftpgetresp.c @@ -22,8 +22,6 @@ #include <stdio.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> /* * Similar to ftpget.c but this also stores the received response-lines diff --git a/docs/examples/ftpupload.c b/docs/examples/ftpupload.c index 305734d5d..722acbc9e 100644 --- a/docs/examples/ftpupload.c +++ b/docs/examples/ftpupload.c @@ -32,6 +32,7 @@ #else #include <unistd.h> #endif +#include "printf_macro.h" /* * This example shows an FTP upload, with a rename of the file just after @@ -56,7 +57,7 @@ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) by default internally */ size_t retcode = fread(ptr, size, nmemb, stream); - fprintf(stderr, "*** We read %d bytes from file\n", retcode); + fprintf(stderr, "*** We read %" _FMT_SIZE_T " bytes from file\n", retcode); return retcode; } diff --git a/docs/examples/ftpuploadresume.c b/docs/examples/ftpuploadresume.c index 0560b54dc..55b8986c7 100644 --- a/docs/examples/ftpuploadresume.c +++ b/docs/examples/ftpuploadresume.c @@ -39,7 +39,7 @@ /* The MinGW headers are missing a few Win32 function definitions, you shouldn't need this if you use VC++ */ -#ifdef __MINGW32__ +#if defined(__MINGW32__) && !defined(__MINGW64__) int __cdecl _snscanf(const char * input, size_t length, const char * format, ...); #endif diff --git a/docs/examples/getinmemory.c b/docs/examples/getinmemory.c index b5b34d4f0..78e6deb10 100644 --- a/docs/examples/getinmemory.c +++ b/docs/examples/getinmemory.c @@ -36,10 +36,10 @@ struct MemoryStruct { static size_t -WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) +WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; - struct MemoryStruct *mem = (struct MemoryStruct *)data; + struct MemoryStruct *mem = (struct MemoryStruct *)userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); if (mem->memory == NULL) { @@ -48,7 +48,7 @@ WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data) exit(EXIT_FAILURE); } - memcpy(&(mem->memory[mem->size]), ptr, realsize); + memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; diff --git a/docs/examples/httpput.c b/docs/examples/httpput.c index f78a74107..664c8e152 100644 --- a/docs/examples/httpput.c +++ b/docs/examples/httpput.c @@ -25,6 +25,7 @@ #include <unistd.h> #include <curl/curl.h> +#include "printf_macro.h" /* * This example shows a HTTP PUT operation. PUTs a file given as a command @@ -45,7 +46,7 @@ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream) by default internally */ retcode = fread(ptr, size, nmemb, stream); - fprintf(stderr, "*** We read %d bytes from file\n", retcode); + fprintf(stderr, "*** We read %" _FMT_SIZE_T " bytes from file\n", retcode); return retcode; } diff --git a/docs/examples/postit2.c b/docs/examples/postit2.c index bb7fd48d7..63c248467 100644 --- a/docs/examples/postit2.c +++ b/docs/examples/postit2.c @@ -37,8 +37,6 @@ #include <string.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> int main(int argc, char *argv[]) { diff --git a/docs/examples/printf_macro.h b/docs/examples/printf_macro.h new file mode 100644 index 000000000..9eed8f4c6 --- /dev/null +++ b/docs/examples/printf_macro.h @@ -0,0 +1,45 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +/* Simple hack trying to get a valid printf format string for size_t. + * If that fails for your platform you can define your own _FMT_SIZE_T, + * f.e.: -D_FMT_SIZE_T="zd" + */ +#ifndef _PRINTF_MACRO_H +#define _PRINTF_MACRO_H + +#ifndef _FMT_SIZE_T +#ifdef WIN32 +#define _FMT_SIZE_T "Id" +#else +/* +"zd" is a GNU extension to POSIX; so we dont use it for size_t but hack around +#define _FMT_SIZE_T "zd" +*/ +#ifdef __x86_64__ +#define _FMT_SIZE_T "lu" +#else +#define _FMT_SIZE_T "u" +#endif /* __x86_64__ */ +#endif /* WIN32 */ +#endif /* !_FMT_SIZE_T */ + +#endif /* !_PRINTF_MACRO_H */ diff --git a/docs/examples/progressfunc.c b/docs/examples/progressfunc.c new file mode 100644 index 000000000..42ed3287b --- /dev/null +++ b/docs/examples/progressfunc.c @@ -0,0 +1,58 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include <stdio.h> +#include <curl/curl.h> + +#define STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES 6000 + +static int progress(void *p, + double dltotal, double dlnow, + double ultotal, double ulnow) +{ + fprintf(stderr, "UP: %g of %g DOWN: %g of %g\r\n", + ulnow, ultotal, dlnow, dltotal); + + if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES) + return 1; + return 0; +} + +int main(void) +{ + CURL *curl; + CURLcode res=0; + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/"); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress); + curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); + res = curl_easy_perform(curl); + + if(res) + fprintf(stderr, "%s\n", curl_easy_strerror(res)); + + /* always cleanup */ + curl_easy_cleanup(curl); + } + return (int)res; +} diff --git a/docs/examples/resolve.c b/docs/examples/resolve.c new file mode 100644 index 000000000..7b3e5656e --- /dev/null +++ b/docs/examples/resolve.c @@ -0,0 +1,51 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include <stdio.h> +#include <curl/curl.h> + +int main(void) +{ + CURL *curl; + CURLcode res = CURLE_OK; + struct curl_slist *host = NULL; + + /* 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 + */ + host = curl_slist_append(NULL, "example.com:80:127.0.0.1"); + + curl = curl_easy_init(); + if(curl) { + curl_easy_setopt(curl, CURLOPT_RESOLVE, host); + curl_easy_setopt(curl, CURLOPT_URL, "http://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.c b/docs/examples/rtsp.c new file mode 100644 index 000000000..42b26cc71 --- /dev/null +++ b/docs/examples/rtsp.c @@ -0,0 +1,271 @@ +/* + * Copyright (c) 2011, Jim Hollinger + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * 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. + * * Neither the name of Jim Hollinger 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 COPYRIGHT HOLDERS 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 COPYRIGHT + * OWNER 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 <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if defined (WIN32) +# include <conio.h> /* _getch() */ +#else +# include <termios.h> +# include <unistd.h> + +static int _getch(void) +{ + struct termios oldt, newt; + int ch; + tcgetattr( STDIN_FILENO, &oldt ); + newt = oldt; + newt.c_lflag &= ~( ICANON | ECHO ); + tcsetattr( STDIN_FILENO, TCSANOW, &newt ); + ch = getchar(); + tcsetattr( STDIN_FILENO, TCSANOW, &oldt ); + return ch; +} +#endif + +#include <curl/curl.h> + +#define VERSION_STR "V1.0" + +/* error handling macros */ +#define my_curl_easy_setopt(A, B, C) \ + if ((res = curl_easy_setopt((A), (B), (C))) != CURLE_OK) \ + fprintf(stderr, "curl_easy_setopt(%s, %s, %s) failed: %d\n", \ + #A, #B, #C, res); + +#define my_curl_easy_perform(A) \ + if ((res = curl_easy_perform((A))) != CURLE_OK) \ + fprintf(stderr, "curl_easy_perform(%s) failed: %d\n", #A, res); + + +/* send RTSP OPTIONS request */ +static void rtsp_options(CURL *curl, const char *uri) +{ + CURLcode res = CURLE_OK; + printf("\nRTSP: OPTIONS %s\n", uri); + my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri); + my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_OPTIONS); + my_curl_easy_perform(curl); +} + + +/* send RTSP DESCRIBE request and write sdp response to a file */ +static void rtsp_describe(CURL *curl, const char *uri, + const char *sdp_filename) +{ + CURLcode res = CURLE_OK; + FILE *sdp_fp = fopen(sdp_filename, "wt"); + printf("\nRTSP: DESCRIBE %s\n", uri); + if (sdp_fp == NULL) { + fprintf(stderr, "Could not open '%s' for writing\n", sdp_filename); + sdp_fp = stdout; + } + else { + printf("Writing SDP to '%s'\n", sdp_filename); + } + my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, sdp_fp); + my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_DESCRIBE); + my_curl_easy_perform(curl); + my_curl_easy_setopt(curl, CURLOPT_WRITEDATA, stdout); + if (sdp_fp != stdout) { + fclose(sdp_fp); + } +} + +/* send RTSP SETUP request */ +static void rtsp_setup(CURL *curl, const char *uri, const char *transport) +{ + CURLcode res = CURLE_OK; + printf("\nRTSP: SETUP %s\n", uri); + printf(" TRANSPORT %s\n", transport); + my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri); + my_curl_easy_setopt(curl, CURLOPT_RTSP_TRANSPORT, transport); + my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_SETUP); + my_curl_easy_perform(curl); +} + + +/* send RTSP PLAY request */ +static void rtsp_play(CURL *curl, const char *uri, const char *range) +{ + CURLcode res = CURLE_OK; + printf("\nRTSP: PLAY %s\n", uri); + my_curl_easy_setopt(curl, CURLOPT_RTSP_STREAM_URI, uri); + my_curl_easy_setopt(curl, CURLOPT_RANGE, range); + my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_PLAY); + my_curl_easy_perform(curl); +} + + +/* send RTSP TEARDOWN request */ +static void rtsp_teardown(CURL *curl, const char *uri) +{ + CURLcode res = CURLE_OK; + printf("\nRTSP: TEARDOWN %s\n", uri); + my_curl_easy_setopt(curl, CURLOPT_RTSP_REQUEST, CURL_RTSPREQ_TEARDOWN); + my_curl_easy_perform(curl); +} + + +/* convert url into an sdp filename */ +static void get_sdp_filename(const char *url, char *sdp_filename) +{ + const char *s = strrchr(url, '/'); + strcpy(sdp_filename, "video.sdp"); + if (s != NULL) { + s++; + if (s[0] != '\0') { + sprintf(sdp_filename, "%s.sdp", s); + } + } +} + + +/* scan sdp file for media control attribute */ +static void get_media_control_attribute(const char *sdp_filename, + char *control) +{ + int max_len = 256; + char *s = malloc(max_len); + FILE *sdp_fp = fopen(sdp_filename, "rt"); + control[0] = '\0'; + if (sdp_fp != NULL) { + while (fgets(s, max_len - 2, sdp_fp) != NULL) { + sscanf(s, " a = control: %s", control); + } + fclose(sdp_fp); + } + free(s); +} + + +/* main app */ +int main(int argc, char * const argv[]) +{ +#if 1 + const char *transport = "RTP/AVP;unicast;client_port=1234-1235"; /* UDP */ +#else + const char *transport = "RTP/AVP/TCP;unicast;client_port=1234-1235"; /* TCP */ +#endif + const char *range = "0.000-"; + int rc = EXIT_SUCCESS; + char *basename = NULL; + + printf("\nRTSP request %s\n", VERSION_STR); + printf(" Project web site: http://code.google.com/p/rtsprequest/\n"); + printf(" Requires cURL V7.20 or greater\n\n"); + + /* check command line */ + if ((argc != 2) && (argc != 3)) { + basename = strrchr(argv[0], '/'); + if (basename == NULL) { + basename = strrchr(argv[0], '\\'); + } + if (basename == NULL) { + basename = argv[0]; + } else { + basename++; + } + printf("Usage: %s url [transport]\n", basename); + printf(" url of video server\n"); + printf(" transport (optional) specifier for media stream protocol\n"); + printf(" default transport: %s\n", transport); + printf("Example: %s rtsp://192.168.0.2/media/video1\n\n", basename); + rc = EXIT_FAILURE; + } else { + const char *url = argv[1]; + char *uri = malloc(strlen(url) + 32); + char *sdp_filename = malloc(strlen(url) + 32); + char *control = malloc(strlen(url) + 32); + CURLcode res; + get_sdp_filename(url, sdp_filename); + if (argc == 3) { + transport = argv[2]; + } + + /* initialize curl */ + res = curl_global_init(CURL_GLOBAL_ALL); + if (res == CURLE_OK) { + curl_version_info_data *data = curl_version_info(CURLVERSION_NOW); + CURL *curl; + fprintf(stderr, " cURL V%s loaded\n", data->version); + + /* initialize this curl session */ + curl = curl_easy_init(); + if (curl != NULL) { + my_curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L); + my_curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1L); + my_curl_easy_setopt(curl, CURLOPT_WRITEHEADER, stdout); + my_curl_easy_setopt(curl, CURLOPT_URL, url); + + /* request server options */ + sprintf(uri, "%s", url); + rtsp_options(curl, uri); + + /* request session description and write response to sdp file */ + rtsp_describe(curl, uri, sdp_filename); + + /* get media control attribute from sdp file */ + get_media_control_attribute(sdp_filename, control); + + /* setup media stream */ + sprintf(uri, "%s/%s", url, control); + rtsp_setup(curl, uri, transport); + + /* start playing media stream */ + sprintf(uri, "%s/", url); + rtsp_play(curl, uri, range); + printf("Playing video, press any key to stop ..."); + _getch(); + printf("\n"); + + /* teardown session */ + rtsp_teardown(curl, uri); + + /* cleanup */ + curl_easy_cleanup(curl); + curl = NULL; + } else { + fprintf(stderr, "curl_easy_init() failed\n"); + } + curl_global_cleanup(); + } else { + fprintf(stderr, "curl_global_init(%s) failed: %d\n", + "CURL_GLOBAL_ALL", res); + } + free(control); + free(sdp_filename); + free(uri); + } + + return rc; +} diff --git a/docs/examples/sendrecv.c b/docs/examples/sendrecv.c index 0a49f2ff5..369601d16 100644 --- a/docs/examples/sendrecv.c +++ b/docs/examples/sendrecv.c @@ -24,6 +24,7 @@ #include <stdio.h> #include <string.h> #include <curl/curl.h> +#include "printf_macro.h" /* Auxiliary function that waits on the socket. */ static int wait_on_socket(curl_socket_t sockfd, int for_recv, long timeout_ms) @@ -122,7 +123,7 @@ int main(void) if(CURLE_OK != res) break; - printf("Received %u bytes.\n", iolen); + printf("Received %" _FMT_SIZE_T " bytes.\n", iolen); } /* always cleanup */ diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c index dac287886..afa14fc85 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -24,8 +24,6 @@ #include <unistd.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> static size_t write_data(void *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/docs/examples/simplessl.c b/docs/examples/simplessl.c index aeaadce59..46a378329 100644 --- a/docs/examples/simplessl.c +++ b/docs/examples/simplessl.c @@ -22,9 +22,6 @@ #include <stdio.h> #include <curl/curl.h> -#include <curl/types.h> -#include <curl/easy.h> - /* some requirements for this to work: 1. set pCertFile to the file with the client certificate diff --git a/docs/examples/smooth-gtk-thread.c b/docs/examples/smooth-gtk-thread.c index 8cf106c81..932f6e396 100644 --- a/docs/examples/smooth-gtk-thread.c +++ b/docs/examples/smooth-gtk-thread.c @@ -37,8 +37,6 @@ #include <pthread.h> #include <curl/curl.h> -#include <curl/types.h> /* new for v7 */ -#include <curl/easy.h> /* new for v7 */ #define NUMT 4 diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index 70b84c326..14d77de27 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -147,7 +147,7 @@ size_t SyncTime_CURL_WriteHeader(void *ptr, size_t size, size_t nmemb, TmpStr1 & 2? */ AutoSyncTime = 0; else { - RetVal = sscanf ((char *)(ptr), "Date: %s %d %s %d %d:%d:%d", + RetVal = sscanf ((char *)(ptr), "Date: %s %hu %s %hu %hu:%hu:%hu", TmpStr1, &SYSTime.wDay, TmpStr2, &SYSTime.wYear, &SYSTime.wHour, &SYSTime.wMinute, &SYSTime.wSecond); diff --git a/docs/libcurl/curl_easy_cleanup.3 b/docs/libcurl/curl_easy_cleanup.3 index 75a370367..d8a3f9fcf 100644 --- a/docs/libcurl/curl_easy_cleanup.3 +++ b/docs/libcurl/curl_easy_cleanup.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -37,8 +37,15 @@ This will effectively close all connections this handle has used and possibly has kept open until now. Don't call this function if you intend to transfer more files. -Any uses of the \fBhandle\fP after this function has been called are -illegal. This kills the handle and all memory associated with it! +Occasionally you may get your progress callback or header callback called from +within \fIcurl_easy_cleanup(3)\fP (if previously set for the handle using +\fIcurl_easy_setopt(3)\fP). 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 uses of the \fBhandle\fP after this function has been called and have +returned, are illegal. This kills the handle and all memory associated with +it! With libcurl versions prior to 7.17.: when you've called this, you can safely remove all the strings you've previously told libcurl to use, as it won't use diff --git a/docs/libcurl/curl_easy_setopt.3 b/docs/libcurl/curl_easy_setopt.3 index c2804f385..394bd7798 100644 --- a/docs/libcurl/curl_easy_setopt.3 +++ b/docs/libcurl/curl_easy_setopt.3 @@ -91,7 +91,9 @@ 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 SIGPIPEs 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. +they may still happen, contrary to our desire. In addition, using +\fICURLAUTH_NTLM_WB\fP authentication could cause a SIGCHLD signal to be +raised. .IP CURLOPT_WILDCARDMATCH Set this option to 1 if you want to transfer multiple files according to a file name pattern. The pattern can be specified as part of the @@ -582,20 +584,162 @@ POST/PUT and a 401 or 407 is received immediately afterwards. .SH NETWORK OPTIONS .IP CURLOPT_URL The actual URL to deal with. The parameter should be a char * to a zero -terminated string. +terminated string which must be URL-encoded in the following format: -If the given URL lacks the protocol part ("http://" or "ftp://" etc), it will -attempt to guess which protocol to use based on the given host name. If the -given protocol of the set URL is not supported, libcurl will return on error -(\fICURLE_UNSUPPORTED_PROTOCOL\fP) when you call \fIcurl_easy_perform(3)\fP or -\fIcurl_multi_perform(3)\fP. Use \fIcurl_version_info(3)\fP for detailed info -on which protocols are supported. +scheme://host:port/path -The string given to CURLOPT_URL must be url-encoded and follow RFC 2396 +For a greater explanation of the format please see RFC 2396 (http://curl.haxx.se/rfc/rfc2396.txt). -Starting with version 7.20.0, the fragment part of the URI will not be send as -part of the path, which was the case previously. +If the given URL lacks the scheme, or protocol, part ("http://" or "ftp://" +etc), libcurl will attempt to resolve which protocol to use based on the +given host mame. If the protocol is not supported, libcurl will return +(\fICURLE_UNSUPPORTED_PROTOCOL\fP) when you call \fIcurl_easy_perform(3)\fP +or \fIcurl_multi_perform(3)\fP. Use \fIcurl_version_info(3)\fP for detailed +information on which protocols are supported. + +The host 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. For example: + +http://www.example.com/ + +http://hostname/ + +http://192.168.0.1/ + +http://[2001:1890:1112:1::20]/ + +It is also possible to specify the user name and password as part of the +host, for some protocols, when connecting to servers that require +authentication. + +For example the following types of authentication support this: + +http://user:password@www.domain.com +ftp://user:password@ftp.domain.com +pop3://user:password@mail.domain.com + +The port is optional and when not specified libcurl will use the default port +based on the determined or specified protocol: 80 for http, 21 for ftp and 25 +for smtp, etc. The following examples show how to specify the port: + +http://www.weirdserver.com:8080/ - This will connect to a web server using +port 8080. + +smtp://mail.domain.com:587/ - This will connect to a smtp server on the +alternative mail port. + +The path part of the URL is protocol specific and whilst some examples are +given below this list is not conclusive: + +.B HTTP + +The path part of a HTTP request specifies the file to retrieve and from what +directory. If the directory is not specified then the web server's root +directory is used. If the file is omitted then the default document will be +retrieved for either the directory specified or the root directory. The +exact resource returned for each URL is entirely dependent on the server's +configuration. + +http://www.netscape.com - This gets the main page (index.html in this +example) from Netscape's web server. + +http://www.netscape.com/index.html - This returns the main page from Netscape +by specifying the page to get. + +http://www.netscape.com/contactus/ - This returns the default document from +the contactus directory. + +.B FTP + +The path part of an FTP request specifies the file to retrieve and from what +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://cool.haxx.se - This retrieves the directory listing for our FTP server. + +ftp://cool.haxx.se/readme.txt - This downloads the file readme.txt from the +root directory. + +ftp://cool.haxx.se/libcurl/readme.txt - This downloads readme.txt from the +libcurl directory. + +ftp://user:password@my.example.com/readme.txt - This retrieves the readme.txt +file from the user's home directory. When a username and password is +specified, everything that is specified in the path part is relative to the +user's home directory. To retrieve files from the root directory or a +directory underneath the root directory then the absolute path must be +specified by prepending an additional forward slash to the beginning of the +path. + +ftp://user:password@my.example.com//readme.txt - This retrieves the readme.txt +from the root directory when logging in as a specified user. + +.B SMTP + +The path part of a SMTP request specifies the host name to present during +communication with the mail server. If the path is omitted then libcurl will +attempt to resolve the local computer's host name. 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. + +smtp://mail.domain.com - This connects to the mail server at domain.com and +sends your local computer's host name in the HELO / EHLO command. + +smtp://mail.domain.com/client.domain.com - This will send client.domain.com in +the HELO / EHLO command to the mail server at domain.com. + +.B POP3 + +The path part of a POP3 request specifies the mailbox (message) to retrieve. +If the mailbox is not specified then a list of waiting messages is returned +instead. + +pop3://user:password@mail.domain.com - This lists the available messages +pop3://user:password@mail.domain.com/1 - This retrieves the first message + +.B SCP + +The path part of an SCP request specifies the file to retrieve and from what +directory. The file part may not be omitted. 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. +If the user name is not embedded in the URL, it can be set with the +\fICURLOPT_USERPWD\fP or \fBCURLOPT_USERNAME\fP option. + +scp://user@example.com/etc/issue - This specifies the file /etc/issue + +scp://example.com/~/my-file - This specifies the file my-file in the +user's home directory on the server + +.B SFTP + +The path part of an SFTP request specifies the file to retrieve and from what +directory. If the file part is omitted then libcurl downloads the directory +listing for the directory specified. If the path ends in a / 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. +If the user name is not embedded in the URL, it can be set with the +\fICURLOPT_USERPWD\fP or \fBCURLOPT_USERNAME\fP option. + +sftp://user:password@example.com/etc/issue - This specifies the file +/etc/issue + +sftp://user@example.com/~/my-file - This specifies the file my-file in the +user's home directory + +sftp://ssh.example.com/~/Documents/ - This requests a directory listing +of the Documents directory under the user's home directory + +.B NOTES + +Starting with version 7.20.0, the fragment part of the URI will not be sent as +part of the path, which was previously the case. \fICURLOPT_URL\fP is the only option that \fBmust\fP be set before \fIcurl_easy_perform(3)\fP is called. @@ -664,10 +808,10 @@ this are \fICURLPROXY_HTTP\fP, \fICURLPROXY_HTTP_1_0\fP (added in 7.19.4), If you set \fBCURLOPT_PROXYTYPE\fP to \fICURLPROXY_HTTP_1_0\fP, it will only affect how libcurl speaks to a proxy when CONNECT is used. The HTTP version -used for "regular" HTTP requests is instead controled with +used for "regular" HTTP requests is instead controlled with \fICURLOPT_HTTP_VERSION\fP. .IP CURLOPT_NOPROXY -Pass a pointer to a zero terminated string. The should be a comma- separated +Pass a pointer to a zero terminated string. The should be a comma separated list of hosts which do not use a proxy, if one is specified. The only wildcard 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 @@ -890,6 +1034,20 @@ prevent the password from being eavesdropped. You need to build libcurl with OpenSSL support for this option to work, or build libcurl on Windows. +.IP 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 +(Added in 7.22.0) + +Note that libcurl will fork 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 will cause a SIGCHLD signal to be +raised (regardless of whether \fICURLOPT_NOSIGNAL\fP 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. .IP CURLAUTH_ANY This is a convenience macro that sets all bits and thus makes libcurl pick any it finds suitable. libcurl will automatically select the one it finds most @@ -917,12 +1075,12 @@ You need to build libcurl with GnuTLS or OpenSSL with TLS-SRP support for this to work. (Added in 7.21.4) .RE .IP CURLOPT_TLSAUTH_USERNAME -Pass a char * as parameter, which should point to the zero-terminated username +Pass a char * as parameter, which should point to the zero terminated username to use for the TLS authentication method specified with the \fICURLOPT_TLSAUTH_TYPE\fP option. Requires that the \fICURLOPT_TLS_PASSWORD\fP option also be set. (Added in 7.21.4) .IP CURLOPT_TLSAUTH_PASSWORD -Pass a char * as parameter, which should point to the zero-terminated password +Pass a char * as parameter, which should point to the zero terminated password to use for the TLS authentication method specified with the \fICURLOPT_TLSAUTH_TYPE\fP option. Requires that the \fICURLOPT_TLS_USERNAME\fP option also be set. (Added in 7.21.4) @@ -1313,18 +1471,22 @@ Examples with specified ports: You disable PORT again and go back to using the passive version by setting this option to NULL. .IP CURLOPT_QUOTE -Pass a pointer to a linked list of FTP or SFTP commands to pass to -the server prior to your FTP request. This will be 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 \fIcurl_slist_append(3)\fP -to append strings (commands) to the list, and clear the entire list -afterwards with \fIcurl_slist_free_all(3)\fP. Disable this operation -again by setting a NULL to this option. -The set of valid FTP commands depends on the server (see RFC959 for a -list of mandatory commands). -The valid SFTP commands are: chgrp, chmod, chown, ln, mkdir, pwd, -rename, rm, rmdir, symlink (see +Pass a pointer to a linked list of FTP or SFTP commands to pass to the server +prior to your FTP request. This will be 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 \fIcurl_slist_append(3)\fP to append strings (commands) to the +list, and clear the entire list afterwards with +\fIcurl_slist_free_all(3)\fP. Disable this operation again by setting a NULL +to this option. When speaking to a FTP server, prefix the command with an +asterisk (*) to make libcurl continue even if the command fails as by default +libcurl will stop at first failure. + +The set of valid FTP commands depends on the server (see RFC959 for a list of +mandatory commands). + +The valid SFTP commands are: chgrp, chmod, chown, ln, mkdir, pwd, rename, rm, +rmdir, symlink (see .BR curl (1)) (SFTP support added in 7.16.3) .IP CURLOPT_POSTQUOTE @@ -1451,7 +1613,7 @@ a reply. Initiate the shutdown and wait for a reply. .RE .IP CURLOPT_FTP_ACCOUNT -Pass a pointer to a zero-terminated string (or NULL to disable). When an FTP +Pass a pointer to a zero 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. (Added in 7.13.0) .IP CURLOPT_FTP_FILEMETHOD @@ -2105,6 +2267,14 @@ of these, 'private' will be used. Set the string to NULL to disable kerberos support for FTP. (This option was known as CURLOPT_KRB4LEVEL up to 7.16.3) +.IP CURLOPT_GSSAPI_DELEGATION +Set the parameter 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 GSSAPI implementation and the definition of +GSS_C_DELEG_POLICY_FLAG was available at compile-time. +(Added in 7.22.0) .SH SSH OPTIONS .IP CURLOPT_SSH_AUTH_TYPES Pass a long set to a bitmask consisting of one or more of diff --git a/docs/libcurl/curl_multi_fdset.3 b/docs/libcurl/curl_multi_fdset.3 index fadc53812..3dbdc4504 100644 --- a/docs/libcurl/curl_multi_fdset.3 +++ b/docs/libcurl/curl_multi_fdset.3 @@ -40,19 +40,28 @@ but be sure to FD_ZERO them before calling this function as otherwise remove any others. The \fIcurl_multi_perform(3)\fP function should be called as soon as one of them is ready to be read from or written to. -To be sure to have up-to-date results, you should call -\fIcurl_multi_perform\fP until it does not return CURLM_CALL_MULTI_PERFORM -prior to calling \fIcurl_multi_fdset\fP. This will make sure that libcurl has -updated the handles' socket states. - If no file descriptors are set by libcurl, \fImax_fd\fP will contain -1 when this function returns. Otherwise it will contain the higher descriptor number -libcurl set. +libcurl set. When libcurl returns -1 in \fImax_fd\fP, it is because libcurl +currently does something that isn't 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(). When max_fd returns with -1, you need to +wait a while and then proceed and call \fIcurl_multi_perform\fP anyway. How +long to wait? I would suggest 100 milliseconds at least, but you may want to +test it out in your own particular conditions to find a suitable value. When doing select(), you should use \fBcurl_multi_timeout\fP to figure out how long to wait for action. Call \fIcurl_multi_perform\fP 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'd 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 will try 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 will possibly save you +from the crash, but will make your program NOT wait for sockets it should wait +for... .SH RETURN VALUE CURLMcode type, general libcurl multi interface error code. See \fIlibcurl-errors(3)\fP diff --git a/docs/libcurl/curl_share_setopt.3 b/docs/libcurl/curl_share_setopt.3 index 5fff33d25..295423ae3 100644 --- a/docs/libcurl/curl_share_setopt.3 +++ b/docs/libcurl/curl_share_setopt.3 @@ -64,6 +64,11 @@ Cached DNS hosts will be 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 will share DNS cache by default without this having to be used! +.IP CURL_LOCK_DATA_SSL_SESSION +SSL session IDs will be shared accross the easy handles using this shared +object. This will reduce 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. .RE .IP CURLSHOPT_UNSHARE This option does the opposite of \fICURLSHOPT_SHARE\fP. It specifies that diff --git a/docs/libcurl/curl_version_info.3 b/docs/libcurl/curl_version_info.3 index 4481830a3..ccb202834 100644 --- a/docs/libcurl/curl_version_info.3 +++ b/docs/libcurl/curl_version_info.3 @@ -128,6 +128,11 @@ the app having to pass them on. (Added in 7.13.2) .IP CURL_VERSION_CONV libcurl was built with support for character conversions, as provided by the CURLOPT_CONV_* callbacks. (Added in 7.15.4) +.IP CURL_VERSION_TLSAUTH_SRP +libcurl was built with support for TLS-SRP. (Added in 7.21.4) +.IP CURL_VERSION_NTLM_WB +libcurl was built with support for NTLM delegation to a winbind helper. +(Added in 7.22.0) .RE \fIssl_version\fP is an ASCII string for the OpenSSL version used. If libcurl has no SSL support, this is NULL. diff --git a/docs/libcurl/libcurl-errors.3 b/docs/libcurl/libcurl-errors.3 index beabf98f0..7954a83db 100644 --- a/docs/libcurl/libcurl-errors.3 +++ b/docs/libcurl/libcurl-errors.3 @@ -277,3 +277,6 @@ An invalid share object was passed to the function. .IP "CURLSHE_NOMEM (4)" Not enough memory was available. (Added in 7.12.0) +.IP "CURLSHE_NOT_BUILT_IN (5)" +The requsted sharing could not be done because the library you use don't have +that particular feature enabled. (Added in 7.23.0) diff --git a/docs/libcurl/libcurl-multi.3 b/docs/libcurl/libcurl-multi.3 index d84bafcad..21cf8218b 100644 --- a/docs/libcurl/libcurl-multi.3 +++ b/docs/libcurl/libcurl-multi.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -82,14 +82,6 @@ might need attention. This also makes it very easy for your program to wait for input on your own private file descriptors at the same time or perhaps timeout every now and then, should you want that. -A little note here about the return codes from the multi functions, and -especially the \fIcurl_multi_perform(3)\fP: if you receive -\fICURLM_CALL_MULTI_PERFORM\fP, this basically means that you should call -\fIcurl_multi_perform(3)\fP again, before you select() on more actions. You -don't have to do it immediately, but the return code means that libcurl may -have more data available to return or that there may be more data to send off -before it is "satisfied". - \fIcurl_multi_perform(3)\fP 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 @@ -118,13 +110,32 @@ If you want to re-use 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). .SH "MULTI_SOCKET" -Since 7.16.0, the \fIcurl_multi_socket_action(3)\fP 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 will make a significant -difference for applications using large numbers of simultaneous connections. - -\fIcurl_multi_socket_action(3)\fP is then used -instead of \fIcurl_multi_perform(3)\fP. +\fIcurl_multi_socket_action(3)\fP 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 will make a significant difference for applications +using large numbers of simultaneous connections. + +\fIcurl_multi_socket_action(3)\fP is then used instead of +\fIcurl_multi_perform(3)\fP. + +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 and CURLMOPT_TIMERFUNCTION options to +\fIcurl_multi_setopt(3)\fP. + +The API is then 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 then make sure to receive all sockets informed about in +the CURLMOPT_SOCKETFUNCTION callback and make sure it reacts on the given +activity on them. When a socket has the given activity, you call +\fIcurl_multi_socket_action(3)\fP specifying which socket and action there +are. + +The CURLMOPT_TIMERFUNCTION callback is called to set a timeout. When that +timeout expires, your application should call the +\fIcurl_multi_socket_action(3)\fP function saying it was due to a timeout. .SH "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 diff --git a/docs/libcurl/libcurl-tutorial.3 b/docs/libcurl/libcurl-tutorial.3 index 1efd6fbb3..ff1a06be2 100644 --- a/docs/libcurl/libcurl-tutorial.3 +++ b/docs/libcurl/libcurl-tutorial.3 @@ -5,7 +5,7 @@ .\" * | (__| |_| | _ <| |___ .\" * \___|\___/|_| \_\_____| .\" * -.\" * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. .\" * .\" * This software is licensed as described in the file COPYING, which .\" * you should have received as part of this distribution. The terms @@ -249,9 +249,11 @@ complication for you. Given simply the URL to a file, libcurl will take care of all the details needed to get the file moved from one machine to another. .SH "Multi-threading Issues" -The first basic rule is that you must \fBnever\fP share a libcurl handle (be -it easy or multi or whatever) between multiple threads. Only use one handle in -one thread at a time. +The first basic rule is that you must \fBnever\fP simultaneously share a +libcurl handle (be it easy or multi or whatever) between multiple +threads. Only use one handle in one thread at any time. 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. libcurl is completely thread safe, except for two issues: signals and SSL/TLS handlers. Signals are used for timing out name resolves (during DNS lookup) - diff --git a/docs/libcurl/libcurl.m4 b/docs/libcurl/libcurl.m4 index 01a0575cc..8cada0523 100644 --- a/docs/libcurl/libcurl.m4 +++ b/docs/libcurl/libcurl.m4 @@ -157,6 +157,7 @@ x=CURLOPT_FILE; 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 diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index 9257fb16b..8c1792c88 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -20,6 +20,7 @@ CURLAUTH_DIGEST_IE 7.19.3 CURLAUTH_GSSNEGOTIATE 7.10.6 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 CURLCLOSEPOLICY_LEAST_RECENTLY_USED 7.7 @@ -186,6 +187,9 @@ CURLFTPSSL_TRY 7.11.0 7.17.0 CURLFTP_CREATE_DIR 7.19.4 CURLFTP_CREATE_DIR_NONE 7.19.4 CURLFTP_CREATE_DIR_RETRY 7.19.4 +CURLGSSAPI_DELEGATION_FLAG 7.22.0 +CURLGSSAPI_DELEGATION_NONE 7.22.0 +CURLGSSAPI_DELEGATION_POLICY_FLAG 7.22.0 CURLINFO_APPCONNECT_TIME 7.19.0 CURLINFO_CERTINFO 7.19.1 CURLINFO_CONDITION_UNMET 7.19.4 @@ -344,6 +348,7 @@ 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_GSSAPI_DELEGATION 7.22.0 CURLOPT_HEADER 7.1 CURLOPT_HEADERDATA 7.10 CURLOPT_HEADERFUNCTION 7.7.2 @@ -545,6 +550,7 @@ CURLSHE_BAD_OPTION 7.10.3 CURLSHE_INVALID 7.10.3 CURLSHE_IN_USE 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 @@ -675,6 +681,7 @@ CURL_VERSION_KERBEROS4 7.10 CURL_VERSION_LARGEFILE 7.11.1 CURL_VERSION_LIBZ 7.10 CURL_VERSION_NTLM 7.10.6 +CURL_VERSION_NTLM_WB 7.22.0 CURL_VERSION_SPNEGO 7.10.8 CURL_VERSION_SSL 7.10 CURL_VERSION_SSPI 7.13.2 diff --git a/include/curl/curl.h b/include/curl/curl.h index a9d42fad6..f4aa17fdd 100644 --- a/include/curl/curl.h +++ b/include/curl/curl.h @@ -55,18 +55,17 @@ #include <sys/types.h> #include <time.h> -#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__GNUC__) && \ - !defined(__CYGWIN__) || defined(__MINGW32__) -#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H)) +#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__) +#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__)) /* The check above prevents the winsock2 inclusion if winsock.h already was included, since they can't co-exist without problems */ #include <winsock2.h> #include <ws2tcpip.h> #endif -#else +#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 system that are known to + 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(__SYMBIAN32__) || defined(__INTEGRITY) || \ @@ -75,14 +74,13 @@ #include <sys/select.h> #endif -#ifndef _WIN32_WCE +#if !defined(WIN32) && !defined(_WIN32_WCE) #include <sys/socket.h> #endif + #if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__) #include <sys/time.h> #endif -#include <sys/types.h> -#endif #ifdef __BEOS__ #include <support/SupportDefs.h> @@ -122,7 +120,7 @@ typedef void CURL; #ifndef curl_socket_typedef /* socket typedef */ -#ifdef WIN32 +#if defined(WIN32) && !defined(__LWIP_OPT_H__) typedef SOCKET curl_socket_t; #define CURL_SOCKET_BAD INVALID_SOCKET #else @@ -189,10 +187,10 @@ typedef int (*curl_progress_callback)(void *clientp, #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 + typedef size_t (*curl_write_callback)(char *buffer, size_t size, size_t nitems, @@ -600,6 +598,7 @@ typedef enum { #define CURLAUTH_GSSNEGOTIATE (1<<2) /* GSS-Negotiate */ #define CURLAUTH_NTLM (1<<3) /* NTLM */ #define CURLAUTH_DIGEST_IE (1<<4) /* Digest with IE flavour */ +#define CURLAUTH_NTLM_WB (1<<5) /* NTLM delegating to winbind helper */ #define CURLAUTH_ONLY (1<<31) /* used together with a single other type to force no auth or just that single type */ @@ -614,6 +613,10 @@ typedef enum { #define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */ #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 struct curl_khkey { @@ -916,9 +919,7 @@ typedef enum { /* send linked-list of post-transfer QUOTE commands */ CINIT(POSTQUOTE, OBJECTPOINT, 39), - /* Pass a pointer to string of the output using full variable-replacement - as described elsewhere. */ - CINIT(WRITEINFO, OBJECTPOINT, 40), + CINIT(WRITEINFO, OBJECTPOINT, 40), /* DEPRECATED, do not use! */ CINIT(VERBOSE, LONG, 41), /* talk a lot */ CINIT(HEADER, LONG, 42), /* throw the header out too */ @@ -994,8 +995,7 @@ typedef enum { /* Max amount of cached alive connections */ CINIT(MAXCONNECTS, LONG, 71), - /* 72 - DEPRECATED */ - CINIT(CLOSEPOLICY, LONG, 72), + CINIT(CLOSEPOLICY, LONG, 72), /* DEPRECATED, do not use! */ /* 73 = OBSOLETE */ @@ -1069,7 +1069,7 @@ typedef enum { CINIT(SSLENGINE_DEFAULT, LONG, 90), /* Non-zero value means to use the global dns cache */ - CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* To become OBSOLETE soon */ + CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */ /* DNS cache timeout */ CINIT(DNS_CACHE_TIMEOUT, LONG, 92), @@ -1483,6 +1483,9 @@ typedef enum { CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208), CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209), + /* allow GSSAPI credential delegation */ + CINIT(GSSAPI_DELEGATION, LONG, 210), + CURLOPT_LASTENTRY /* the last unused */ } CURLoption; @@ -2011,8 +2014,9 @@ typedef enum { CURLSHE_BAD_OPTION, /* 1 */ CURLSHE_IN_USE, /* 2 */ CURLSHE_INVALID, /* 3 */ - CURLSHE_NOMEM, /* out of memory */ - CURLSHE_LAST /* never use */ + CURLSHE_NOMEM, /* 4 out of memory */ + CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */ + CURLSHE_LAST /* never use */ } CURLSHcode; typedef enum { @@ -2092,8 +2096,9 @@ typedef struct { #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 delegating to winbind helper */ -/* + /* * NAME curl_version_info() * * DESCRIPTION diff --git a/include/curl/curlver.h b/include/curl/curlver.h index 5fe5c2d73..33d069f83 100644 --- a/include/curl/curlver.h +++ b/include/curl/curlver.h @@ -30,13 +30,13 @@ /* This is the version number of the libcurl package from which this header file origins: */ -#define LIBCURL_VERSION "7.21.8-DEV" +#define LIBCURL_VERSION "7.23.0-DEV" /* The numeric version number is also available "in parts" by using these defines: */ #define LIBCURL_VERSION_MAJOR 7 -#define LIBCURL_VERSION_MINOR 21 -#define LIBCURL_VERSION_PATCH 8 +#define LIBCURL_VERSION_MINOR 23 +#define LIBCURL_VERSION_PATCH 0 /* This is the numeric version of the libcurl version number, meant for easier parsing and comparions by programs. The LIBCURL_VERSION_NUM define will @@ -53,7 +53,7 @@ and it is always a greater number in a more recent release. It makes comparisons with greater than and less than work. */ -#define LIBCURL_VERSION_NUM 0x071508 +#define LIBCURL_VERSION_NUM 0x071700 /* * This is the date and time when the full source package was created. The diff --git a/include/curl/typecheck-gcc.h b/include/curl/typecheck-gcc.h index f043a18e4..5c584b002 100644 --- a/include/curl/typecheck-gcc.h +++ b/include/curl/typecheck-gcc.h @@ -392,7 +392,8 @@ _CURL_WARNING(_curl_easy_getinfo_err_curl_slist, /* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */ /* XXX: also check size of an char[] array? */ #define _curl_is_error_buffer(expr) \ - (__builtin_types_compatible_p(__typeof__(expr), char *) || \ + (_curl_is_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* */ @@ -521,7 +522,11 @@ typedef int (_curl_progress_callback2)(const void *, _curl_callback_compatible((expr), _curl_debug_callback1) || \ _curl_callback_compatible((expr), _curl_debug_callback2) || \ _curl_callback_compatible((expr), _curl_debug_callback3) || \ - _curl_callback_compatible((expr), _curl_debug_callback4)) + _curl_callback_compatible((expr), _curl_debug_callback4) || \ + _curl_callback_compatible((expr), _curl_debug_callback5) || \ + _curl_callback_compatible((expr), _curl_debug_callback6) || \ + _curl_callback_compatible((expr), _curl_debug_callback7) || \ + _curl_callback_compatible((expr), _curl_debug_callback8)) typedef int (_curl_debug_callback1) (CURL *, curl_infotype, char *, size_t, void *); typedef int (_curl_debug_callback2) (CURL *, @@ -530,6 +535,14 @@ 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... */ diff --git a/lib/Makefile.Watcom b/lib/Makefile.Watcom index a780bbb28..10906c942 100644 --- a/lib/Makefile.Watcom +++ b/lib/Makefile.Watcom @@ -89,7 +89,7 @@ ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.5 !ifdef %libssh2_root LIBSSH2_ROOT = $(%libssh2_root) !else -LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.2.8 +LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.3.0 !endif !ifdef %librtmp_root diff --git a/lib/Makefile.inc b/lib/Makefile.inc index 04285b533..ec7f50537 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -14,7 +14,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \ - http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ + http_negotiate.c inet_pton.c strtoofft.c strerror.c \ hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c \ select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \ qssl.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ @@ -22,7 +22,8 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c polarssl.c \ curl_rtmp.c openldap.c curl_gethostname.c gopher.c axtls.c \ idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c \ - asyn-ares.c asyn-thread.c + asyn-ares.c asyn-thread.c curl_gssapi.c curl_ntlm.c curl_ntlm_wb.c \ + curl_ntlm_core.c curl_ntlm_msgs.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ @@ -30,11 +31,12 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h \ curl_fnmatch.h wildcard.h fileinfo.h ftplistparser.h strtok.h \ connect.h llist.h hash.h content_encoding.h share.h curl_md4.h \ - curl_md5.h http_digest.h http_negotiate.h http_ntlm.h inet_pton.h \ + curl_md5.h http_digest.h http_negotiate.h inet_pton.h \ strtoofft.h strerror.h inet_ntop.h curlx.h curl_memory.h setup.h \ transfer.h select.h easyif.h multiif.h parsedate.h sslgen.h gtls.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \ curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h \ warnless.h curl_hmac.h polarssl.h curl_rtmp.h curl_gethostname.h \ - gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h + gopher.h axtls.h cyassl.h http_proxy.h non-ascii.h asyn.h curl_ntlm.h \ + curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h curl_ntlm_msgs.h diff --git a/lib/Makefile.m32 b/lib/Makefile.m32 index 76171cb9b..140571653 100644 --- a/lib/Makefile.m32 +++ b/lib/Makefile.m32 @@ -1,7 +1,7 @@ -######################################################################### +########################################################################### # -## Makefile for building libcurl.a with MingW32 (GCC-3.2 or later) -## and optionally OpenSSL (0.9.8), libssh2 (1.2), zlib (1.2.5), librtmp (2.3) +## Makefile for building libcurl.a with MingW (GCC-3.2 or later) +## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3) ## ## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn @@ -9,10 +9,8 @@ ## Hint: you can also set environment vars to control the build, f.e.: ## set ZLIB_PATH=c:/zlib-1.2.5 ## set ZLIB=1 -## -## Comments to: Troy Engel <tengel@sonic.net> or -## Joern Hartroth <hartroth@acm.org> -######################################################################### +# +########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH @@ -22,9 +20,18 @@ endif ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-0.9.8r endif +ifndef OPENSSL_INCLUDE +OPENSSL_INCLUDE = $(OPENSSL_PATH)/outinc +endif +ifndef OPENSSL_LIBPATH +OPENSSL_LIBPATH = $(OPENSSL_PATH)/out +endif +ifndef OPENSSL_LIBS +OPENSSL_LIBS = -leay32 -lssl32 +endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH @@ -45,22 +52,35 @@ ifndef LDAP_SDK LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif +PROOT = .. + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH -LIBCARES_PATH = ../ares +LIBCARES_PATH = $(PROOT)/ares +endif + +# Edit the var below to set to your architecture or set environment var. +ifndef ARCH +ARCH = w32 endif CC = gcc CFLAGS = -g -O2 -Wall +CFLAGS += -fno-strict-aliasing +ifeq ($(ARCH),w64) +CFLAGS += -D_AMD64_ +endif # comment LDFLAGS below to keep debug info LDFLAGS = -s AR = ar RANLIB = ranlib RC = windres -RCFLAGS = --include-dir=../include -DDEBUGBUILD=0 -O COFF -i -RM = del /q /f 2>NUL +RCFLAGS = --include-dir=$(PROOT)/include -DDEBUGBUILD=0 -O COFF -i STRIP = strip -g +RM = del /q /f 2>NUL +CP = copy + ######################################################## ## Nothing more to do below this line! @@ -95,6 +115,9 @@ endif ifeq ($(findstring -sspi,$(CFG)),-sspi) SSPI = 1 endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +SPNEGO = 1 +endif ifeq ($(findstring -ldaps,$(CFG)),-ldaps) LDAPS = 1 endif @@ -104,10 +127,11 @@ endif INCLUDES = -I. -I../include CFLAGS += -DBUILDING_LIBCURL + ifdef ARES - INCLUDES += -I$(LIBCARES_PATH) + INCLUDES += -I"$(LIBCARES_PATH)" CFLAGS += -DUSE_ARES - DLL_LIBS += -L$(LIBCARES_PATH) -lcares + DLL_LIBS += -L"$(LIBCARES_PATH)" -lcares libcurl_dll_DEPENDENCIES = $(LIBCARES_PATH)/libcares.a endif ifdef RTMP @@ -118,37 +142,39 @@ endif ifdef SSH2 INCLUDES += -I"$(LIBSSH2_PATH)/include" -I"$(LIBSSH2_PATH)/win32" CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - DLL_LIBS += -L$(LIBSSH2_PATH)/win32 -lssh2 + DLL_LIBS += -L"$(LIBSSH2_PATH)/win32" -lssh2 endif ifdef SSL - INCLUDES += -I"$(OPENSSL_PATH)/outinc" -I"$(OPENSSL_PATH)/outinc/openssl" + INCLUDES += -I"$(OPENSSL_INCLUDE)" CFLAGS += -DUSE_SSLEAY -DUSE_OPENSSL -DHAVE_OPENSSL_ENGINE_H -DHAVE_OPENSSL_PKCS12_H \ -DHAVE_ENGINE_LOAD_BUILTIN_ENGINES -DOPENSSL_NO_KRB5 \ -DCURL_WANTS_CA_BUNDLE_ENV - DLL_LIBS += -L$(OPENSSL_PATH)/out -leay32 -lssl32 + DLL_LIBS += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - DLL_LIBS += -L$(ZLIB_PATH) -lz + DLL_LIBS += -L"$(ZLIB_PATH)" -lz endif ifdef IDN INCLUDES += -I"$(LIBIDN_PATH)/include" CFLAGS += -DUSE_LIBIDN - DLL_LIBS += -L$(LIBIDN_PATH)/lib -lidn + DLL_LIBS += -L"$(LIBIDN_PATH)/lib" -lidn else ifdef WINIDN - INCLUDES += -I"$(WINIDN_PATH)/include" - CFLAGS += -DHAVE_NORMALIZATION_H CFLAGS += -DUSE_WIN32_IDN + CFLAGS += -DWANT_IDN_PROTOTYPES DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif +ifdef SPNEGO + CFLAGS += -DHAVE_SPNEGO +endif ifdef IPV6 - CFLAGS += -DENABLE_IPV6 + CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL @@ -165,11 +191,10 @@ ifdef USE_LDAP_OPENLDAP endif ifndef USE_LDAP_NOVELL ifndef USE_LDAP_OPENLDAP -DLL_LIBS += -lwldap32 + DLL_LIBS += -lwldap32 endif endif DLL_LIBS += -lws2_32 -COMPILE = $(CC) $(INCLUDES) $(CFLAGS) # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc @@ -183,7 +208,6 @@ libcurl_a_DEPENDENCIES := $(strip $(CSOURCES) $(HHEADERS)) RESOURCE = libcurl.res -.SUFFIXES: .rc .res all: $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) @@ -200,20 +224,25 @@ $(libcurl_dll_LIBRARY): $(libcurl_a_OBJECTS) $(RESOURCE) $(libcurl_dll_DEPENDENC $(CC) $(LDFLAGS) -shared -Wl,--out-implib,$(libcurl_dll_a_LIBRARY) \ -o $@ $(libcurl_a_OBJECTS) $(RESOURCE) $(DLL_LIBS) -.c.o: - $(COMPILE) -c $< +%.o: %.c $(PROOT)/include/curl/curlbuild.h + $(CC) $(INCLUDES) $(CFLAGS) -c $< -.rc.res: +%.res: %.rc $(RC) $(RCFLAGS) $< -o $@ clean: +ifeq "$(wildcard $(PROOT)/include/curl/curlbuild.h.dist)" "$(PROOT)/include/curl/curlbuild.h.dist" + -$(RM) $(subst /,\,$(PROOT)/include/curl/curlbuild.h) +endif -$(RM) $(libcurl_a_OBJECTS) $(RESOURCE) distclean vclean: clean -$(RM) $(libcurl_a_LIBRARY) $(libcurl_dll_LIBRARY) $(libcurl_dll_a_LIBRARY) -FORCE: ; - $(LIBCARES_PATH)/libcares.a: $(MAKE) -C $(LIBCARES_PATH) -f Makefile.m32 +$(PROOT)/include/curl/curlbuild.h: + @echo Creating $@ + @$(CP) $(subst /,\,$@).dist $(subst /,\,$@) + diff --git a/lib/Makefile.netware b/lib/Makefile.netware index 2cc7c9ecc..43fae2e7a 100644 --- a/lib/Makefile.netware +++ b/lib/Makefile.netware @@ -24,7 +24,7 @@ endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your axTLS package. @@ -42,6 +42,11 @@ ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.3 endif +# Edit the path below to point to the base of your fbopenssl package. +ifndef FBOPENSSL_PATH +FBOPENSSL_PATH = ../../fbopenssl-0.4 +endif + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = ../ares @@ -95,7 +100,7 @@ else endif PERL = perl # Here you can find a native Win32 binary of the original awk: -# http://www.gknw.net/development/prgtools/awk-20070501.zip +# http://www.gknw.net/development/prgtools/awk-20100523.zip AWK = awk CP = cp -afv MKDIR = mkdir @@ -181,6 +186,43 @@ CURL_LIB = ../lib INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) +ifeq ($(findstring -static,$(CFG)),-static) +LINK_STATIC = 1 +endif +ifeq ($(findstring -ares,$(CFG)),-ares) +WITH_ARES = 1 +endif +ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +WITH_RTMP = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +WITH_SSH2 = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -axtls,$(CFG)),-axtls) +WITH_AXTLS = 1 +WITH_SSL = +else +ifeq ($(findstring -ssl,$(CFG)),-ssl) +WITH_SSL = 1 +endif +endif +ifeq ($(findstring -zlib,$(CFG)),-zlib) +WITH_ZLIB = 1 +endif +ifeq ($(findstring -idn,$(CFG)),-idn) +WITH_IDN = 1 +endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +WITH_SPNEGO = 1 +endif +ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +ENABLE_IPV6 = 1 +endif + ifdef WITH_ARES INCLUDES += -I$(LIBCARES_PATH) LDLIBS += $(LIBCARES_PATH)/libcares.$(LIBEXT) @@ -204,6 +246,10 @@ ifdef WITH_SSL LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) IMPORTS += GetProcessSwitchCount RunningProcess INSTDEP += ca-bundle.crt +ifdef WITH_SPNEGO + INCLUDES += -I$(FBOPENSSL_PATH)/include + LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT) +endif else ifdef WITH_AXTLS INCLUDES += -I$(AXTLS_PATH)/inc @@ -498,6 +544,7 @@ endif @echo $(DL)#define USE_MANUAL 1$(DL) >> $@ @echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@ + @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@ @@ -583,6 +630,9 @@ ifdef WITH_SSL @echo $(DL)#define HAVE_LIBSSL 1$(DL) >> $@ @echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ +ifdef WITH_SPNEGO + @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ +endif else ifdef WITH_AXTLS @echo $(DL)#define USE_AXTLS 1$(DL) >> $@ diff --git a/lib/Makefile.vc6 b/lib/Makefile.vc6 index a778801dc..fb7566660 100644 --- a/lib/Makefile.vc6 +++ b/lib/Makefile.vc6 @@ -20,6 +20,11 @@ #
#***************************************************************************
+# All files in the Makefile.vc* series are generated automatically from the
+# one made for MSVC version 6. Alas, if you want to do changes to any of the
+# fiels and send back to the project, edit the version six, make your diff and
+# mail curl-library.
+
###########################################################################
#
# Makefile for building libcurl with MSVC6
@@ -59,13 +64,14 @@ !INCLUDE ..\Makefile.msvc.names
-
-
-
!IFNDEF OPENSSL_PATH
OPENSSL_PATH = ../../openssl-0.9.8r
!ENDIF
+!IFNDEF LIBSSH2_PATH
+LIBSSH2_PATH = ../../libssh2-1.2.8
+!ENDIF
+
!IFNDEF ZLIB_PATH
ZLIB_PATH = ../../zlib-1.2.5
!ENDIF
@@ -100,6 +106,7 @@ WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK" CCNODBG = cl.exe /O2 /DNDEBUG
CCDEBUG = cl.exe /Od /Gm /Zi /D_DEBUG /GZ
CFLAGSSSL = /DUSE_SSLEAY /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl"
+CFLAGSSSH2 = /DUSE_LIBSSH2 /DCURL_DISABLE_LDAP /DHAVE_LIBSSH2 /DHAVE_LIBSSH2_H /DLIBSSH2_WIN32 /DLIBSSH2_LIBRARY /I "$(LIBSSH2_PATH)/include"
CFLAGSZLIB = /DHAVE_ZLIB_H /DHAVE_ZLIB /DHAVE_LIBZ /I "$(ZLIB_PATH)"
CFLAGS = /I. /I../include /nologo /W3 /GX /DWIN32 /YX /FD /c /DBUILDING_LIBCURL /D_BIND_TO_CURRENT_VCLIBS_VERSION=1
CFLAGSLIB = /DCURL_STATICLIB
@@ -220,6 +227,36 @@ CFGSET = TRUE !ENDIF
######################
+# release-ssl-ssh2-zlib
+
+!IF "$(CFG)" == "release-ssl-ssh2-zlib"
+TARGET = $(LIB_NAME).lib
+DIROBJ = $(CFG)
+LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32"
+LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)"
+LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)"
+LNK = $(LNKLIB) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET)
+CC = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB)
+CFGSET = TRUE
+RESOURCE = $(LIBSSH2_PATH)/Release/src/libssh2.lib $(ZLIB_PATH)/zlib.lib
+!ENDIF
+
+######################
+# debug-ssl-ssh2-zlib
+
+!IF "$(CFG)" == "debug-ssl-ssh2-zlib"
+TARGET = $(LIB_NAME_DEBUG).lib
+DIROBJ = $(CFG)
+LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)"
+LFLAGSSSH2 = "/LIBPATH:$(LIBSSH2_PATH)"
+LFLAGSSSL = "/LIBPATH:$(OPENSSL_PATH)\out32"
+LNK = $(LNKLIB) $(ZLIBLIBS) $(LFLAGSSSL) $(LFLAGSSSH2) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET)
+CC = $(CCDEBUG) $(RTLIBD) $(CFLAGSSSL) $(CFLAGSSSH2) $(CFLAGSZLIB) $(CFLAGSLIB)
+CFGSET = TRUE
+RESOURCE = $(LIBSSH2_PATH)/Release/src/libssh2.lib $(ZLIB_PATH)/zlib.lib
+!ENDIF
+
+######################
# release-dll
!IF "$(CFG)" == "release-dll"
@@ -418,6 +455,7 @@ RESOURCE = $(DIROBJ)\libcurl.res !MESSAGE release-ssl - release static library with ssl
!MESSAGE release-zlib - release static library with zlib
!MESSAGE release-ssl-zlib - release static library with ssl and zlib
+!MESSAGE release-ssl-ssh2-zlib - release static library with ssl, ssh2 and zlib
!MESSAGE release-ssl-dll - release static library with dynamic ssl
!MESSAGE release-zlib-dll - release static library with dynamic zlib
!MESSAGE release-ssl-dll-zlib-dll - release static library with dynamic ssl and dynamic zlib
@@ -425,6 +463,7 @@ RESOURCE = $(DIROBJ)\libcurl.res !MESSAGE release-dll-ssl-dll - release dynamic library with dynamic ssl
!MESSAGE release-dll-zlib-dll - release dynamic library with dynamic zlib
!MESSAGE release-dll-ssl-dll-zlib-dll - release dynamic library with dynamic ssl and dynamic zlib
+!MESSAGE debug-ssl-ssh2-zlib - debug static library with ssl, ssh2 and zlib
!MESSAGE debug - debug static library
!MESSAGE debug-ssl - debug static library with ssl
!MESSAGE debug-zlib - debug static library with zlib
@@ -467,6 +506,10 @@ X_OBJS= \ $(DIROBJ)\curl_fnmatch.obj \
$(DIROBJ)\curl_gethostname.obj \
$(DIROBJ)\curl_memrchr.obj \
+ $(DIROBJ)\curl_ntlm.obj \
+ $(DIROBJ)\curl_ntlm_core.obj \
+ $(DIROBJ)\curl_ntlm_msgs.obj \
+ $(DIROBJ)\curl_ntlm_wb.obj \
$(DIROBJ)\curl_rand.obj \
$(DIROBJ)\curl_rtmp.obj \
$(DIROBJ)\curl_sspi.obj \
@@ -494,7 +537,6 @@ X_OBJS= \ $(DIROBJ)\http_digest.obj \
$(DIROBJ)\http_negotiate.obj \
$(DIROBJ)\http_negotiate_sspi.obj \
- $(DIROBJ)\http_ntlm.obj \
$(DIROBJ)\http.obj \
$(DIROBJ)\http_proxy.obj \
$(DIROBJ)\if2ip.obj \
diff --git a/lib/asyn-ares.c b/lib/asyn-ares.c index 4165a451d..7f3bdf8a2 100644 --- a/lib/asyn-ares.c +++ b/lib/asyn-ares.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -39,16 +37,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/asyn-thread.c b/lib/asyn-thread.c index 3341686d9..38cde5df7 100644 --- a/lib/asyn-thread.c +++ b/lib/asyn-thread.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -37,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #if defined(USE_THREADS_POSIX) @@ -421,7 +414,7 @@ static bool init_resolve_thread (struct connectdata *conn, socket error string function can be used for this pupose. */ static const char *gai_strerror(int ecode) { - switch (ecode){ + switch (ecode) { case EAI_AGAIN: return "The name could not be resolved at this time"; case EAI_BADFLAGS: @@ -633,14 +626,28 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, int *waitp) { struct addrinfo hints; + struct in_addr in; Curl_addrinfo *res; int error; char sbuf[NI_MAXSERV]; int pf = PF_INET; +#ifdef CURLRES_IPV6 + struct in6_addr in6; +#endif /* CURLRES_IPV6 */ *waitp = 0; /* default to synchronous response */ -#ifndef CURLRES_IPV4 + /* 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 */ + return Curl_ip2addr(AF_INET, &in, hostname, port); + +#ifdef CURLRES_IPV6 + /* check if this is an IPv6 address string */ + if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0) + /* This is an IPv6 address literal */ + return Curl_ip2addr(AF_INET6, &in6, hostname, port); + /* * Check if a limited name resolve has been requested. */ @@ -660,7 +667,7 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, /* the stack seems to be a non-ipv6 one */ pf = PF_INET; -#endif /* !CURLRES_IPV4 */ +#endif /* CURLRES_IPV6 */ memset(&hints, 0, sizeof(hints)); hints.ai_family = pf; diff --git a/lib/asyn.h b/lib/asyn.h index 34f9c14c5..e7c1b886d 100644 --- a/lib/asyn.h +++ b/lib/asyn.h @@ -146,15 +146,15 @@ Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn, #ifndef CURLRES_ASYNCH /* convert these functions if an asynch resolver isn't used */ -#define Curl_resolver_cancel(x) +#define Curl_resolver_cancel(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_getsock(x,y,z) 0 #define Curl_resolver_duphandle(x,y) CURLE_OK #define Curl_resolver_init(x) CURLE_OK #define Curl_resolver_global_init() CURLE_OK -#define Curl_resolver_global_cleanup() -#define Curl_resolver_cleanup(x) +#define Curl_resolver_global_cleanup() Curl_nop_stmt +#define Curl_resolver_cleanup(x) Curl_nop_stmt #endif #ifdef CURLRES_ASYNCH diff --git a/lib/axtls.c b/lib/axtls.c index ffbd1d4f3..e37aed50a 100644 --- a/lib/axtls.c +++ b/lib/axtls.c @@ -27,13 +27,11 @@ */ #include "setup.h" + #ifdef USE_AXTLS #include <axTLS/ssl.h> #include "axtls.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -58,7 +56,7 @@ static int SSL_read(SSL *ssl, void *buf, int num) while((ret = ssl_read(ssl, &read_buf)) == SSL_OK); - if(ret > SSL_OK){ + if(ret > SSL_OK) { memcpy(buf, read_buf, ret > num ? num : ret); } @@ -187,10 +185,10 @@ Curl_axtls_connect(struct connectdata *conn, /* Load the trusted CA cert bundle file */ if(data->set.ssl.CAfile) { if(ssl_obj_load(ssl_ctx, SSL_OBJ_X509_CACERT, data->set.ssl.CAfile, NULL) - != SSL_OK){ + != SSL_OK) { infof(data, "error reading ca cert file %s \n", data->set.ssl.CAfile); - if(data->set.ssl.verifypeer){ + if(data->set.ssl.verifypeer) { Curl_axtls_close(conn, sockindex); return CURLE_SSL_CACERT_BADFILE; } @@ -208,13 +206,13 @@ Curl_axtls_connect(struct connectdata *conn, */ /* Load client certificate */ - if(data->set.str[STRING_CERT]){ + if(data->set.str[STRING_CERT]) { i=0; /* Instead of trying to analyze cert type here, let axTLS try them all. */ - while(cert_types[i] != 0){ + while(cert_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i], data->set.str[STRING_CERT], NULL); - if(ssl_fcn_return == SSL_OK){ + if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read cert file %s \n", data->set.str[STRING_CERT]); break; @@ -222,7 +220,7 @@ Curl_axtls_connect(struct connectdata *conn, i++; } /* Tried all cert types, none worked. */ - if(cert_types[i] == 0){ + if(cert_types[i] == 0) { failf(data, "%s is not x509 or pkcs12 format", data->set.str[STRING_CERT]); Curl_axtls_close(conn, sockindex); @@ -233,13 +231,13 @@ Curl_axtls_connect(struct connectdata *conn, /* Load client key. If a pkcs12 file successfully loaded a cert, then there's nothing to do because the key has already been loaded. */ - if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12){ + if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) { i=0; /* Instead of trying to analyze key type here, let axTLS try them all. */ - while(key_types[i] != 0){ + while(key_types[i] != 0) { ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i], data->set.str[STRING_KEY], NULL); - if(ssl_fcn_return == SSL_OK){ + if(ssl_fcn_return == SSL_OK) { infof(data, "successfully read key file %s \n", data->set.str[STRING_KEY]); break; @@ -247,7 +245,7 @@ Curl_axtls_connect(struct connectdata *conn, i++; } /* Tried all key types, none worked. */ - if(key_types[i] == 0){ + if(key_types[i] == 0) { failf(data, "Failure: %s is not a supported key file", data->set.str[STRING_KEY]); Curl_axtls_close(conn, sockindex); @@ -273,7 +271,7 @@ Curl_axtls_connect(struct connectdata *conn, /* Check to make sure handshake was ok. */ ssl_fcn_return = ssl_handshake_status(ssl); - if(ssl_fcn_return != SSL_OK){ + if(ssl_fcn_return != SSL_OK) { Curl_axtls_close(conn, sockindex); ssl_display_error(ssl_fcn_return); /* goes to stdout. */ return map_error_to_curl(ssl_fcn_return); @@ -285,8 +283,8 @@ Curl_axtls_connect(struct connectdata *conn, */ /* Verify server's certificate */ - if(data->set.ssl.verifypeer){ - if(ssl_verify_cert(ssl) != SSL_OK){ + if(data->set.ssl.verifypeer) { + if(ssl_verify_cert(ssl) != SSL_OK) { Curl_axtls_close(conn, sockindex); failf(data, "server cert verify failed"); return CURLE_SSL_CONNECT_ERROR; @@ -415,7 +413,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf, sizeof(buf)); - if(nread < SSL_OK){ + if(nread < SSL_OK) { failf(data, "close notify alert not received during shutdown"); retval = -1; } @@ -447,13 +445,13 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ infof(conn->data, " axtls_recv\n"); - if(connssl){ + if(connssl) { ret = (ssize_t)SSL_read(conn->ssl[num].ssl, buf, (int)buffersize); /* axTLS isn't terribly generous about error reporting */ /* With patched axTLS, SSL_CLOSE_NOTIFY=-3. Hard-coding until axTLS team approves proposed fix. */ - if(ret == -3 ){ + if(ret == -3 ) { Curl_axtls_close(conn, num); } else if(ret < 0) { diff --git a/lib/base64.c b/lib/base64.c index 0de1f0100..23ebb4aa9 100644 --- a/lib/base64.c +++ b/lib/base64.c @@ -24,9 +24,6 @@ #include "setup.h" -#include <stdlib.h> -#include <string.h> - #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -71,12 +68,19 @@ static void decodeQuantum(unsigned char *dest, const char *src) /* * Curl_base64_decode() * - * Given a base64 string at src, decode it and return an allocated memory in - * the *outptr. Returns the length of the decoded data. + * 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 */ -size_t Curl_base64_decode(const char *src, unsigned char **outptr) +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen) { size_t length = 0; size_t equalsTerm = 0; @@ -87,6 +91,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) unsigned char *newstr; *outptr = NULL; + *outlen = 0; while((src[length] != '=') && src[length]) length++; @@ -100,7 +105,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) /* Don't allocate a buffer if the decoded length is 0 */ if(numQuantums == 0) - return 0; + return CURLE_OK; rawlen = (numQuantums * 3) - equalsTerm; @@ -108,7 +113,7 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) (which may be partially thrown out) and the zero terminator. */ newstr = malloc(rawlen+4); if(!newstr) - return 0; + return CURLE_OUT_OF_MEMORY; *outptr = newstr; @@ -127,23 +132,34 @@ size_t Curl_base64_decode(const char *src, unsigned char **outptr) newstr[i] = lastQuantum[i]; newstr[i] = '\0'; /* zero terminate */ - return rawlen; + + *outlen = rawlen; /* return size of decoded data */ + + return CURLE_OK; } /* * Curl_base64_encode() * - * Returns the length of the newly created base64 string. The third argument - * is a pointer to an allocated area holding the base64 data. If something - * went wrong, 0 is returned. + * 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. + * + * When encoded data length is 0, returns NULL in *outptr. * * @unittest: 1302 */ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr) +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen) { - CURLcode res; + CURLcode error; unsigned char ibuf[3]; unsigned char obuf[4]; int i; @@ -154,24 +170,25 @@ size_t Curl_base64_encode(struct SessionHandle *data, const char *indata = inputbuff; - *outptr = NULL; /* set to NULL in case of failure before we reach the end */ + *outptr = NULL; + *outlen = 0; if(0 == insize) insize = strlen(indata); base64data = output = malloc(insize*4/3+4); if(NULL == output) - return 0; + return CURLE_OUT_OF_MEMORY; /* * The base64 data needs to be created using the network encoding * not the host encoding. And we can't change the actual input * so we copy it to a buffer, translate it, and use that instead. */ - res = Curl_convert_clone(data, indata, insize, &convbuf); - if(res) { + error = Curl_convert_clone(data, indata, insize, &convbuf); + if(error) { free(output); - return 0; + return error; } if(convbuf) @@ -218,12 +235,14 @@ size_t Curl_base64_encode(struct SessionHandle *data, } output += 4; } - *output=0; - *outptr = base64data; /* make it return the actual data memory */ + *output = '\0'; + *outptr = base64data; /* return pointer to new data, allocated memory */ if(convbuf) free(convbuf); - return strlen(base64data); /* return the length of the new data */ + *outlen = strlen(base64data); /* return the length of the new data */ + + return CURLE_OK; } /* ---- End of Base64 Encoding ---- */ diff --git a/lib/checksrc.pl b/lib/checksrc.pl index 5d369496a..9f5058ddb 100755 --- a/lib/checksrc.pl +++ b/lib/checksrc.pl @@ -62,7 +62,7 @@ while(1) { next; } elsif($file =~ /-W(.*)/) { - $wlist = $1; + $wlist .= " $1 "; $file = shift @ARGV; next; } @@ -79,7 +79,7 @@ if(!$file) { } do { - if($file ne "$wlist") { + if("$wlist" !~ / $file /) { my $fullname = $file; $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/'); scanfile($fullname); @@ -145,9 +145,14 @@ sub scanfile { } # check for "} else" - if($l =~ /^(.*)\} else/) { + if($l =~ /^(.*)\} *else/) { checkwarn($line, length($1), $file, $l, "else after closing brace on same line"); } + # check for "){" + if($l =~ /^(.*)\)\{/) { + checkwarn($line, length($1)+1, $file, $l, "missing space after close paren"); + } + # check for open brace first on line but not first column # only alert if previous line ended with a close paren and wasn't a cpp # line diff --git a/lib/config-amigaos.h b/lib/config-amigaos.h index 99b96d656..1474ba915 100644 --- a/lib/config-amigaos.h +++ b/lib/config-amigaos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #define HAVE_ARPA_INET_H 1 #define HAVE_CLOSESOCKET_CAMEL 1 +#define HAVE_ERRNO_H 1 #define HAVE_GETHOSTBYADDR 1 #define HAVE_INET_ADDR 1 #define HAVE_INTTYPES_H 1 diff --git a/lib/config-dos.h b/lib/config-dos.h index 35d21aae2..694a30465 100644 --- a/lib/config-dos.h +++ b/lib/config-dos.h @@ -40,6 +40,7 @@ #define PACKAGE "curl" #define HAVE_ARPA_INET_H 1 +#define HAVE_ERRNO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_GETADDRINFO 1 #define HAVE_GETNAMEINFO 1 diff --git a/lib/config-mac.h b/lib/config-mac.h index 80af84e52..72e8260d1 100644 --- a/lib/config-mac.h +++ b/lib/config-mac.h @@ -30,6 +30,7 @@ #define OS "mac" +#define HAVE_ERRNO_H 1 #define HAVE_NETINET_IN_H 1 #define HAVE_SYS_SOCKET_H 1 #define HAVE_SYS_SELECT_H 1 diff --git a/lib/config-os400.h b/lib/config-os400.h index 8dba1e4cd..4d2730928 100644 --- a/lib/config-os400.h +++ b/lib/config-os400.h @@ -97,6 +97,9 @@ /* Define if you have the <des.h> header file. */ #undef HAVE_DES_H +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H + /* Define if you have the <err.h> header file. */ #undef HAVE_ERR_H diff --git a/lib/config-riscos.h b/lib/config-riscos.h index 5ccf68124..127dbdb0a 100644 --- a/lib/config-riscos.h +++ b/lib/config-riscos.h @@ -92,6 +92,9 @@ /* Define if you have the <des.h> header file. */ #undef HAVE_DES_H +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H + /* Define if you have the <err.h> header file. */ #undef HAVE_ERR_H diff --git a/lib/config-vms.h b/lib/config-vms.h index e3844f83b..75c77d1b1 100644 --- a/lib/config-vms.h +++ b/lib/config-vms.h @@ -143,6 +143,9 @@ /* Define if you have the uname function. */ #define HAVE_UNAME 1 +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + /* Define if you have the <err.h> header file. */ #define HAVE_ERR_H 1 diff --git a/lib/config-win32.h b/lib/config-win32.h index 6768dda3c..cfbca9ca3 100644 --- a/lib/config-win32.h +++ b/lib/config-win32.h @@ -1,5 +1,5 @@ -#ifndef __LIB_CONFIG_WIN32_H -#define __LIB_CONFIG_WIN32_H +#ifndef HEADER_CURL_CONFIG_WIN32_H +#define HEADER_CURL_CONFIG_WIN32_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -23,49 +23,57 @@ ***************************************************************************/ /* ================================================================ */ -/* lib/config-win32.h - Hand crafted config file for Windows */ +/* Hand crafted config file for Windows */ /* ================================================================ */ /* ---------------------------------------------------------------- */ /* HEADER FILES */ /* ---------------------------------------------------------------- */ -/* Define if you have the <arpa/inet.h> header file. */ +/* Define if you have the <arpa/inet.h> header file. */ /* #define HAVE_ARPA_INET_H 1 */ -/* Define if you have the <assert.h> header file. */ +/* Define if you have the <assert.h> header file. */ #define HAVE_ASSERT_H 1 -/* Define if you have the <crypto.h> header file. */ +/* Define if you have the <crypto.h> header file. */ /* #define HAVE_CRYPTO_H 1 */ -/* Define if you have the <err.h> header file. */ +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H 1 + +/* Define if you have the <err.h> header file. */ /* #define HAVE_ERR_H 1 */ -/* Define if you have the <fcntl.h> header file. */ +/* Define if you have the <fcntl.h> header file. */ #define HAVE_FCNTL_H 1 -/* Define if you have the <getopt.h> header file. */ -/* #define HAVE_GETOPT_H 1 */ +/* Define if you have the <getopt.h> header file. */ +#if defined(__MINGW32__) || defined(__POCC__) +#define HAVE_GETOPT_H 1 +#endif -/* Define if you have the <io.h> header file. */ +/* Define if you have the <io.h> header file. */ #define HAVE_IO_H 1 -/* Define if you have the <limits.h> header file. */ +/* Define if you have the <limits.h> header file. */ #define HAVE_LIMITS_H 1 -/* Define if you need the malloc.h header file even with stdlib.h */ +/* Define if you have the <locale.h> header file. */ +#define HAVE_LOCALE_H 1 + +/* Define if you need <malloc.h> header even with <stdlib.h> header file. */ #if !defined(__SALFORDC__) && !defined(__POCC__) #define NEED_MALLOC_H 1 #endif -/* Define if you have the <netdb.h> header file. */ +/* Define if you have the <netdb.h> header file. */ /* #define HAVE_NETDB_H 1 */ -/* Define if you have the <netinet/in.h> header file. */ +/* Define if you have the <netinet/in.h> header file. */ /* #define HAVE_NETINET_IN_H 1 */ -/* Define if you have the <process.h> header file. */ +/* Define if you have the <process.h> header file. */ #ifndef __SALFORDC__ #define HAVE_PROCESS_H 1 #endif @@ -73,68 +81,68 @@ /* Define if you have the <signal.h> header file. */ #define HAVE_SIGNAL_H 1 -/* Define if you have the <sgtty.h> header file. */ +/* Define if you have the <sgtty.h> header file. */ /* #define HAVE_SGTTY_H 1 */ -/* Define if you have the <ssl.h> header file. */ +/* Define if you have the <ssl.h> header file. */ /* #define HAVE_SSL_H 1 */ -/* Define if you have the <stdlib.h> header file. */ +/* Define if you have the <stdlib.h> header file. */ #define HAVE_STDLIB_H 1 -/* Define if you have the <sys/param.h> header file. */ +/* Define if you have the <sys/param.h> header file. */ /* #define HAVE_SYS_PARAM_H 1 */ -/* Define if you have the <sys/select.h> header file. */ +/* Define if you have the <sys/select.h> header file. */ /* #define HAVE_SYS_SELECT_H 1 */ -/* Define if you have the <sys/socket.h> header file. */ +/* Define if you have the <sys/socket.h> header file. */ /* #define HAVE_SYS_SOCKET_H 1 */ -/* Define if you have the <sys/sockio.h> header file. */ +/* Define if you have the <sys/sockio.h> header file. */ /* #define HAVE_SYS_SOCKIO_H 1 */ -/* Define if you have the <sys/stat.h> header file. */ +/* Define if you have the <sys/stat.h> header file. */ #define HAVE_SYS_STAT_H 1 -/* Define if you have the <sys/time.h> header file */ +/* Define if you have the <sys/time.h> header file. */ /* #define HAVE_SYS_TIME_H 1 */ -/* Define if you have the <sys/types.h> header file. */ +/* Define if you have the <sys/types.h> header file. */ #define HAVE_SYS_TYPES_H 1 -/* Define if you have the <sys/utime.h> header file. */ +/* Define if you have the <sys/utime.h> header file. */ #ifndef __BORLANDC__ #define HAVE_SYS_UTIME_H 1 #endif -/* Define if you have the <termio.h> header file. */ +/* Define if you have the <termio.h> header file. */ /* #define HAVE_TERMIO_H 1 */ -/* Define if you have the <termios.h> header file. */ +/* Define if you have the <termios.h> header file. */ /* #define HAVE_TERMIOS_H 1 */ -/* Define if you have the <time.h> header file. */ +/* Define if you have the <time.h> header file. */ #define HAVE_TIME_H 1 -/* Define if you have the <unistd.h> header file. */ +/* Define if you have the <unistd.h> header file. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ defined(__POCC__) #define HAVE_UNISTD_H 1 #endif -/* Define if you have the <windows.h> header file. */ +/* Define if you have the <windows.h> header file. */ #define HAVE_WINDOWS_H 1 -/* Define if you have the <winsock.h> header file. */ +/* Define if you have the <winsock.h> header file. */ #define HAVE_WINSOCK_H 1 -/* Define if you have the <winsock2.h> header file. */ +/* Define if you have the <winsock2.h> header file. */ #ifndef __SALFORDC__ #define HAVE_WINSOCK2_H 1 #endif -/* Define if you have the <ws2tcpip.h> header file. */ +/* Define if you have the <ws2tcpip.h> header file. */ #ifndef __SALFORDC__ #define HAVE_WS2TCPIP_H 1 #endif @@ -146,41 +154,44 @@ /* Define if sig_atomic_t is an available typedef. */ #define HAVE_SIG_ATOMIC_T 1 -/* Define if you have the ANSI C header files. */ +/* Define if you have the ANSI C header files. */ #define STDC_HEADERS 1 -/* Define if you can safely include both <sys/time.h> and <time.h>. */ +/* Define if you can safely include both <sys/time.h> and <time.h>. */ /* #define TIME_WITH_SYS_TIME 1 */ /* ---------------------------------------------------------------- */ /* FUNCTIONS */ /* ---------------------------------------------------------------- */ -/* Define if you have the closesocket function. */ +/* Define if you have the closesocket function. */ #define HAVE_CLOSESOCKET 1 -/* Define if you don't have vprintf but do have _doprnt. */ +/* Define if you don't have vprintf but do have _doprnt. */ /* #define HAVE_DOPRNT 1 */ -/* Define if you have the gethostbyaddr function. */ +/* Define if you have the ftruncate function. */ +#define HAVE_FTRUNCATE 1 + +/* Define if you have the gethostbyaddr function. */ #define HAVE_GETHOSTBYADDR 1 -/* Define if you have the gethostname function. */ +/* Define if you have the gethostname function. */ #define HAVE_GETHOSTNAME 1 -/* Define if you have the getpass function. */ +/* Define if you have the getpass function. */ /* #define HAVE_GETPASS 1 */ -/* Define if you have the getservbyname function. */ +/* Define if you have the getservbyname function. */ #define HAVE_GETSERVBYNAME 1 -/* Define if you have the getprotobyname function. */ +/* Define if you have the getprotobyname function. */ #define HAVE_GETPROTOBYNAME -/* Define if you have the gettimeofday function. */ +/* Define if you have the gettimeofday function. */ /* #define HAVE_GETTIMEOFDAY 1 */ -/* Define if you have the inet_addr function. */ +/* Define if you have the inet_addr function. */ #define HAVE_INET_ADDR 1 /* Define if you have the ioctlsocket function. */ @@ -189,35 +200,41 @@ /* Define if you have a working ioctlsocket FIONBIO function. */ #define HAVE_IOCTLSOCKET_FIONBIO 1 -/* Define if you have the perror function. */ +/* Define if you have the perror function. */ #define HAVE_PERROR 1 -/* Define if you have the RAND_screen function when using SSL */ +/* Define if you have the RAND_screen function when using SSL. */ #define HAVE_RAND_SCREEN 1 /* Define if you have the `RAND_status' function when using SSL. */ #define HAVE_RAND_STATUS 1 -/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. +/* Define if you have the `CRYPTO_cleanup_all_ex_data' function. This is present in OpenSSL versions after 0.9.6b */ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1 -/* Define if you have the select function. */ +/* Define if you have the select function. */ #define HAVE_SELECT 1 -/* Define if you have the setvbuf function. */ +/* 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 setvbuf function. */ #define HAVE_SETVBUF 1 -/* Define if you have the socket function. */ +/* Define if you have the socket function. */ #define HAVE_SOCKET 1 -/* Define if you have the strcasecmp function. */ +/* Define if you have the strcasecmp function. */ /* #define HAVE_STRCASECMP 1 */ -/* Define if you have the strdup function. */ +/* Define if you have the strdup function. */ #define HAVE_STRDUP 1 -/* Define if you have the strftime function. */ +/* Define if you have the strftime function. */ #define HAVE_STRFTIME 1 /* Define if you have the stricmp function. */ @@ -229,21 +246,21 @@ /* Define if you have the strnicmp function. */ #define HAVE_STRNICMP 1 -/* Define if you have the strstr function. */ +/* Define if you have the strstr function. */ #define HAVE_STRSTR 1 -/* Define if you have the strtoll function. */ +/* Define if you have the strtoll function. */ #if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__) #define HAVE_STRTOLL 1 #endif -/* Define if you have the tcgetattr function. */ +/* Define if you have the tcgetattr function. */ /* #define HAVE_TCGETATTR 1 */ -/* Define if you have the tcsetattr function. */ +/* Define if you have the tcsetattr function. */ /* #define HAVE_TCSETATTR 1 */ -/* Define if you have the utime function */ +/* Define if you have the utime function. */ #ifndef __BORLANDC__ #define HAVE_UTIME 1 #endif @@ -330,13 +347,13 @@ /* TYPEDEF REPLACEMENTS */ /* ---------------------------------------------------------------- */ -/* Define this if in_addr_t is not an available 'typedefed' type */ +/* Define if in_addr_t is not an available 'typedefed' type. */ #define in_addr_t unsigned long -/* Define as the return type of signal handlers (int or void). */ +/* Define to the return type of signal handlers (int or void). */ #define RETSIGTYPE void -/* Define ssize_t if it is not an available 'typedefed' type */ +/* Define if ssize_t is not an available 'typedefed' type. */ #ifndef _SSIZE_T_DEFINED # if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ defined(__POCC__) || \ @@ -354,19 +371,19 @@ /* TYPE SIZES */ /* ---------------------------------------------------------------- */ -/* The size of `int', as computed by sizeof. */ +/* Define to the size of `int', as computed by sizeof. */ #define SIZEOF_INT 4 -/* The size of `long double', as computed by sizeof. */ +/* Define to the size of `long double', as computed by sizeof. */ #define SIZEOF_LONG_DOUBLE 16 -/* The size of `long long', as computed by sizeof. */ +/* Define to the size of `long long', as computed by sizeof. */ /* #define SIZEOF_LONG_LONG 8 */ -/* The size of `short', as computed by sizeof. */ +/* Define to the size of `short', as computed by sizeof. */ #define SIZEOF_SHORT 2 -/* The size of `size_t', as computed by sizeof. */ +/* Define to the size of `size_t', as computed by sizeof. */ #if defined(_WIN64) # define SIZEOF_SIZE_T 8 #else @@ -377,14 +394,49 @@ /* STRUCT RELATED */ /* ---------------------------------------------------------------- */ -/* Define this if you have struct sockaddr_storage */ +/* Define if you have struct sockaddr_storage. */ #if !defined(__SALFORDC__) && !defined(__BORLANDC__) #define HAVE_STRUCT_SOCKADDR_STORAGE 1 #endif -/* Define this if you have struct timeval */ +/* 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 + +/* ---------------------------------------------------------------- */ +/* BSD-style lwIP TCP/IP stack SPECIFIC */ +/* ---------------------------------------------------------------- */ + +/* Define to use BSD-style lwIP TCP/IP stack. */ +/* #define USE_LWIPSOCK 1 */ + +#ifdef USE_LWIPSOCK +# undef USE_WINSOCK +# undef HAVE_WINSOCK_H +# undef HAVE_WINSOCK2_H +# undef HAVE_WS2TCPIP_H +# undef HAVE_ERRNO_H +# undef HAVE_GETHOSTNAME +# undef HAVE_GETNAMEINFO +# undef LWIP_POSIX_SOCKETS_IO_NAMES +# undef RECV_TYPE_ARG1 +# undef RECV_TYPE_ARG3 +# undef SEND_TYPE_ARG1 +# undef SEND_TYPE_ARG3 +# define HAVE_FREEADDRINFO +# define HAVE_GETADDRINFO +# define HAVE_GETHOSTBYNAME +# 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 +#endif + /* ---------------------------------------------------------------- */ /* Watt-32 tcp/ip SPECIFIC */ /* ---------------------------------------------------------------- */ @@ -413,8 +465,11 @@ /* COMPILER SPECIFIC */ /* ---------------------------------------------------------------- */ -/* Undef keyword 'const' if it does not work. */ -/* #undef const */ +/* 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 */ @@ -429,14 +484,14 @@ #define HAVE_LONGLONG 1 #endif -/* Define to avoid VS2005 complaining about portable C functions */ +/* 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 dafault size for time_t is 64-bit, unless */ -/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */ +/* VS2005 and later dafault 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 @@ -446,12 +501,13 @@ #endif /* Officially, Microsoft's Windows SDK versions 6.X do not support Windows - 2000 as a supported build target. VS2008 default installations provide 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 using - Windows SDK versions 6.X and Windows 2000 as a build target are functional */ + 2000 as a supported build target. VS2008 default installations provide + 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 6.X and Windows 2000 as a build + target are functional. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_MINIMUM_TARGET 0x0500 +# define VS2008_MIN_TARGET 0x0500 #endif /* When no build target is specified VS2008 default build target is Windows @@ -459,18 +515,18 @@ for VS2008 we will target the minimum Officially supported build target, which happens to be Windows XP. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_DEFAULT_TARGET 0x0501 +# define VS2008_DEF_TARGET 0x0501 #endif -/* VS2008 default target settings and minimum build target check */ +/* VS2008 default target settings and minimum build target check. */ #if defined(_MSC_VER) && (_MSC_VER >= 1500) # ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEFAULT_TARGET +# define _WIN32_WINNT VS2008_DEF_TARGET # endif # ifndef WINVER -# define WINVER VS2008_DEFAULT_TARGET +# define WINVER VS2008_DEF_TARGET # endif -# if (_WIN32_WINNT < VS2008_MINIMUM_TARGET) || (WINVER < VS2008_MINIMUM_TARGET) +# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET) # error VS2008 does not support Windows build targets prior to Windows 2000 # endif #endif @@ -549,13 +605,13 @@ /* ---------------------------------------------------------------- */ /* - * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS + * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS. */ -/* Define USE_ARES to enable c-ares asynchronous DNS lookups */ +/* Define to enable c-ares asynchronous DNS lookups. */ /* #define USE_ARES 1 */ -/* Define USE_THREADS_WIN32 to enable threaded asynchronous DNS lookups */ +/* Define to enable threaded asynchronous DNS lookups. */ #define USE_THREADS_WIN32 1 #if defined(USE_ARES) && defined(USE_THREADS_WIN32) @@ -597,10 +653,10 @@ #undef 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) /* Itanium */ #define OS "ia64-pc-win32" -#elif defined(_M_X64) /* AMD64/EM64T - Not defined until MSVC 2005 */ -#define OS "amd64-pc-win32" #else #define OS "unknown-pc-win32" #endif @@ -608,8 +664,11 @@ /* Name of package */ #define PACKAGE "curl" +/* If you want to build curl with the built-in manual */ +#define USE_MANUAL 1 + #if defined(__POCC__) || (USE_IPV6) # define ENABLE_IPV6 1 #endif -#endif /* __LIB_CONFIG_WIN32_H */ +#endif /* HEADER_CURL_CONFIG_WIN32_H */ diff --git a/lib/config-win32ce.h b/lib/config-win32ce.h index 872334286..1ade83fbe 100644 --- a/lib/config-win32ce.h +++ b/lib/config-win32ce.h @@ -39,6 +39,9 @@ /* Define if you have the <crypto.h> header file. */ /* #define HAVE_CRYPTO_H 1 */ +/* Define if you have the <errno.h> header file. */ +/* #define HAVE_ERRNO_H 1 */ + /* Define if you have the <err.h> header file. */ /* #define HAVE_ERR_H 1 */ diff --git a/lib/connect.c b/lib/connect.c index a9185978c..2a1876e71 100644 --- a/lib/connect.c +++ b/lib/connect.c @@ -22,9 +22,6 @@ #include "setup.h" -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -52,9 +49,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include <sys/filio.h> @@ -68,10 +62,6 @@ #include <inet.h> #endif -#include <stdio.h> -#include <errno.h> -#include <string.h> - #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -669,7 +659,7 @@ CURLcode Curl_is_connected(struct connectdata *conn, *connected = FALSE; /* a very negative world view is best */ - if(conn->bits.tcpconnect) { + if(conn->bits.tcpconnect[sockindex]) { /* we are connected already! */ *connected = TRUE; return CURLE_OK; @@ -708,9 +698,10 @@ CURLcode Curl_is_connected(struct connectdata *conn, if(code) return code; - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[sockindex] = TRUE; *connected = TRUE; - Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + if(sockindex == FIRSTSOCKET) + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_verboseconnect(conn); Curl_updateconninfo(conn, sockfd); @@ -756,7 +747,7 @@ static void tcpnodelay(struct connectdata *conn, #ifdef TCP_NODELAY struct SessionHandle *data= conn->data; curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay; - int proto = IPPROTO_TCP; + int level = IPPROTO_TCP; #if 0 /* The use of getprotobyname() is disabled since it isn't thread-safe on @@ -768,10 +759,10 @@ static void tcpnodelay(struct connectdata *conn, detected. */ struct protoent *pe = getprotobyname("tcp"); if(pe) - proto = pe->p_proto; + level = pe->p_proto; #endif - if(setsockopt(sockfd, proto, TCP_NODELAY, (void *)&onoff, + if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff, sizeof(onoff)) < 0) infof(data, "Could not set TCP_NODELAY: %s\n", Curl_strerror(conn, SOCKERRNO)); @@ -799,10 +790,10 @@ static void nosigpipe(struct connectdata *conn, Curl_strerror(conn, SOCKERRNO)); } #else -#define nosigpipe(x,y) +#define nosigpipe(x,y) Curl_nop_stmt #endif -#ifdef WIN32 +#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. @@ -845,7 +836,7 @@ singleipconnect(struct connectdata *conn, { struct Curl_sockaddr_ex addr; int rc; - int error; + int error = 0; bool isconnected = FALSE; struct SessionHandle *data = conn->data; curl_socket_t sockfd; @@ -916,11 +907,6 @@ singleipconnect(struct connectdata *conn, Curl_persistconninfo(conn); -#ifdef ENABLE_IPV6 - if(addr.family == AF_INET6) - conn->bits.ipv6 = TRUE; -#endif - if(data->set.tcp_nodelay) tcpnodelay(conn, sockfd); @@ -955,6 +941,8 @@ singleipconnect(struct connectdata *conn, /* Connect TCP sockets, bind UDP */ if(!isconnected && (conn->socktype == SOCK_STREAM)) { rc = connect(sockfd, &addr.sa_addr, addr.addrlen); + if(-1 == rc) + error = SOCKERRNO; conn->connecttime = Curl_tvnow(); if(conn->num_addr > 1) Curl_expire(data, conn->timeoutms_per_addr); @@ -963,8 +951,6 @@ singleipconnect(struct connectdata *conn, rc = 0; if(-1 == rc) { - error = SOCKERRNO; - switch (error) { case EINPROGRESS: case EWOULDBLOCK: @@ -1008,6 +994,10 @@ singleipconnect(struct connectdata *conn, /* we are connected, awesome! */ *connected = TRUE; /* this is a true connect */ infof(data, "connected\n"); +#ifdef ENABLE_IPV6 + conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE; +#endif + Curl_updateconninfo(conn, sockfd); *sockp = sockfd; return CURLE_OK; diff --git a/lib/connect.h b/lib/connect.h index 3df9d970e..052549368 100644 --- a/lib/connect.h +++ b/lib/connect.h @@ -1,5 +1,5 @@ -#ifndef __CONNECT_H -#define __CONNECT_H +#ifndef HEADER_CURL_CONNECT_H +#define HEADER_CURL_CONNECT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #include "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */ @@ -52,7 +53,7 @@ long Curl_timeleft(struct SessionHandle *data, curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, struct connectdata **connp); -#ifdef WIN32 +#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. @@ -64,10 +65,11 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, */ void Curl_sndbufset(curl_socket_t sockfd); #else -#define Curl_sndbufset(y) +#define Curl_sndbufset(y) Curl_nop_stmt #endif void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd); void Curl_persistconninfo(struct connectdata *conn); int Curl_closesocket(struct connectdata *conn, curl_socket_t sock); -#endif + +#endif /* HEADER_CURL_CONNECT_H */ diff --git a/lib/content_encoding.c b/lib/content_encoding.c index 876115a32..3276ef988 100644 --- a/lib/content_encoding.c +++ b/lib/content_encoding.c @@ -24,9 +24,6 @@ #ifdef HAVE_LIBZ -#include <stdlib.h> -#include <string.h> - #include "urldata.h" #include <curl/curl.h> #include "sendf.h" @@ -52,6 +49,21 @@ #define COMMENT 0x10 /* bit 4 set: file comment present */ #define RESERVED 0xE0 /* bits 5..7: reserved */ +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 connectdata *conn, z_stream *z) { @@ -161,11 +173,10 @@ Curl_unencode_deflate_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + z->zalloc = (alloc_func)zalloc_cb; + z->zfree = (free_func)zfree_cb; + if(inflateInit(z) != Z_OK) return process_zlib_error(conn, z); k->zlib_init = ZLIB_INIT; @@ -272,11 +283,9 @@ Curl_unencode_gzip_write(struct connectdata *conn, /* Initialize zlib? */ if(k->zlib_init == ZLIB_UNINIT) { - z->zalloc = (alloc_func)Z_NULL; - z->zfree = (free_func)Z_NULL; - z->opaque = 0; - z->next_in = NULL; - z->avail_in = 0; + memset(z, 0, sizeof(z_stream)); + 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 */ diff --git a/lib/content_encoding.h b/lib/content_encoding.h index 3aff9d3c0..372da4a3b 100644 --- a/lib/content_encoding.h +++ b/lib/content_encoding.h @@ -1,5 +1,5 @@ -#ifndef __CURL_CONTENT_ENCODING_H -#define __CURL_CONTENT_ENCODING_H +#ifndef HEADER_CURL_CONTENT_ENCODING_H +#define HEADER_CURL_CONTENT_ENCODING_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,7 +32,7 @@ void Curl_unencode_cleanup(struct connectdata *conn); #else #define ALL_CONTENT_ENCODINGS "identity" -#define Curl_unencode_cleanup(x) +#define Curl_unencode_cleanup(x) Curl_nop_stmt #endif CURLcode Curl_unencode_deflate_write(struct connectdata *conn, @@ -45,4 +45,4 @@ Curl_unencode_gzip_write(struct connectdata *conn, ssize_t nread); -#endif +#endif /* HEADER_CURL_CONTENT_ENCODING_H */ diff --git a/lib/cookie.c b/lib/cookie.c index 7657da06e..41ccdbe34 100644 --- a/lib/cookie.c +++ b/lib/cookie.c @@ -81,9 +81,6 @@ Example set of cookies: #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) -#include <stdlib.h> -#include <string.h> - #define _MPRINTF_REPLACE #include <curl/mprintf.h> @@ -129,7 +126,7 @@ static bool tailmatch(const char *little, const char *bigone) if(littlelen > biglen) return FALSE; - return (bool)Curl_raw_equal(little, bigone+biglen-littlelen); + return Curl_raw_equal(little, bigone+biglen-littlelen) ? TRUE : FALSE; } /* @@ -147,9 +144,9 @@ void Curl_cookie_loadfiles(struct SessionHandle *data) data->set.cookiesession); list = list->next; } - Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); curl_slist_free_all(data->change.cookielist); /* clean up list */ data->change.cookielist = NULL; /* don't do this again! */ + Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } } @@ -209,7 +206,6 @@ Curl_cookie_add(struct SessionHandle *data, if(httpheader) { /* This line was read off a HTTP-header */ const char *ptr; - const char *sep; const char *semiptr; char *what; @@ -226,185 +222,186 @@ Curl_cookie_add(struct SessionHandle *data, ptr = lineptr; do { - /* we have a <what>=<this> pair or a 'secure' word here */ - sep = strchr(ptr, '='); - if(sep && (!semiptr || (semiptr>sep)) ) { - /* - * There is a = sign and if there was a semicolon too, which make sure - * that the semicolon comes _after_ the equal sign. - */ - - name[0]=what[0]=0; /* init the buffers */ - if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%" - MAX_COOKIE_LINE_TXT "[^;\r\n]", - name, what)) { - /* this is a <name>=<what> pair. We 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. */ - - const char *whatptr; - - /* Strip off trailing whitespace from the 'what' */ - size_t len=strlen(what); - while(len && ISBLANK(what[len-1])) { - what[len-1]=0; - len--; - } + /* we have a <what>=<this> pair or a stand-alone word here */ + name[0]=what[0]=0; /* init the buffers */ + if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%" + MAX_COOKIE_LINE_TXT "[^;\r\n]", + name, what)) { + /* 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. */ + const char *whatptr; + bool done = FALSE; + bool sep; + size_t len=strlen(what); + const char *endofn = &ptr[ strlen(name) ]; + + /* skip trailing spaces in name */ + while(*endofn && ISBLANK(*endofn)) + endofn++; + + /* name ends with a '=' ? */ + sep = (*endofn == '=')?TRUE:FALSE; + + /* Strip off trailing whitespace from the 'what' */ + while(len && ISBLANK(what[len-1])) { + what[len-1]=0; + len--; + } - /* Skip leading whitespace from the 'what' */ - whatptr=what; - while(*whatptr && ISBLANK(*whatptr)) { - whatptr++; - } + /* Skip leading whitespace from the 'what' */ + whatptr=what; + while(*whatptr && ISBLANK(*whatptr)) + whatptr++; - if(Curl_raw_equal("path", name)) { - strstore(&co->path, whatptr); - if(!co->path) { - badcookie = TRUE; /* out of memory bad */ - break; + if(!len) { + /* this was a "<name>=" with no content, and we must allow + 'secure' and 'httponly' specified this weirdly */ + done = TRUE; + if(Curl_raw_equal("secure", name)) + co->secure = TRUE; + else if(Curl_raw_equal("httponly", name)) + co->httponly = TRUE; + else if(sep) + /* there was a '=' so we're not done parsing this field */ + done = FALSE; + } + if(done) + ; + else if(Curl_raw_equal("path", name)) { + strstore(&co->path, whatptr); + if(!co->path) { + badcookie = TRUE; /* out of memory bad */ + break; + } + } + else if(Curl_raw_equal("domain", name)) { + /* note that this name may or may not have a preceding dot, but + we don't care about that, we treat the names the same anyway */ + + const char *domptr=whatptr; + const char *nextptr; + int dotcount=1; + + /* Count the dots, we need to make sure that there are enough + of them. */ + + if('.' == whatptr[0]) + /* don't count the initial dot, assume it */ + domptr++; + + do { + nextptr = strchr(domptr, '.'); + if(nextptr) { + if(domptr != nextptr) + dotcount++; + domptr = nextptr+1; } + } while(nextptr); + + /* The original Netscape cookie spec defined that this domain name + MUST have three dots (or two if one of the seven holy TLDs), + but it seems that these kinds of cookies are in use "out there" + so we cannot be that strict. I've therefore lowered the check + to not allow less than two dots. */ + + if(dotcount < 2) { + /* Received and skipped a cookie with a domain using too few + dots. */ + badcookie=TRUE; /* mark this as a bad cookie */ + infof(data, "skipped cookie with illegal dotcount domain: %s\n", + whatptr); } - else if(Curl_raw_equal("domain", name)) { - /* note that this name may or may not have a preceding dot, but - we don't care about that, we treat the names the same anyway */ - - const char *domptr=whatptr; - const char *nextptr; - int dotcount=1; - - /* Count the dots, we need to make sure that there are enough - of them. */ + else { + /* 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('.' == whatptr[0]) - /* don't count the initial dot, assume it */ - domptr++; - - do { - nextptr = strchr(domptr, '.'); - if(nextptr) { - if(domptr != nextptr) - dotcount++; - domptr = nextptr+1; + whatptr++; /* ignore preceding dot */ + + if(!domain || tailmatch(whatptr, domain)) { + const char *tailptr=whatptr; + if(tailptr[0] == '.') + tailptr++; + strstore(&co->domain, tailptr); /* don't prefix w/dots + internally */ + if(!co->domain) { + badcookie = TRUE; + break; } - } while(nextptr); - - /* The original Netscape cookie spec defined that this domain name - MUST have three dots (or two if one of the seven holy TLDs), - but it seems that these kinds of cookies are in use "out there" - so we cannot be that strict. I've therefore lowered the check - to not allow less than two dots. */ - - if(dotcount < 2) { - /* Received and skipped a cookie with a domain using too few - dots. */ - badcookie=TRUE; /* mark this as a bad cookie */ - infof(data, "skipped cookie with illegal dotcount domain: %s\n", - whatptr); + co->tailmatch=TRUE; /* we always do that if the domain name was + given */ } else { - /* 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('.' == whatptr[0]) - whatptr++; /* ignore preceding dot */ - - if(!domain || tailmatch(whatptr, domain)) { - const char *tailptr=whatptr; - if(tailptr[0] == '.') - tailptr++; - strstore(&co->domain, tailptr); /* don't prefix w/dots - internally */ - if(!co->domain) { - badcookie = TRUE; - break; - } - 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\n", - whatptr); - } - } - } - else if(Curl_raw_equal("version", name)) { - strstore(&co->version, whatptr); - if(!co->version) { - badcookie = TRUE; - break; + /* 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\n", + whatptr); } } - else if(Curl_raw_equal("max-age", name)) { - /* 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. - - */ - strstore(&co->maxage, whatptr); - if(!co->maxage) { - badcookie = TRUE; - break; - } - co->expires = - strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) - + (long)now; + } + else if(Curl_raw_equal("version", name)) { + strstore(&co->version, whatptr); + if(!co->version) { + badcookie = TRUE; + break; } - else if(Curl_raw_equal("expires", name)) { - strstore(&co->expirestr, whatptr); - if(!co->expirestr) { - badcookie = TRUE; - break; - } - /* Note that if the date couldn't get parsed for whatever reason, - the cookie will be treated as a session cookie */ - co->expires = curl_getdate(what, &now); - - /* 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 if(Curl_raw_equal("max-age", name)) { + /* 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. + + */ + strstore(&co->maxage, whatptr); + if(!co->maxage) { + badcookie = TRUE; + break; } - else if(!co->name) { - co->name = strdup(name); - co->value = strdup(whatptr); - if(!co->name || !co->value) { - badcookie = TRUE; - break; - } + co->expires = + strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10) + + (long)now; + } + else if(Curl_raw_equal("expires", name)) { + strstore(&co->expirestr, whatptr); + if(!co->expirestr) { + badcookie = TRUE; + break; } - /* - else this is the second (or more) name we don't know - about! */ + /* Note that if the date couldn't get parsed for whatever reason, + the cookie will be treated as a session cookie */ + co->expires = curl_getdate(what, &now); + + /* 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 an "illegal" <what>=<this> pair */ + else if(!co->name) { + co->name = strdup(name); + co->value = strdup(whatptr); + if(!co->name || !co->value) { + badcookie = TRUE; + break; + } } + /* + else this is the second (or more) name we don't know + about! */ } else { - if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]", - what)) { - if(Curl_raw_equal("secure", what)) { - co->secure = TRUE; - } - else if(Curl_raw_equal("httponly", what)) { - co->httponly = TRUE; - } - /* else, - unsupported keyword without assign! */ - - } + /* this is an "illegal" <what>=<this> pair */ } + if(!semiptr || !*semiptr) { /* we already know there are no more cookies */ semiptr = NULL; @@ -530,7 +527,7 @@ Curl_cookie_add(struct SessionHandle *data, As far as I can see, it is set to true when the cookie says .domain.com and to false when the domain is complete www.domain.com */ - co->tailmatch=(bool)Curl_raw_equal(ptr, "TRUE"); + co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 2: /* It turns out, that sometimes the file format allows the path @@ -550,7 +547,7 @@ Curl_cookie_add(struct SessionHandle *data, fields++; /* add a field and fall down to secure */ /* FALLTHROUGH */ case 3: - co->secure = (bool)Curl_raw_equal(ptr, "TRUE"); + co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE; break; case 4: co->expires = curlx_strtoofft(ptr, NULL, 10); @@ -1110,23 +1107,20 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) c = data->cookies->cookies; - beg = list; while(c) { /* fill the list with _all_ the cookies we know */ line = get_netscape_format(c); - if(line == NULL) { - curl_slist_free_all(beg); + if(!line) { + curl_slist_free_all(list); return NULL; } - list = curl_slist_append(list, line); + beg = curl_slist_append(list, line); free(line); - if(list == NULL) { - curl_slist_free_all(beg); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; c = c->next; } @@ -1151,10 +1145,12 @@ void Curl_flush_cookies(struct SessionHandle *data, int cleanup) data->set.str[STRING_COOKIEJAR]); } else { - if(cleanup && data->change.cookielist) + if(cleanup && data->change.cookielist) { /* since nothing is written, we can just free the list of cookie file names */ curl_slist_free_all(data->change.cookielist); /* clean up list */ + data->change.cookielist = NULL; + } Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE); } diff --git a/lib/cookie.h b/lib/cookie.h index a950e359b..5997e4680 100644 --- a/lib/cookie.h +++ b/lib/cookie.h @@ -21,15 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include <stdio.h> -#if defined(WIN32) -#include <time.h> -#else -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif -#endif +#include "setup.h" #include <curl/curl.h> @@ -95,10 +87,10 @@ 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) do { } while (0) +#define Curl_cookie_loadfiles(x) Curl_nop_stmt #define Curl_cookie_init(x,y,z,w) NULL -#define Curl_cookie_cleanup(x) do { } while (0) -#define Curl_flush_cookies(x,y) +#define Curl_cookie_cleanup(x) Curl_nop_stmt +#define Curl_flush_cookies(x,y) Curl_nop_stmt #else void Curl_flush_cookies(struct SessionHandle *data, int cleanup); void Curl_cookie_cleanup(struct CookieInfo *); diff --git a/lib/curl_addrinfo.c b/lib/curl_addrinfo.c index 074bf17dc..bae403f95 100644 --- a/lib/curl_addrinfo.c +++ b/lib/curl_addrinfo.c @@ -40,7 +40,6 @@ #ifdef __VMS # include <in.h> # include <inet.h> -# include <stdlib.h> #endif #if defined(NETWARE) && defined(__NOVELL_LIBC__) diff --git a/lib/curl_base64.h b/lib/curl_base64.h index 2498a0a22..6e200d2ec 100644 --- a/lib/curl_base64.h +++ b/lib/curl_base64.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,10 +22,11 @@ * ***************************************************************************/ -size_t Curl_base64_encode(struct SessionHandle *data, - const char *inputbuff, size_t insize, - char **outptr); +CURLcode Curl_base64_encode(struct SessionHandle *data, + const char *inputbuff, size_t insize, + char **outptr, size_t *outlen); -size_t Curl_base64_decode(const char *src, unsigned char **outptr); +CURLcode Curl_base64_decode(const char *src, + unsigned char **outptr, size_t *outlen); #endif /* HEADER_CURL_BASE64_H */ diff --git a/lib/curl_gethostname.c b/lib/curl_gethostname.c index 7f0bfed54..aafa45b59 100644 --- a/lib/curl_gethostname.c +++ b/lib/curl_gethostname.c @@ -32,12 +32,16 @@ * 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. + * 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() @@ -58,6 +62,8 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { return -1; #else + int err; + char* dot; #ifdef DEBUGBUILD @@ -65,17 +71,34 @@ int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) { const char *force_hostname = getenv("CURL_GETHOSTNAME"); if(force_hostname) { strncpy(name, force_hostname, namelen); - name[namelen-1] = '\0'; - return 0; + err = 0; + } + else { + name[0] = '\0'; + err = gethostname(name, namelen); } -#endif /* DEBUGBUILD */ +#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. */ - return gethostname(name, namelen); + 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 index b8ecf88d6..48740f62a 100644 --- a/lib/curl_gethostname.h +++ b/lib/curl_gethostname.h @@ -22,6 +22,10 @@ * ***************************************************************************/ +/* Hostname buffer size */ +#define HOSTNAME_MAX 1024 + +/* This returns the local machine's un-qualified hostname */ int Curl_gethostname(char *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 000000000..b9c8ad0cf --- /dev/null +++ b/lib/curl_gssapi.c @@ -0,0 +1,69 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#ifdef HAVE_GSSAPI + +#include "curl_gssapi.h" +#include "sendf.h" + +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 * minor_status, + gss_ctx_id_t * context, + gss_name_t target_name, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags) +{ + OM_uint32 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_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\n"); +#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, + GSS_C_NO_OID, /* mech_type */ + req_flags, + 0, /* time_req */ + input_chan_bindings, + input_token, + NULL, /* actual_mech_type */ + output_token, + ret_flags, + NULL /* time_rec */); +} + +#endif /* HAVE_GSSAPI */ diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h new file mode 100644 index 000000000..fd4596b80 --- /dev/null +++ b/lib/curl_gssapi.h @@ -0,0 +1,57 @@ +#ifndef HEADER_CURL_GSSAPI_H +#define HEADER_CURL_GSSAPI_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" +#include "urldata.h" + +#ifdef HAVE_GSSAPI + +#ifdef HAVE_GSSGNU +# include <gss.h> +#elif defined HAVE_GSSMIT + /* MIT style */ +# include <gssapi/gssapi.h> +# include <gssapi/gssapi_generic.h> +# include <gssapi/gssapi_krb5.h> +#else + /* Heimdal-style */ +# include <gssapi.h> +#endif + + +/* Common method for using gss api */ + +OM_uint32 Curl_gss_init_sec_context( + struct SessionHandle *data, + OM_uint32 * minor_status, + gss_ctx_id_t * context, + gss_name_t target_name, + gss_channel_bindings_t input_chan_bindings, + gss_buffer_t input_token, + gss_buffer_t output_token, + OM_uint32 * ret_flags); + +#endif /* HAVE_GSSAPI */ + +#endif /* HEADER_CURL_GSSAPI_H */ diff --git a/lib/curl_ntlm.c b/lib/curl_ntlm.c new file mode 100644 index 000000000..c7d67a0de --- /dev/null +++ b/lib/curl_ntlm.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#ifdef USE_NTLM + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#include "urldata.h" +#include "sendf.h" +#include "rawstr.h" +#include "curl_ntlm.h" +#include "curl_ntlm_msgs.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "curl_memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +#if defined(USE_NSS) +#include "nssg.h" +#elif defined(USE_WINDOWS_SSPI) +#include "curl_sspi.h" +#endif + +/* The last #include file should be: */ +#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 connectdata *conn, + 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; + CURLcode result = CURLE_OK; + +#ifdef USE_NSS + result = Curl_nss_force_init(conn->data); + if(result) + return result; +#endif + + ntlm = proxy ? &conn->proxyntlm : &conn->ntlm; + + /* skip initial whitespaces */ + while(*header && ISSPACE(*header)) + header++; + + if(checkprefix("NTLM", header)) { + header += strlen("NTLM"); + + while(*header && ISSPACE(*header)) + header++; + + if(*header) { + result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm); + if(CURLE_OK != result) + return result; + + ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */ + } + else { + if(ntlm->state >= NTLMSTATE_TYPE1) { + infof(conn->data, "NTLM handshake failure (internal error)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */ + } + } + + return result; +} + +/* + * This is for creating ntlm header output + */ +CURLcode Curl_output_ntlm(struct connectdata *conn, + bool proxy) +{ + char *base64 = NULL; + size_t len = 0; + CURLcode error; + + /* point to the address of the pointer that holds the string to send to the + server, which is for a plain host or for a 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 ntlmdata *ntlm; + struct auth *authp; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + +#ifdef USE_NSS + if(CURLE_OK != Curl_nss_force_init(conn->data)) + return CURLE_OUT_OF_MEMORY; +#endif + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + passwdp = conn->proxypasswd; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + passwdp = conn->passwd; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp = ""; + + if(!passwdp) + passwdp = ""; + +#ifdef USE_WINDOWS_SSPI + if(s_hSecDll == NULL) { + /* not thread safe and leaks - use curl_global_init() to avoid */ + CURLcode err = Curl_sspi_global_init(); + if(s_hSecDll == NULL) + return err; + } +#endif + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: /* for the weird cases we (re)start here */ + /* Create a type-1 message */ + error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64, + &len); + + if(error) + return error; + + if(base64) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + free(base64); + } + break; + + case NTLMSTATE_TYPE2: + /* We already received the type-2 message, create a type-3 message */ + error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp, + ntlm, &base64, &len); + if(error) + return error; + + if(base64) { + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", + proxy ? "Proxy-" : "", + base64); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + free(base64); + + ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */ + authp->done = TRUE; + } + break; + + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + if(*allocuserpwd) { + free(*allocuserpwd); + *allocuserpwd = NULL; + } + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +void Curl_http_ntlm_cleanup(struct connectdata *conn) +{ +#ifdef USE_WINDOWS_SSPI + Curl_ntlm_sspi_cleanup(&conn->ntlm); + Curl_ntlm_sspi_cleanup(&conn->proxyntlm); +#elif defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#else + (void)conn; +#endif +} + +#endif /* USE_NTLM */ diff --git a/lib/curl_ntlm.h b/lib/curl_ntlm.h new file mode 100644 index 000000000..b2783778b --- /dev/null +++ b/lib/curl_ntlm.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_NTLM_H +#define HEADER_CURL_NTLM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#ifdef USE_NTLM + +/* this is for ntlm header input */ +CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy, + const char *header); + +/* this is for creating ntlm header output */ +CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); + +void Curl_http_ntlm_cleanup(struct connectdata *conn); + +#else + +#define Curl_http_ntlm_cleanup(a) Curl_nop_stmt + +#endif + +#endif /* HEADER_CURL_NTLM_H */ diff --git a/lib/curl_ntlm_core.c b/lib/curl_ntlm_core.c new file mode 100644 index 000000000..0be16b474 --- /dev/null +++ b/lib/curl_ntlm_core.c @@ -0,0 +1,379 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#ifdef USE_SSLEAY + +# ifdef USE_OPENSSL +# include <openssl/des.h> +# ifndef OPENSSL_NO_MD4 +# include <openssl/md4.h> +# endif +# include <openssl/md5.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> +# else +# include <des.h> +# ifndef OPENSSL_NO_MD4 +# include <md4.h> +# endif +# include <md5.h> +# include <ssl.h> +# include <rand.h> +# endif +# if (OPENSSL_VERSION_NUMBER < 0x00907001L) +# 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 +# else +# define DESKEYARG(x) *x +# define DESKEY(x) &x +# endif + +#elif defined(USE_GNUTLS) + +# include <gcrypt.h> +# define MD5_DIGEST_LENGTH 16 +# define MD4_DIGEST_LENGTH 16 + +#elif defined(USE_NSS) + +# include <nss.h> +# include <pk11pub.h> +# include <hasht.h> +# include "curl_md4.h" +# define MD5_DIGEST_LENGTH MD5_LENGTH + +#else +# error "Can't compile NTLM support without a crypto library." +#endif + +#include "urldata.h" +#include "non-ascii.h" +#include "rawstr.h" +#include "curl_memory.h" +#include "curl_ntlm_core.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +#ifdef USE_SSLEAY +/* + * 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; + + 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); + + DES_set_odd_parity(&key); + DES_set_key(&key, ks); +} + +#else /* defined(USE_SSLEAY) */ + +/* + * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. + */ +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); +} + +#if defined(USE_GNUTLS) + +/* + * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. + */ +static void setup_des_key(const unsigned char *key_56, + gcry_cipher_hd_t *des) +{ + char key[8]; + extend_key_56_to_64(key_56, key); + gcry_cipher_setkey(*des, key, 8); +} + +#elif defined(USE_NSS) + +/* + * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using + * the expanded key. The caller is responsible for giving 64 bit of valid + * data is IN and (at least) 64 bit large buffer as OUT. + */ +static bool encrypt_des(const unsigned char *in, unsigned char *out, + const unsigned char *key_56) +{ + const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ + PK11SlotInfo *slot = NULL; + char key[8]; /* expanded 64 bit key */ + SECItem key_item; + PK11SymKey *symkey = NULL; + SECItem *param = NULL; + PK11Context *ctx = NULL; + int out_len; /* not used, required by NSS */ + bool rv = FALSE; + + /* use internal slot for DES encryption (requires NSS to be initialized) */ + slot = PK11_GetInternalKeySlot(); + if(!slot) + return FALSE; + + /* expand the 56 bit key to 64 bit and wrap by NSS */ + extend_key_56_to_64(key_56, key); + key_item.data = (unsigned char *)key; + key_item.len = /* hard-wired */ 8; + symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, + &key_item, NULL); + if(!symkey) + goto fail; + + /* create DES encryption context */ + param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); + if(!param) + goto fail; + ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); + if(!ctx) + goto fail; + + /* perform the encryption */ + if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, + (unsigned char *)in, /* inbuflen */ 8) + && SECSuccess == PK11_Finalize(ctx)) + rv = /* all OK */ TRUE; + +fail: + /* cleanup */ + if(ctx) + PK11_DestroyContext(ctx, PR_TRUE); + if(symkey) + PK11_FreeSymKey(symkey); + if(param) + SECITEM_FreeItem(param, PR_TRUE); + PK11_FreeSlot(slot); + return rv; +} + +#endif /* defined(USE_NSS) */ + +#endif /* defined(USE_SSLEAY) */ + + /* + * 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) +{ +#ifdef USE_SSLEAY + 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) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys, &des); + gcry_cipher_encrypt(des, results, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 7, &des); + gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(keys + 14, &des); + gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) + encrypt_des(plaintext, results, keys); + encrypt_des(plaintext, results + 8, keys + 7); + encrypt_des(plaintext, results + 16, keys + 14); +#endif +} + +/* + * Set up lanmanager hashed password + */ +void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */) +{ + CURLcode res; + unsigned char pw[14]; + static const unsigned char magic[] = { + 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ + }; + size_t len = CURLMIN(strlen(password), 14); + + Curl_strntoupper((char *)pw, password, len); + memset(&pw[len], 0, 14 - len); + + /* + * The LanManager hashed password needs to be created using the + * password in the network encoding not the host encoding. + */ + res = Curl_convert_to_network(data, (char *)pw, 14); + if(res) + return; + + { + /* Create LanManager hashed password. */ + +#ifdef USE_SSLEAY + 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) + gcry_cipher_hd_t des; + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw, &des); + gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); + gcry_cipher_close(des); + + gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); + setup_des_key(pw + 7, &des); + gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8); + gcry_cipher_close(des); +#elif defined(USE_NSS) + encrypt_des(magic, lmbuffer, pw); + encrypt_des(magic, lmbuffer + 8, pw + 7); +#endif + + memset(lmbuffer + 16, 0, 21 - 16); + } +} + +#if USE_NTRESPONSES +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'; + } +} + +/* + * Set up nt hashed passwords + */ +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */) +{ + size_t len = strlen(password); + unsigned char *pw = malloc(len * 2); + CURLcode result; + if(!pw) + return CURLE_OUT_OF_MEMORY; + + ascii_to_unicode_le(pw, password, len); + + /* + * The NT hashed password needs to be created using the password in the + * network encoding not the host encoding. + */ + result = Curl_convert_to_network(data, (char *)pw, len * 2); + if(result) + return result; + + { + /* Create NT hashed password. */ +#ifdef USE_SSLEAY + MD4_CTX MD4pw; + MD4_Init(&MD4pw); + MD4_Update(&MD4pw, pw, 2 * len); + MD4_Final(ntbuffer, &MD4pw); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD4pw; + gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); + gcry_md_write(MD4pw, pw, 2 * len); + memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); + gcry_md_close(MD4pw); +#elif defined(USE_NSS) + Curl_md4it(ntbuffer, pw, 2 * len); +#endif + + memset(ntbuffer + 16, 0, 21 - 16); + } + + free(pw); + + return CURLE_OK; +} +#endif /* USE_NTRESPONSES */ + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ diff --git a/lib/curl_ntlm_core.h b/lib/curl_ntlm_core.h new file mode 100644 index 000000000..5615b3504 --- /dev/null +++ b/lib/curl_ntlm_core.h @@ -0,0 +1,68 @@ +#ifndef HEADER_CURL_NTLM_CORE_H +#define HEADER_CURL_NTLM_CORE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI) + +#ifdef USE_SSLEAY +# if !defined(OPENSSL_VERSION_NUMBER) && \ + !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H) +# error "curl_ntlm_core.h shall not be included before OpenSSL headers." +# endif +# ifdef OPENSSL_NO_MD4 +# define USE_NTRESPONSES 0 +# define USE_NTLM2SESSION 0 +# endif +#endif + +/* + * Define USE_NTRESPONSES to 1 in order to make the type-3 message include + * the NT response message. Define USE_NTLM2SESSION to 1 in order to make + * the type-3 message include the NTLM2Session response message, requires + * USE_NTRESPONSES defined to 1. + */ + +#ifndef USE_NTRESPONSES +# define USE_NTRESPONSES 1 +# define USE_NTLM2SESSION 1 +#endif + +void Curl_ntlm_core_lm_resp(const unsigned char *keys, + const unsigned char *plaintext, + unsigned char *results); + +void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data, + const char *password, + unsigned char *lmbuffer /* 21 bytes */); + +#if USE_NTRESPONSES +CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data, + const char *password, + unsigned char *ntbuffer /* 21 bytes */); +#endif + +#endif /* USE_NTLM && !USE_WINDOWS_SSPI */ + +#endif /* HEADER_CURL_NTLM_CORE_H */ diff --git a/lib/curl_ntlm_msgs.c b/lib/curl_ntlm_msgs.c new file mode 100644 index 000000000..bfd3e2814 --- /dev/null +++ b/lib/curl_ntlm_msgs.c @@ -0,0 +1,958 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#ifdef USE_NTLM + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef USE_SSLEAY + +# ifdef USE_OPENSSL +# include <openssl/des.h> +# ifndef OPENSSL_NO_MD4 +# include <openssl/md4.h> +# endif +# include <openssl/md5.h> +# include <openssl/ssl.h> +# include <openssl/rand.h> +# else +# include <des.h> +# ifndef OPENSSL_NO_MD4 +# include <md4.h> +# endif +# include <md5.h> +# include <ssl.h> +# include <rand.h> +# endif +# include "ssluse.h" + +#elif defined(USE_GNUTLS) + +# include <gcrypt.h> +# include "gtls.h" +# define MD5_DIGEST_LENGTH 16 +# define MD4_DIGEST_LENGTH 16 + +#elif defined(USE_NSS) + +# include <nss.h> +# include <pk11pub.h> +# include <hasht.h> +# include "nssg.h" +# include "curl_md4.h" +# define MD5_DIGEST_LENGTH MD5_LENGTH + +#elif defined(USE_WINDOWS_SSPI) +# include "curl_sspi.h" +#else +# error "Can't compile NTLM support without a crypto library." +#endif + +#include "urldata.h" +#include "non-ascii.h" +#include "sendf.h" +#include "curl_base64.h" +#include "curl_ntlm_core.h" +#include "curl_gethostname.h" +#include "curl_memory.h" + +#define BUILDING_CURL_NTLM_MSGS_C +#include "curl_ntlm_msgs.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#include "memdebug.h" + +/* "NTLMSSP" signature is always in ASCII regardless of the platform */ +#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" + +#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) +#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \ + (((x) >> 16) & 0xff), (((x) >> 24) & 0xff) + +#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_NETWARE) + fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); + 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 + +#ifndef USE_WINDOWS_SSPI +/* + * This function converts from the little endian format used in the + * incoming package to whatever endian format we're using natively. + * Argument is a pointer to a 4 byte buffer. + */ +static unsigned int readint_le(unsigned char *buf) +{ + return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | + ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); +} +#endif + +/* + 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_ntlm_decode_type2_message() + * + * This is used to decode a ntlm type-2 message received from a: HTTP, SMTP + * or POP3 server. The message is first decoded from a base64 string into a + * raw ntlm message and checked for validity before the appropriate data for + * creating a type-3 message is written to the given ntlm data structure. + * + * Parameters: + * + * data [in] - Pointer to session handle. + * header [in] - Pointer to the input buffer. + * ntlm [in] - Pointer to ntlm data struct being used and modified. + * + * Returns CURLE_OK on success. + */ +CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, + const char* header, + struct ntlmdata* ntlm) +{ +#ifndef USE_WINDOWS_SSPI + static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; +#endif + + /* 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 + */ + + size_t size = 0; + unsigned char *buffer = NULL; + CURLcode error; + +#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI) + (void)data; +#endif + + error = Curl_base64_decode(header, &buffer, &size); + if(error) + return error; + + if(!buffer) { + infof(data, "NTLM handshake failure (unhandled condition)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + +#ifdef USE_WINDOWS_SSPI + ntlm->type_2 = malloc(size + 1); + if(ntlm->type_2 == NULL) { + free(buffer); + return CURLE_OUT_OF_MEMORY; + } + ntlm->n_type_2 = (unsigned long)size; + memcpy(ntlm->type_2, buffer, size); +#else + ntlm->flags = 0; + + if((size < 32) || + (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || + (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) { + /* This was not a good enough type-2 message */ + free(buffer); + infof(data, "NTLM handshake failure (bad type-2 message)\n"); + return CURLE_REMOTE_ACCESS_DENIED; + } + + ntlm->flags = readint_le(&buffer[20]); + memcpy(ntlm->nonce, &buffer[24], 8); + + 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); + }); +#endif + free(buffer); + + return CURLE_OK; +} + +#ifdef USE_WINDOWS_SSPI +void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm) +{ + if(ntlm->type_2) { + free(ntlm->type_2); + ntlm->type_2 = NULL; + } + if(ntlm->has_handles) { + s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + ntlm->has_handles = 0; + } + if(ntlm->p_identity) { + if(ntlm->identity.User) free(ntlm->identity.User); + if(ntlm->identity.Password) free(ntlm->identity.Password); + if(ntlm->identity.Domain) free(ntlm->identity.Domain); + ntlm->p_identity = NULL; + } +} +#endif + +#ifndef USE_WINDOWS_SSPI +/* 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'; + } +} +#endif + +/* + * Curl_ntlm_create_type1_message() + * + * This is used to generate an already encoded NTLM type-1 message ready + * for sending to the recipient, be it a: HTTP, SMTP or POP3 server, + * using the appropriate compile time crypo API. + * + * Parameters: + * + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The ntlm data struct being used and modified. + * outptr [in/out] - The adress 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_ntlm_create_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen) +{ + /* 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 + */ + + unsigned char ntlmbuf[NTLM_BUFSIZE]; + size_t size; + +#ifdef USE_WINDOWS_SSPI + + SecBuffer buf; + SecBufferDesc desc; + SECURITY_STATUS status; + ULONG attrs; + const char *dest = ""; + const char *user; + const char *domain = ""; + size_t userlen = 0; + size_t domlen = 0; + size_t passwdlen = 0; + TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + + Curl_ntlm_sspi_cleanup(ntlm); + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = user - userp; + user++; + } + else { + user = userp; + domain = ""; + domlen = 0; + } + + if(user) + userlen = strlen(user); + + if(passwdp) + passwdlen = strlen(passwdp); + + if(userlen > 0) { + /* note: initialize all of this before doing the mallocs so that + * it can be cleaned up later without leaking memory. + */ + ntlm->p_identity = &ntlm->identity; + memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); + if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) + return CURLE_OUT_OF_MEMORY; + + ntlm->identity.UserLength = (unsigned long)userlen; + if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) + return CURLE_OUT_OF_MEMORY; + + ntlm->identity.PasswordLength = (unsigned long)strlen(passwdp); + if((ntlm->identity.Domain = malloc(domlen + 1)) == NULL) + return CURLE_OUT_OF_MEMORY; + + strncpy((char *)ntlm->identity.Domain, domain, domlen); + ntlm->identity.Domain[domlen] = '\0'; + ntlm->identity.DomainLength = (unsigned long)domlen; + ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; + } + else + ntlm->p_identity = NULL; + + status = s_pSecFn->AcquireCredentialsHandleA(NULL, (void *)"NTLM", + SECPKG_CRED_OUTBOUND, NULL, + ntlm->p_identity, NULL, NULL, + &ntlm->handle, &tsDummy); + if(status != SEC_E_OK) + return CURLE_OUT_OF_MEMORY; + + desc.ulVersion = SECBUFFER_VERSION; + desc.cBuffers = 1; + desc.pBuffers = &buf; + buf.cbBuffer = NTLM_BUFSIZE; + buf.BufferType = SECBUFFER_TOKEN; + buf.pvBuffer = ntlmbuf; + + status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL, + (void *)dest, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, + NULL, 0, + &ntlm->c_handle, &desc, + &attrs, &tsDummy); + + if(status == SEC_I_COMPLETE_AND_CONTINUE || + status == SEC_I_CONTINUE_NEEDED) + s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); + else if(status != SEC_E_OK) { + s_pSecFn->FreeCredentialsHandle(&ntlm->handle); + return CURLE_RECV_ERROR; + } + + ntlm->has_handles = 1; + size = buf.cbBuffer; + +#else + + 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)userp; + (void)passwdp; + (void)ntlm; + +#if USE_NTLM2SESSION +#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY +#else +#define NTLM2FLAG 0 +#endif + snprintf((char *)ntlmbuf, NTLM_BUFSIZE, + 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 | + NTLM2FLAG | + 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 */); + + /* Initial packet length */ + size = 32 + hostlen + domlen; + +#endif + + 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 | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + ntlm_print_flags(stderr, + NTLMFLAG_NEGOTIATE_OEM | + NTLMFLAG_REQUEST_TARGET | + NTLMFLAG_NEGOTIATE_NTLM_KEY | + NTLM2FLAG | + NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); + fprintf(stderr, "\n****\n"); + }); + + /* Return with binary blob encoded into base64 */ + return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); +} + +/* + * Curl_ntlm_create_type3_message() + * + * This is used to generate an already encoded NTLM type-3 message ready + * for sending to the recipient, be it a: HTTP, SMTP or POP3 server, + * using the appropriate compile time crypo API. + * + * Parameters: + * + * data [in] - The session handle. + * userp [in] - The user name in the format User or Domain\User. + * passdwp [in] - The user's password. + * ntlm [in/out] - The ntlm data struct being used and modified. + * outptr [in/out] - The adress 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_ntlm_create_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen) +{ + /* 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 + */ + + unsigned char ntlmbuf[NTLM_BUFSIZE]; + size_t size; + +#ifdef USE_WINDOWS_SSPI + const char *dest = ""; + SecBuffer type_2; + SecBuffer type_3; + SecBufferDesc type_2_desc; + SecBufferDesc type_3_desc; + SECURITY_STATUS status; + ULONG attrs; + TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */ + + (void)passwdp; + (void)userp; + (void)data; + + type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; + type_2_desc.cBuffers = type_3_desc.cBuffers = 1; + type_2_desc.pBuffers = &type_2; + type_3_desc.pBuffers = &type_3; + + type_2.BufferType = SECBUFFER_TOKEN; + type_2.pvBuffer = ntlm->type_2; + type_2.cbBuffer = ntlm->n_type_2; + type_3.BufferType = SECBUFFER_TOKEN; + type_3.pvBuffer = ntlmbuf; + type_3.cbBuffer = NTLM_BUFSIZE; + + status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, + &ntlm->c_handle, + (void *)dest, + ISC_REQ_CONFIDENTIALITY | + ISC_REQ_REPLAY_DETECT | + ISC_REQ_CONNECTION, + 0, SECURITY_NETWORK_DREP, + &type_2_desc, + 0, &ntlm->c_handle, + &type_3_desc, + &attrs, &tsDummy); + if(status != SEC_E_OK) + return CURLE_RECV_ERROR; + + size = type_3.cbBuffer; + + Curl_ntlm_sspi_cleanup(ntlm); + +#else + int lmrespoff; + unsigned char lmresp[24]; /* fixed-size */ +#if USE_NTRESPONSES + int ntrespoff; + unsigned char ntresp[24]; /* fixed-size */ +#endif + 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; + CURLcode res; + + user = strchr(userp, '\\'); + if(!user) + user = strchr(userp, '/'); + + if(user) { + domain = userp; + domlen = (user - domain); + user++; + } + else + user = userp; + + if(user) + userlen = strlen(user); + + /* 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); + } + + if(unicode) { + domlen = domlen * 2; + userlen = userlen * 2; + hostlen = hostlen * 2; + } + +#if USE_NTLM2SESSION + /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ + if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { + unsigned char ntbuffer[0x18]; + unsigned char tmp[0x18]; + unsigned char md5sum[MD5_DIGEST_LENGTH]; + unsigned char entropy[8]; + + /* Need to create 8 bytes random data */ +#ifdef USE_SSLEAY + MD5_CTX MD5pw; + Curl_ossl_seed(data); /* Initiate the seed if not already done */ + RAND_bytes(entropy, 8); +#elif defined(USE_GNUTLS) + gcry_md_hd_t MD5pw; + Curl_gtls_seed(data); /* Initiate the seed if not already done */ + gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); +#elif defined(USE_NSS) + PK11Context *MD5pw; + unsigned int MD5len; + Curl_nss_seed(data); /* Initiate the seed if not already done */ + PK11_GenerateRandom(entropy, 8); +#endif + + /* 8 bytes random data as challenge in lmresp */ + memcpy(lmresp, entropy, 8); + + /* Pad with zeros */ + memset(lmresp + 8, 0, 0x10); + + /* Fill tmp with challenge(nonce?) + entropy */ + memcpy(tmp, &ntlm->nonce[0], 8); + memcpy(tmp + 8, entropy, 8); + +#ifdef USE_SSLEAY + MD5_Init(&MD5pw); + MD5_Update(&MD5pw, tmp, 16); + MD5_Final(md5sum, &MD5pw); +#elif defined(USE_GNUTLS) + gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); + gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH); + memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH); + gcry_md_close(MD5pw); +#elif defined(USE_NSS) + MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); + PK11_DigestOp(MD5pw, tmp, 16); + PK11_DigestFinal(MD5pw, md5sum, &MD5len, MD5_DIGEST_LENGTH); + PK11_DestroyContext(MD5pw, PR_TRUE); +#endif + + /* We shall only use the first 8 bytes of md5sum, but the des + code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */ + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) + return CURLE_OUT_OF_MEMORY; + Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp); + + /* End of NTLM2 Session code */ + } + else +#endif + { + +#if USE_NTRESPONSES + unsigned char ntbuffer[0x18]; +#endif + unsigned char lmbuffer[0x18]; + +#if USE_NTRESPONSES + if(CURLE_OUT_OF_MEMORY == + Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer)) + return CURLE_OUT_OF_MEMORY; + Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); +#endif + + Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer); + Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); + /* A safer but less compatible alternative is: + * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); + * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ + } + + lmrespoff = 64; /* size of the message header */ +#if USE_NTRESPONSES + ntrespoff = lmrespoff + 0x18; + domoff = ntrespoff + 0x18; +#else + domoff = lmrespoff + 0x18; +#endif + useroff = domoff + domlen; + hostoff = useroff + userlen; + + /* Create the big type-3 message binary blob */ + size = snprintf((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, /* zero termination */ + 0, 0, 0, /* type-3 long, the 24 upper bits */ + + SHORTPAIR(0x18), /* LanManager response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(lmrespoff), + 0x0, 0x0, + +#if USE_NTRESPONSES + SHORTPAIR(0x18), /* NT-response length, twice */ + SHORTPAIR(0x18), + SHORTPAIR(ntrespoff), + 0x0, 0x0, +#else + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, + 0x0, 0x0, +#endif + 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); + }); + +#if USE_NTRESPONSES + if(size < (NTLM_BUFSIZE - 0x18)) { + DEBUGASSERT(size == (size_t)ntrespoff); + memcpy(&ntlmbuf[size], ntresp, 0x18); + size += 0x18; + } + + DEBUG_OUT({ + fprintf(stderr, "\n ntresp="); + ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); + }); + +#endif + + 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; + + /* Convert domain, user, and host to ASCII but leave the rest as-is */ + res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff], + size - domoff); + if(res) + return CURLE_CONV_FAILED; + +#endif + + /* Return with binary blob encoded into base64 */ + return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen); +} + +#endif /* USE_NTLM */ diff --git a/lib/http_ntlm.h b/lib/curl_ntlm_msgs.h index c7422d701..7acf7229f 100644 --- a/lib/http_ntlm.h +++ b/lib/curl_ntlm_msgs.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_NTLM_H -#define __HTTP_NTLM_H +#ifndef HEADER_CURL_NTLM_MSGS_H +#define HEADER_CURL_NTLM_MSGS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,26 +22,42 @@ * ***************************************************************************/ -typedef enum { - CURLNTLM_NONE, /* not a ntlm */ - CURLNTLM_BAD, /* an ntlm, but one we don't like */ - CURLNTLM_FIRST, /* the first 401-reply we got with NTLM */ - CURLNTLM_FINE, /* an ntlm we act on */ - - CURLNTLM_LAST /* last entry in this enum, don't use */ -} CURLntlm; - -/* this is for ntlm header input */ -CURLntlm Curl_input_ntlm(struct connectdata *conn, bool proxy, - const char *header); +#include "setup.h" + +#ifdef USE_NTLM + +/* This is to generate a base64 encoded NTLM type-1 message */ +CURLcode Curl_ntlm_create_type1_message(const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is to generate a base64 encoded NTLM type-3 message */ +CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data, + const char *userp, + const char *passwdp, + struct ntlmdata *ntlm, + char **outptr, + size_t *outlen); + +/* This is to decode a NTLM type-2 message */ +CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data, + const char* header, + struct ntlmdata* ntlm); + +/* This is to clean up the ntlm data structure */ +#ifdef USE_WINDOWS_SSPI +void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm); +#else +#define Curl_ntlm_sspi_cleanup(x) +#endif -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy); +/* NTLM buffer fixed size, large enough for long user + host + domain */ +#define NTLM_BUFSIZE 1024 -void Curl_ntlm_cleanup(struct connectdata *conn); -#ifndef USE_NTLM -#define Curl_ntlm_cleanup(x) -#endif +/* Stuff only required for curl_ntlm_msgs.c */ +#ifdef BUILDING_CURL_NTLM_MSGS_C /* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */ @@ -146,4 +162,9 @@ void Curl_ntlm_cleanup(struct connectdata *conn); #define NTLMFLAG_NEGOTIATE_56 (1<<31) /* Indicates that 56-bit encryption is supported. */ -#endif + +#endif /* BUILDING_CURL_NTLM_MSGS_C */ + +#endif /* USE_NTLM */ + +#endif /* HEADER_CURL_NTLM_MSGS_H */ diff --git a/lib/curl_ntlm_wb.c b/lib/curl_ntlm_wb.c new file mode 100644 index 000000000..18d0d13f8 --- /dev/null +++ b/lib/curl_ntlm_wb.c @@ -0,0 +1,394 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + +/* + * NTLM details: + * + * http://davenport.sourceforge.net/ntlm.html + * http://www.innovation.ch/java/ntlm.html + */ + +#define DEBUG_ME 0 + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif +#ifdef HAVE_SYS_WAIT_H +#include <sys/wait.h> +#endif +#ifdef HAVE_SIGNAL_H +#include <signal.h> +#endif + +#include "urldata.h" +#include "sendf.h" +#include "select.h" +#include "curl_ntlm_wb.h" +#include "url.h" +#include "strerror.h" +#include "curl_memory.h" + +#define _MPRINTF_REPLACE /* use our functions only */ +#include <curl/mprintf.h> + +/* The last #include file should be: */ +#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 */ +#if 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 + +void Curl_ntlm_wb_cleanup(struct connectdata *conn) +{ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) { + sclose(conn->ntlm_auth_hlpr_socket); + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + } + + if(conn->ntlm_auth_hlpr_pid) { + int i; + for(i = 0; i < 4; i++) { + pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG); + if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD) + break; + switch(i) { + case 0: + kill(conn->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(conn->ntlm_auth_hlpr_pid, SIGKILL); + break; + case 3: + break; + } + } + conn->ntlm_auth_hlpr_pid = 0; + } + + Curl_safefree(conn->challenge_header); + conn->challenge_header = NULL; + Curl_safefree(conn->response_header); + conn->response_header = NULL; +} + +static CURLcode ntlm_wb_init(struct connectdata *conn, 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; + int error; + + /* Return if communication with ntlm_auth already set up */ + if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD || + conn->ntlm_auth_hlpr_pid) + return CURLE_OK; + + username = userp; + slash = strpbrk(username, "\\/"); + if(slash) { + if((domain = strdup(username)) == NULL) + 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) { + error = ERRNO; + failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s", + ntlm_auth, error, Curl_strerror(conn, error)); + goto done; + } + + if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) { + error = ERRNO; + failf(conn->data, "Could not open socket pair. errno %d: %s", + error, Curl_strerror(conn, error)); + goto done; + } + + child_pid = fork(); + if(child_pid == -1) { + error = ERRNO; + sclose(sockfds[0]); + sclose(sockfds[1]); + failf(conn->data, "Could not fork. errno %d: %s", + error, Curl_strerror(conn, error)); + 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) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdin. errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + if(dup2(sockfds[1], STDOUT_FILENO) == -1) { + error = ERRNO; + failf(conn->data, "Could not redirect child stdout. errno %d: %s", + error, Curl_strerror(conn, error)); + 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); + + error = ERRNO; + sclose_nolog(sockfds[1]); + failf(conn->data, "Could not execl(). errno %d: %s", + error, Curl_strerror(conn, error)); + exit(1); + } + + sclose(sockfds[1]); + conn->ntlm_auth_hlpr_socket = sockfds[0]; + conn->ntlm_auth_hlpr_pid = child_pid; + Curl_safefree(domain); + Curl_safefree(ntlm_auth_alloc); + return CURLE_OK; + +done: + Curl_safefree(domain); + Curl_safefree(ntlm_auth_alloc); + return CURLE_REMOTE_ACCESS_DENIED; +} + +static CURLcode ntlm_wb_response(struct connectdata *conn, + const char *input, curlntlm state) +{ + ssize_t size; + char buf[200]; /* enough, type 1, 3 message length is less then 200 */ + char *tmpbuf = buf; + size_t len_in = strlen(input), len_out = sizeof(buf); + + while(len_in > 0) { + ssize_t written = swrite(conn->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(len_out > 0) { + size = sread(conn->ntlm_auth_hlpr_socket, tmpbuf, len_out); + if(size == -1) { + if(errno == EINTR) + continue; + goto done; + } + else if(size == 0) + goto done; + else if(tmpbuf[size - 1] == '\n') { + tmpbuf[size - 1] = '\0'; + goto wrfinish; + } + tmpbuf += size; + len_out -= size; + } + goto done; +wrfinish: + /* Samba/winbind installed but not configured */ + if(state == NTLMSTATE_TYPE1 && + size == 3 && + buf[0] == 'P' && buf[1] == 'W') + return CURLE_REMOTE_ACCESS_DENIED; + /* invalid response */ + if(size < 4) + goto done; + if(state == NTLMSTATE_TYPE1 && + (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' ')) + goto done; + if(state == NTLMSTATE_TYPE2 && + (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') && + (buf[0]!='A' || buf[1]!='F' || buf[2]!=' ')) + goto done; + + conn->response_header = aprintf("NTLM %.*s", size - 4, buf + 3); + return CURLE_OK; +done: + return CURLE_REMOTE_ACCESS_DENIED; +} + +/* + * 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 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 a HTTP proxy */ + char **allocuserpwd; + /* point to the name and password for this */ + const char *userp; + /* point to the correct struct with this */ + struct ntlmdata *ntlm; + struct auth *authp; + + CURLcode res = CURLE_OK; + char *input; + + DEBUGASSERT(conn); + DEBUGASSERT(conn->data); + + if(proxy) { + allocuserpwd = &conn->allocptr.proxyuserpwd; + userp = conn->proxyuser; + ntlm = &conn->proxyntlm; + authp = &conn->data->state.authproxy; + } + else { + allocuserpwd = &conn->allocptr.userpwd; + userp = conn->user; + ntlm = &conn->ntlm; + authp = &conn->data->state.authhost; + } + authp->done = FALSE; + + /* not set means empty */ + if(!userp) + userp=""; + + switch(ntlm->state) { + case NTLMSTATE_TYPE1: + default: + /* Use Samba's 'winbind' daemon to support NTLM authentication, + * by delegating the NTLM challenge/response protocal to a helper + * in ntlm_auth. + * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html + * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html + * http://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(conn, userp); + if(res) + return res; + res = ntlm_wb_response(conn, "YR\n", ntlm->state); + if(res) + return res; + + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); + Curl_safefree(conn->response_header); + conn->response_header = NULL; + break; + case NTLMSTATE_TYPE2: + input = aprintf("TT %s", conn->challenge_header); + if(!input) + return CURLE_OUT_OF_MEMORY; + res = ntlm_wb_response(conn, input, ntlm->state); + free(input); + input = NULL; + if(res) + return res; + + Curl_safefree(*allocuserpwd); + *allocuserpwd = aprintf("%sAuthorization: %s\r\n", + proxy ? "Proxy-" : "", + conn->response_header); + DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); + ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ + authp->done = TRUE; + Curl_ntlm_wb_cleanup(conn); + break; + case NTLMSTATE_TYPE3: + /* connection is already authenticated, + * don't send a header in future requests */ + if(*allocuserpwd) { + free(*allocuserpwd); + *allocuserpwd=NULL; + } + authp->done = TRUE; + break; + } + + return CURLE_OK; +} + +#endif /* USE_NTLM && NTLM_WB_ENABLED */ diff --git a/lib/curl_ntlm_wb.h b/lib/curl_ntlm_wb.h new file mode 100644 index 000000000..e3eaffe17 --- /dev/null +++ b/lib/curl_ntlm_wb.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_NTLM_WB_H +#define HEADER_CURL_NTLM_WB_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +#include "setup.h" + +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + +/* 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 connectdata *conn, bool proxy); + +void Curl_ntlm_wb_cleanup(struct connectdata *conn); + +#endif /* USE_NTLM && NTLM_WB_ENABLED */ + +#endif /* HEADER_CURL_NTLM_WB_H */ diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c index 44b7e1524..725b8f995 100644 --- a/lib/curl_rtmp.c +++ b/lib/curl_rtmp.c @@ -71,6 +71,7 @@ const struct Curl_handler Curl_handler_rtmp = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -90,6 +91,7 @@ const struct Curl_handler Curl_handler_rtmpt = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -109,6 +111,7 @@ const struct Curl_handler Curl_handler_rtmpe = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -128,6 +131,7 @@ const struct Curl_handler Curl_handler_rtmpte = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -147,6 +151,7 @@ const struct Curl_handler Curl_handler_rtmps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -166,6 +171,7 @@ const struct Curl_handler Curl_handler_rtmpts = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ rtmp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/curl_threads.c b/lib/curl_threads.c index e9636440f..411ccc81d 100644 --- a/lib/curl_threads.c +++ b/lib/curl_threads.c @@ -19,6 +19,7 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #if defined(USE_THREADS_POSIX) diff --git a/lib/cyassl.c b/lib/cyassl.c index 81bcabaa1..cda18a8cb 100644 --- a/lib/cyassl.c +++ b/lib/cyassl.c @@ -27,16 +27,17 @@ */ #include "setup.h" + #ifdef USE_CYASSL -#include <string.h> -#include <stdlib.h> -#include <ctype.h> +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif - #include "urldata.h" #include "sendf.h" #include "inet_pton.h" @@ -412,7 +413,7 @@ int Curl_cyassl_init(void) bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex) { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; else return FALSE; } diff --git a/lib/cyassl.h b/lib/cyassl.h index a21592a28..56d68066f 100644 --- a/lib/cyassl.h +++ b/lib/cyassl.h @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #ifdef USE_CYASSL @@ -45,7 +46,7 @@ CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn, /* API setup for CyaSSL */ #define curlssl_init Curl_cyassl_init -#define curlssl_cleanup() +#define curlssl_cleanup() Curl_nop_stmt #define curlssl_connect Curl_cyassl_connect #define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking #define curlssl_session_free(x) Curl_cyassl_session_free(x) diff --git a/lib/dict.c b/lib/dict.c index 0baaeec3a..b326054d1 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -24,28 +24,18 @@ #ifndef CURL_DISABLE_DICT -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -64,9 +54,6 @@ #include <sys/select.h> #endif - -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -105,6 +92,7 @@ const struct Curl_handler Curl_handler_dict = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/easy.c b/lib/easy.c index ac037d266..60a55edf8 100644 --- a/lib/easy.c +++ b/lib/easy.c @@ -22,29 +22,12 @@ #include "setup.h" -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -#include "strequal.h" - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -65,8 +48,7 @@ #include <sys/param.h> #endif -#endif /* WIN32 ... */ - +#include "strequal.h" #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -81,7 +63,7 @@ #include "easyif.h" #include "select.h" #include "sendf.h" /* for failf function prototype */ -#include "http_ntlm.h" +#include "curl_ntlm.h" #include "connect.h" /* for Curl_getconnectinfo */ #include "slist.h" #include "curl_rand.h" @@ -143,6 +125,8 @@ static CURLcode win32_init(void) return CURLE_FAILED_INIT; } /* The Windows Sockets DLL is acceptable. Proceed. */ +#elif defined(USE_LWIPSOCK) + lwip_init(); #endif #ifdef USE_WINDOWS_SSPI @@ -692,16 +676,15 @@ CURL *curl_easy_duphandle(CURL *incurl) if(outcurl) { if(outcurl->state.connc && - (outcurl->state.connc->type == CONNCACHE_PRIVATE)) + (outcurl->state.connc->type == CONNCACHE_PRIVATE)) { Curl_rm_connc(outcurl->state.connc); - if(outcurl->state.headerbuff) - free(outcurl->state.headerbuff); - if(outcurl->change.cookielist) - curl_slist_free_all(outcurl->change.cookielist); - if(outcurl->change.url) - free(outcurl->change.url); - if(outcurl->change.referer) - free(outcurl->change.referer); + outcurl->state.connc = NULL; + } + curl_slist_free_all(outcurl->change.cookielist); + outcurl->change.cookielist = NULL; + Curl_safefree(outcurl->state.headerbuff); + Curl_safefree(outcurl->change.url); + Curl_safefree(outcurl->change.referer); Curl_freeset(outcurl); free(outcurl); } @@ -718,10 +701,10 @@ void curl_easy_reset(CURL *curl) struct SessionHandle *data = (struct SessionHandle *)curl; Curl_safefree(data->state.pathbuffer); - data->state.pathbuffer=NULL; + + data->state.path = NULL; Curl_safefree(data->state.proto.generic); - data->state.proto.generic=NULL; /* zero out UserDefined data: */ Curl_freeset(data); diff --git a/lib/escape.c b/lib/escape.c index 5500a92bf..b0922bc93 100644 --- a/lib/escape.c +++ b/lib/escape.c @@ -24,12 +24,9 @@ * allocated string or NULL if an error occurred. */ #include "setup.h" -#include <ctype.h> + #include <curl/curl.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> #include "curl_memory.h" #include "urldata.h" #include "warnless.h" diff --git a/lib/file.c b/lib/file.c index 4f3ea1bb4..00d5fc09b 100644 --- a/lib/file.c +++ b/lib/file.c @@ -23,27 +23,13 @@ #include "setup.h" #ifndef CURL_DISABLE_FILE -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#include <fcntl.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -68,8 +54,6 @@ #include <fcntl.h> #endif -#endif /* WIN32 */ - #include "strtoofft.h" #include "urldata.h" #include <curl/curl.h> @@ -83,6 +67,7 @@ #include "url.h" #include "curl_memory.h" #include "parsedate.h" /* for the week day and month names */ +#include "warnless.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -109,6 +94,9 @@ static CURLcode file_do(struct connectdata *, bool *done); static CURLcode file_done(struct connectdata *conn, CURLcode status, bool premature); static CURLcode file_connect(struct connectdata *conn, bool *done); +static CURLcode file_disconnect(struct connectdata *conn, + bool dead_connection); + /* * FILE scheme handler. @@ -125,8 +113,9 @@ const struct Curl_handler Curl_handler_file = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ - ZERO_NULL, /* disconnect */ + file_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ 0, /* defport */ CURLPROTO_FILE, /* protocol */ @@ -222,10 +211,9 @@ static CURLcode file_connect(struct connectdata *conn, bool *done) /* file is not a protocol that can deal with "persistancy" */ file = data->state.proto.file; Curl_safefree(file->freepath); + file->path = NULL; if(file->fd != -1) close(file->fd); - file->path = NULL; - file->freepath = NULL; file->fd = -1; } @@ -282,10 +270,31 @@ static CURLcode file_done(struct connectdata *conn, struct FILEPROTO *file = conn->data->state.proto.file; (void)status; /* not used */ (void)premature; /* not used */ - Curl_safefree(file->freepath); - if(file->fd != -1) - close(file->fd); + 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 connectdata *conn, + bool dead_connection) +{ + struct FILEPROTO *file = conn->data->state.proto.file; + (void)dead_connection; /* not used */ + + if(file) { + Curl_safefree(file->freepath); + file->path = NULL; + if(file->fd != -1) + close(file->fd); + file->fd = -1; + } return CURLE_OK; } @@ -438,7 +447,6 @@ static CURLcode file_do(struct connectdata *conn, bool *done) curl_off_t expected_size=0; bool fstated=FALSE; ssize_t nread; - size_t bytestoread; struct SessionHandle *data = conn->data; char *buf = data->state.buffer; curl_off_t bytecount = 0; @@ -560,7 +568,10 @@ static CURLcode file_do(struct connectdata *conn, bool *done) while(res == CURLE_OK) { /* Don't fill a whole buffer if we want less than all data */ - bytestoread = (expected_size < BUFSIZE-1)?(size_t)expected_size:BUFSIZE-1; + size_t bytestoread = + (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ? + curlx_sotouz(expected_size) : BUFSIZE - 1; + nread = read(fd, buf, bytestoread); if(nread > 0) diff --git a/lib/fileinfo.c b/lib/fileinfo.c index 5495f560d..4ffcbbe29 100644 --- a/lib/fileinfo.c +++ b/lib/fileinfo.c @@ -22,7 +22,6 @@ #include "setup.h" -#include <stdlib.h> #include "strdup.h" #include "fileinfo.h" @@ -49,9 +48,7 @@ void Curl_fileinfo_dtor(void *user, void *element) if(!finfo) return; - if(finfo->b_data){ - free(finfo->b_data); - } + Curl_safefree(finfo->b_data); free(finfo); } diff --git a/lib/formdata.c b/lib/formdata.c index aa5a79ac1..cbef51171 100644 --- a/lib/formdata.c +++ b/lib/formdata.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include <curl/curl.h> /* Length of the random boundary string. */ @@ -28,14 +29,10 @@ #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <time.h> #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) #include <libgen.h> #endif + #include "urldata.h" /* for struct SessionHandle */ #include "formdata.h" #include "curl_rand.h" @@ -462,7 +459,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->flags & HTTPPOST_FILENAME) { if(filename) { if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) + NULL, current_form)) == NULL) return_value = CURL_FORMADD_MEMORY; } else @@ -487,46 +484,18 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } - case CURLFORM_BUFFER: - { - const char *filename = array_state?array_value: - va_arg(params, char *); - - if(current_form->value) { - if(current_form->flags & HTTPPOST_BUFFER) { - if(filename) { - if((current_form = AddFormInfo(strdup(filename), - NULL, current_form)) == NULL) - return_value = CURL_FORMADD_MEMORY; - } - 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 - return_value = CURL_FORMADD_NULL; - current_form->flags |= HTTPPOST_BUFFER; - } - break; - } - case CURLFORM_BUFFERPTR: - current_form->flags |= HTTPPOST_PTRBUFFER; + 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) + 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; } @@ -567,8 +536,8 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, if(current_form->flags & HTTPPOST_FILENAME) { if(contenttype) { if((current_form = AddFormInfo(NULL, - strdup(contenttype), - current_form)) == NULL) + strdup(contenttype), + current_form)) == NULL) return_value = CURL_FORMADD_MEMORY; } else @@ -606,6 +575,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, break; } case CURLFORM_FILENAME: + case CURLFORM_BUFFER: { const char *filename = array_state?array_value: va_arg(params, char *); @@ -622,6 +592,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, } default: return_value = CURL_FORMADD_UNKNOWN_OPTION; + break; } } @@ -884,10 +855,11 @@ int curl_formget(struct curl_httppost *form, void *arg, do { nread = readfromfile(&temp, buffer, sizeof(buffer)); - if((nread == (size_t) -1) || (nread != append(arg, buffer, nread))) { - if(temp.fp) { + if((nread == (size_t) -1) || + (nread > sizeof(buffer)) || + (nread != append(arg, buffer, nread))) { + if(temp.fp) fclose(temp.fp); - } Curl_formclean(&data); return -1; } @@ -925,7 +897,8 @@ void curl_formfree(struct curl_httppost *form) if(!(form->flags & HTTPPOST_PTRNAME) && form->name) free(form->name); /* free the name */ - if(!(form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_CALLBACK)) && + if(!(form->flags & + (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) && form->contents) free(form->contents); /* free the contents */ if(form->contenttype) @@ -1297,22 +1270,24 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata ) return 0; } +/* + * readfromfile() + * + * The read callback that this function may use can return a value larger than + * 'size' (which then this function returns) that indicates a problem and it + * must be properly dealt with + */ static size_t readfromfile(struct Form *form, char *buffer, size_t size) { size_t nread; - bool callback = (bool)(form->data->type == FORM_CALLBACK); + bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE; if(callback) { if(form->fread_func == ZERO_NULL) return 0; else nread = form->fread_func(buffer, 1, size, form->data->line); - - if(nread > size) - /* the read callback can return a value larger than the buffer but - treat any such as no data in this case */ - nread = 0; } else { if(!form->fp) { @@ -23,11 +23,6 @@ #include "setup.h" #ifndef CURL_DISABLE_FTP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -109,7 +104,7 @@ #endif #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define ftp_pasv_verbose(a,b,c,d) do { } while(0) +#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt #endif /* Local API functions */ @@ -139,9 +134,10 @@ static CURLcode ftp_connect(struct connectdata *conn, bool *done); static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); static CURLcode ftp_nextconnect(struct connectdata *conn); static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); -static int ftp_getsock(struct connectdata *conn, - curl_socket_t *socks, +static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, int numsocks); +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks); static CURLcode ftp_doing(struct connectdata *conn, bool *dophase_done); static CURLcode ftp_setup_connection(struct connectdata * conn); @@ -176,6 +172,7 @@ const struct Curl_handler Curl_handler_ftp = { 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, /* readwrite */ @@ -201,6 +198,7 @@ const struct Curl_handler Curl_handler_ftps = { 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, /* readwrite */ @@ -227,6 +225,7 @@ static const struct Curl_handler Curl_handler_ftp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -252,6 +251,7 @@ static const struct Curl_handler Curl_handler_ftps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -279,7 +279,7 @@ static void freedirs(struct ftp_conn *ftpc) { int i; if(ftpc->dirs) { - for(i=0; i < ftpc->dirdepth; i++){ + for(i=0; i < ftpc->dirdepth; i++) { if(ftpc->dirs[i]) { free(ftpc->dirs[i]); ftpc->dirs[i]=NULL; @@ -303,8 +303,8 @@ static void freedirs(struct ftp_conn *ftpc) */ static bool isBadFtpString(const char *string) { - return (bool)((NULL != strchr(string, '\r')) || - (NULL != strchr(string, '\n'))); + return ((NULL != strchr(string, '\r')) || + (NULL != strchr(string, '\n'))) ? TRUE : FALSE; } /*********************************************************************** @@ -639,6 +639,37 @@ static int ftp_getsock(struct connectdata *conn, return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); } +/* For the FTP "DO_MORE" phase only */ +static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks, + int numsocks) +{ + struct ftp_conn *ftpc = &conn->proto.ftpc; + + if(!numsocks) + return GETSOCK_BLANK; + + /* 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. + + When waiting for a connect, we will be in FTP_STOP state and then we wait + for the secondary socket to become writeable. If we're in another state, + we're still handling commands on the control (primary) connection. + + */ + + switch(ftpc->state) { + case FTP_STOP: + break; + default: + return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks); + } + + socks[0] = conn->sock[SECONDARYSOCKET]; + + return GETSOCK_READSOCK(0); +} + /* 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 @@ -810,7 +841,8 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, host = addr; else host = hbuf; /* use the hbuf for host name */ - }else + } + else /* there was only a port(-range) given, default the host */ host = NULL; } /* data->set.ftpport */ @@ -857,7 +889,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, free(addr); if(res == NULL) { - failf(data, "Curl_resolv failed, we can not recover!"); + failf(data, "failed to resolve the address provided to PORT: %s", host); return CURLE_FTP_PORT_FAILED; } @@ -1004,8 +1036,16 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd], sa->sa_family == AF_INET?1:2, myhost, port); - if(result) + if(result) { + failf(data, "Failure sending EPRT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* don't retry using PORT */ + ftpc->count1 = PORT; + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } else if(PORT == fcmd) { @@ -1025,8 +1065,14 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff)); result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp); - if(result) + if(result) { + failf(data, "Failure sending PORT command: %s", + curl_easy_strerror(result)); + Curl_closesocket(conn, portsock); + /* bail out */ + state(conn, FTP_STOP); return result; + } break; } } @@ -1048,7 +1094,7 @@ static CURLcode ftp_state_use_port(struct connectdata *conn, The *proper* fix is to make sure that the active connection from the server is done in a non-blocking way. Currently, it is still BLOCKING. */ - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_PORT); return result; @@ -1234,13 +1280,16 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) return CURLE_OUT_OF_MEMORY; } - PPSENDF(&conn->proto.ftpc.pp, "%s",cmd); + result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd); if(lstArg) free(lstArg); free(cmd); + if(result != CURLE_OK) + return result; + state(conn, FTP_LIST); return result; @@ -1708,7 +1757,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, if(result) return result; - conn->bits.tcpconnect = connected; /* simply TRUE or FALSE */ + conn->bits.tcpconnect[SECONDARYSOCKET] = connected; /* * When this is used from the multi interface, this might've returned with @@ -1746,6 +1795,9 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, break; } + if(result) + return result; + if(conn->bits.tunnel_proxy && conn->bits.httpproxy) { /* FIX: this MUST wait for a proper connect first if 'connected' is * FALSE */ @@ -1768,10 +1820,11 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, data->state.proto.ftp = ftp_save; - if(CURLE_OK != result) + if(result) return result; } + conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; state(conn, FTP_STOP); /* this phase is completed */ @@ -2528,7 +2581,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if(ftpcode/100 == 2) /* We have enabled SSL for the data connection! */ conn->ssl[SECONDARYSOCKET].use = - (bool)(data->set.ftp_ssl != CURLUSESSL_CONTROL); + (data->set.ftp_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE; /* FTP servers typically responds with 500 if they decide to reject our 'P' request */ else if(data->set.ftp_ssl > CURLUSESSL_CONTROL) @@ -2604,12 +2657,6 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) store++; ptr++; } - if(ftpc->entrypath) - free(ftpc->entrypath); - ftpc->entrypath =dir; /* remember this */ - infof(data, "Entry path is '%s'\n", ftpc->entrypath); - /* also save it where getinfo can access it: */ - data->state.most_recent_ftp_entrypath = ftpc->entrypath; /* 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 @@ -2623,11 +2670,27 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) if the path name looks strange to minimize overhead on other systems. */ - if(!ftpc->server_os && ftpc->entrypath[0] != '/') { - PPSENDF(&ftpc->pp, "SYST", NULL); + if(!ftpc->server_os && dir[0] != '/') { + + result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL); + if(result != CURLE_OK) { + free(dir); + return result; + } + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; state(conn, FTP_SYST); break; } + + Curl_safefree(ftpc->entrypath); + ftpc->entrypath = dir; /* remember this */ + infof(data, "Entry path is '%s'\n", ftpc->entrypath); + /* also save it where getinfo can access it: */ + data->state.most_recent_ftp_entrypath = ftpc->entrypath; } else { /* couldn't get the path */ @@ -2657,19 +2720,28 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) for(store = os; *ptr && *ptr != ' ';) *store++ = *ptr++; *store = '\0'; /* zero terminate */ - ftpc->server_os = os; /* Check for special servers here. */ - if(strequal(ftpc->server_os, "OS/400")) { + if(strequal(os, "OS/400")) { /* Force OS400 name format 1. */ - PPSENDF(&ftpc->pp, "SITE NAMEFMT 1", NULL); + result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL); + if(result != CURLE_OK) { + free(os); + return result; + } + /* remember target server OS */ + Curl_safefree(ftpc->server_os); + ftpc->server_os = os; state(conn, FTP_NAMEFMT); break; } - else { - /* Nothing special for the target server. */ - } + else { + /* 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. */ @@ -2820,7 +2892,7 @@ static CURLcode ftp_multi_statemach(struct connectdata *conn, /* Check for the state outside of the Curl_socket_ready() return code checks since at times we are in fact already in this state when this function gets called. */ - *done = (bool)(ftpc->state == FTP_STOP); + *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE; return result; } @@ -2874,9 +2946,9 @@ static CURLcode ftp_init(struct connectdata *conn) */ ftp->user = conn->user; ftp->passwd = conn->passwd; - if(TRUE == isBadFtpString(ftp->user)) + if(isBadFtpString(ftp->user)) return CURLE_URL_MALFORMAT; - if(TRUE == isBadFtpString(ftp->passwd)) + if(isBadFtpString(ftp->passwd)) return CURLE_URL_MALFORMAT; conn->proto.ftpc.known_filesize = -1; /* unknown size for now */ @@ -3478,7 +3550,7 @@ CURLcode ftp_perform(struct connectdata *conn, result = ftp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -3631,8 +3703,7 @@ static CURLcode wc_statemach(struct connectdata *conn) strcat(tmp_path, finfo->filename); /* switch default "state.pathbuffer" and tmp_path, good to see ftp_parse_url_path function to understand this trick */ - if(conn->data->state.pathbuffer) - free(conn->data->state.pathbuffer); + Curl_safefree(conn->data->state.pathbuffer); conn->data->state.pathbuffer = tmp_path; conn->data->state.path = tmp_path; @@ -4099,12 +4170,13 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, /* called from multi.c while DOing */ static CURLcode ftp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result; - result = ftp_multi_statemach(conn, dophase_done); + CURLcode result = ftp_multi_statemach(conn, dophase_done); - if(*dophase_done) { + if(result) + DEBUGF(infof(conn->data, "DO phase failed\n")); + else if(*dophase_done) { result = ftp_dophase_done(conn, FALSE /* not connected */); DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/ftplistparser.c b/lib/ftplistparser.c index a3fef3971..bbf6e9ef9 100644 --- a/lib/ftplistparser.c +++ b/lib/ftplistparser.c @@ -37,8 +37,6 @@ #include "setup.h" -#include <time.h> - #include "ftplistparser.h" #include "curl_fnmatch.h" diff --git a/lib/getenv.c b/lib/getenv.c index 36fbb7583..6b40dd68d 100644 --- a/lib/getenv.c +++ b/lib/getenv.c @@ -22,10 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #ifdef __VMS #include <unixlib.h> #endif diff --git a/lib/getinfo.c b/lib/getinfo.c index bb289741a..aa7af2c86 100644 --- a/lib/getinfo.c +++ b/lib/getinfo.c @@ -27,10 +27,6 @@ #include "urldata.h" #include "getinfo.h" -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> #include "curl_memory.h" #include "sslgen.h" #include "connect.h" /* Curl_getconnectinfo() */ diff --git a/lib/gopher.c b/lib/gopher.c index b2d2689d1..b4efae8cc 100644 --- a/lib/gopher.c +++ b/lib/gopher.c @@ -24,28 +24,18 @@ #ifndef CURL_DISABLE_GOPHER -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -64,9 +54,6 @@ #include <sys/select.h> #endif - -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -110,6 +97,7 @@ const struct Curl_handler Curl_handler_gopher = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ diff --git a/lib/gtls.c b/lib/gtls.c index a376fb0b9..7ca46c812 100644 --- a/lib/gtls.c +++ b/lib/gtls.c @@ -29,14 +29,13 @@ */ #include "setup.h" + #ifdef USE_GNUTLS + #include <gnutls/gnutls.h> #include <gnutls/x509.h> #include <gcrypt.h> -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -477,8 +476,10 @@ gtls_connect_step1(struct connectdata *conn, gnutls_transport_set_push_function(session, Curl_gtls_push); gnutls_transport_set_pull_function(session, Curl_gtls_pull); +#if GNUTLS_VERSION_NUMBER < 0x020c00 /* lowat must be set to zero when using custom push and pull functions. */ gnutls_transport_set_lowat(session, 0); +#endif /* This might be a reconnect, so we check for a session ID in the cache to speed up things */ diff --git a/lib/gtls.h b/lib/gtls.h index 6275b49a3..733122e6c 100644 --- a/lib/gtls.h +++ b/lib/gtls.h @@ -1,5 +1,5 @@ -#ifndef __GTLS_H -#define __GTLS_H +#ifndef HEADER_CURL_GTLS_H +#define HEADER_CURL_GTLS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -22,8 +22,12 @@ * ***************************************************************************/ +#include "setup.h" + #ifdef USE_GNUTLS +#include "urldata.h" + int Curl_gtls_init(void); int Curl_gtls_cleanup(void); CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex); @@ -60,4 +64,4 @@ int Curl_gtls_seed(struct SessionHandle *data); #define curlssl_data_pending(x,y) (x=x, y=y, 0) #endif /* USE_GNUTLS */ -#endif +#endif /* HEADER_CURL_GTLS_H */ diff --git a/lib/hash.c b/lib/hash.c index 6c921e442..3704eea41 100644 --- a/lib/hash.c +++ b/lib/hash.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> - #include "hash.h" #include "llist.h" @@ -41,11 +38,14 @@ 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->key) - free(e->key); + Curl_safefree(e->key); - if(e->ptr) + if(e->ptr) { h->dtor(e->ptr); + e->ptr = NULL; + } + + e->key_len = 0; free(e); } @@ -75,16 +75,22 @@ Curl_hash_init(struct curl_hash *h, for(i = 0; i < slots; ++i) { h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor); if(!h->table[i]) { - while(i--) + while(i--) { Curl_llist_destroy(h->table[i], NULL); + h->table[i] = NULL; + } free(h->table); + h->table = NULL; + h->slots = 0; return 1; /* failure */ } } return 0; /* fine */ } - else + else { + h->slots = 0; return 1; /* failure */ + } } struct curl_hash * @@ -190,6 +196,7 @@ int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len) 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; } } @@ -243,6 +250,9 @@ Curl_hash_clean(struct curl_hash *h) } free(h->table); + h->table = NULL; + h->size = 0; + h->slots = 0; } void diff --git a/lib/hostasyn.c b/lib/hostasyn.c index 50f6b01fb..771562fd1 100644 --- a/lib/hostasyn.c +++ b/lib/hostasyn.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/hostip.c b/lib/hostip.c index 084ee86ac..d261a163a 100644 --- a/lib/hostip.c +++ b/lib/hostip.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_SETJMP_H @@ -560,6 +554,10 @@ int Curl_resolv_timeout(struct connectdata *conn, *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 */ diff --git a/lib/hostip4.c b/lib/hostip4.c index 67aefda29..1a5e26585 100644 --- a/lib/hostip4.c +++ b/lib/hostip4.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -37,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/hostip6.c b/lib/hostip6.c index b944401c5..8241cb4bc 100644 --- a/lib/hostip6.c +++ b/lib/hostip6.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H @@ -160,7 +154,7 @@ static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai) } } #else -#define dump_addrinfo(x,y) +#define dump_addrinfo(x,y) Curl_nop_stmt #endif /* diff --git a/lib/hostsyn.c b/lib/hostsyn.c index a5e97658e..b60188708 100644 --- a/lib/hostsyn.c +++ b/lib/hostsyn.c @@ -22,8 +22,6 @@ #include "setup.h" -#include <string.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -36,16 +34,12 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* required for free() prototypes */ -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> /* for the close() proto */ #endif #ifdef __VMS #include <in.h> #include <inet.h> -#include <stdlib.h> #endif #ifdef HAVE_PROCESS_H diff --git a/lib/http.c b/lib/http.c index 56d263b91..f85cd6c55 100644 --- a/lib/http.c +++ b/lib/http.c @@ -23,32 +23,13 @@ #include "setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif - -#ifdef HAVE_TIME_H -#ifdef TIME_WITH_SYS_TIME -#include <time.h> -#endif -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -70,8 +51,6 @@ #include <sys/param.h> #endif -#endif - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -83,7 +62,8 @@ #include "strequal.h" #include "sslgen.h" #include "http_digest.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "http_negotiate.h" #include "url.h" #include "share.h" @@ -138,6 +118,7 @@ const struct Curl_handler Curl_handler_http = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -161,6 +142,7 @@ const struct Curl_handler Curl_handler_https = { ZERO_NULL, /* doing */ https_getsock, /* proto_getsock */ http_getsock_do, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -252,11 +234,13 @@ static char *copy_header_value(const char *h) */ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) { - char *authorization; - struct SessionHandle *data=conn->data; + size_t size = 0; + char *authorization = NULL; + struct SessionHandle *data = conn->data; char **userp; const char *user; const char *pwd; + CURLcode error; if(proxy) { userp = &conn->allocptr.proxyuserpwd; @@ -270,20 +254,24 @@ static CURLcode http_output_basic(struct connectdata *conn, bool proxy) } snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd); - if(Curl_base64_encode(data, data->state.buffer, - strlen(data->state.buffer), - &authorization) > 0) { - if(*userp) - free(*userp); - *userp = aprintf( "%sAuthorization: Basic %s\r\n", - proxy?"Proxy-":"", - authorization); - free(authorization); - if(!*userp) - return CURLE_OUT_OF_MEMORY; - } - else + + error = Curl_base64_encode(data, + data->state.buffer, strlen(data->state.buffer), + &authorization, &size); + if(error) + return error; + + if(!authorization) + return CURLE_REMOTE_ACCESS_DENIED; + + Curl_safefree(*userp); + *userp = aprintf("%sAuthorization: Basic %s\r\n", + proxy?"Proxy-":"", + authorization); + free(authorization); + if(!*userp) return CURLE_OUT_OF_MEMORY; + return CURLE_OK; } @@ -307,6 +295,8 @@ static bool pickoneauth(struct auth *pick) pick->picked = CURLAUTH_DIGEST; else if(avail & CURLAUTH_NTLM) pick->picked = CURLAUTH_NTLM; + else if(avail & CURLAUTH_NTLM_WB) + pick->picked = CURLAUTH_NTLM_WB; else if(avail & CURLAUTH_BASIC) pick->picked = CURLAUTH_BASIC; else { @@ -393,15 +383,19 @@ static CURLcode http_perhapsrewind(struct connectdata *conn) if((expectsend == -1) || (expectsend > bytessent)) { /* There is still data left to send */ if((data->state.authproxy.picked == CURLAUTH_NTLM) || - (data->state.authhost.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->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) + if(!conn->bits.authneg) { conn->bits.rewindaftersend = TRUE; + infof(data, "Rewind stream after send\n"); + } return CURLE_OK; } @@ -554,6 +548,15 @@ output_auth_headers(struct connectdata *conn, } else #endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + if(authstatus->picked == CURLAUTH_NTLM_WB) { + auth="NTLM_WB"; + result = Curl_output_ntlm_wb(conn, proxy); + if(result) + return result; + } + else +#endif #ifndef CURL_DISABLE_CRYPTO_AUTH if(authstatus->picked == CURLAUTH_DIGEST) { auth="Digest"; @@ -587,7 +590,7 @@ output_auth_headers(struct connectdata *conn, proxy?"Proxy":"Server", auth, proxy?(conn->proxyuser?conn->proxyuser:""): (conn->user?conn->user:"")); - authstatus->multi = (bool)(!authstatus->done); + authstatus->multi = (!authstatus->done) ? TRUE : FALSE; } else authstatus->multi = FALSE; @@ -730,73 +733,73 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, * */ + while(*start) { #ifdef USE_HTTP_NEGOTIATE - if(checkprefix("GSS-Negotiate", start) || - checkprefix("Negotiate", start)) { - int neg; - *availp |= CURLAUTH_GSSNEGOTIATE; - authp->avail |= CURLAUTH_GSSNEGOTIATE; - - if(data->state.negotiate.state == GSS_AUTHSENT) { - /* if we sent GSS authentication in the outgoing request and we get this - back, we're in trouble */ - infof(data, "Authentication problem. Ignoring this.\n"); - data->state.authproblem = TRUE; - } - else { - neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start); - if(neg == 0) { - DEBUGASSERT(!data->req.newurl); - data->req.newurl = strdup(data->change.url); - if(!data->req.newurl) - return CURLE_OUT_OF_MEMORY; - data->state.authproblem = FALSE; - /* we received GSS auth info and we dealt with it fine */ - data->state.negotiate.state = GSS_AUTHRECV; - } - else { + if(checkprefix("GSS-Negotiate", start) || + checkprefix("Negotiate", start)) { + int neg; + *availp |= CURLAUTH_GSSNEGOTIATE; + authp->avail |= CURLAUTH_GSSNEGOTIATE; + + if(data->state.negotiate.state == GSS_AUTHSENT) { + /* if we sent GSS authentication in the outgoing request and we get + this back, we're in trouble */ + infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } - } - } - else -#endif -#ifdef USE_NTLM - /* NTLM support requires the SSL crypto libs */ - if(checkprefix("NTLM", start)) { - *availp |= CURLAUTH_NTLM; - authp->avail |= CURLAUTH_NTLM; - if(authp->picked == CURLAUTH_NTLM) { - /* NTLM authentication is picked and activated */ - CURLntlm ntlm = - Curl_input_ntlm(conn, (bool)(httpcode == 407), start); - - if(CURLNTLM_BAD != ntlm) + else { + neg = Curl_input_negotiate(conn, (httpcode == 407)?TRUE:FALSE, start); + if(neg == 0) { + DEBUGASSERT(!data->req.newurl); + data->req.newurl = strdup(data->change.url); + if(!data->req.newurl) + return CURLE_OUT_OF_MEMORY; data->state.authproblem = FALSE; + /* we received GSS auth info and we dealt with it fine */ + data->state.negotiate.state = GSS_AUTHRECV; + } else { - infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } } } else #endif -#ifndef CURL_DISABLE_CRYPTO_AUTH - if(checkprefix("Digest", start)) { - if((authp->avail & CURLAUTH_DIGEST) != 0) { - infof(data, "Ignoring duplicate digest auth header.\n"); - } - else { - CURLdigest dig; - *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 gonna use Digest. */ - dig = Curl_input_digest(conn, (bool)(httpcode == 407), start); - - if(CURLDIGEST_FINE != dig) { +#ifdef USE_NTLM + /* NTLM support requires the SSL crypto libs */ + if(checkprefix("NTLM", start)) { + *availp |= CURLAUTH_NTLM; + authp->avail |= CURLAUTH_NTLM; + if(authp->picked == CURLAUTH_NTLM || + authp->picked == CURLAUTH_NTLM_WB) { + /* NTLM authentication is picked and activated */ + CURLcode ntlm = + Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start); + if(CURLE_OK == ntlm) { + 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; + + /* Get the challenge-message which will be passed to + * ntlm_auth for generating the type 3 message later */ + while(*start && ISSPACE(*start)) + start++; + if(checkprefix("NTLM", start)) { + start += strlen("NTLM"); + while(*start && ISSPACE(*start)) + start++; + if(*start) + if((conn->challenge_header = strdup(start)) == NULL) + return CURLE_OUT_OF_MEMORY; + } + } +#endif + } + else { infof(data, "Authentication problem. Ignoring this.\n"); data->state.authproblem = TRUE; } @@ -804,19 +807,51 @@ CURLcode Curl_http_input_auth(struct connectdata *conn, } else #endif - if(checkprefix("Basic", start)) { - *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.\n"); - data->state.authproblem = TRUE; +#ifndef CURL_DISABLE_CRYPTO_AUTH + if(checkprefix("Digest", start)) { + if((authp->avail & CURLAUTH_DIGEST) != 0) { + infof(data, "Ignoring duplicate digest auth header.\n"); + } + else { + CURLdigest dig; + *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 gonna use + * Digest. */ + dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start); + + if(CURLDIGEST_FINE != dig) { + infof(data, "Authentication problem. Ignoring this.\n"); + data->state.authproblem = TRUE; + } + } } - } + else +#endif + if(checkprefix("Basic", start)) { + *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.\n"); + data->state.authproblem = TRUE; + } + } + /* there may be multiple methods on one line, so keep reading */ + while(*start && *start != ',') /* read up to the next comma */ + start++; + if(*start == ',') /* if we're on a comma, skip it */ + start++; + while(*start && ISSPACE(*start)) + start++; + } return CURLE_OK; } @@ -923,7 +958,7 @@ static size_t readmoredata(char *buffer, return 0; /* make sure that a HTTP request is never sent away chunked! */ - conn->data->req.forbidchunk = (bool)(http->sending == HTTPSEND_REQUEST); + conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE; if(http->postsize <= (curl_off_t)fullsize) { memcpy(buffer, http->postdata, (size_t)http->postsize); @@ -1456,11 +1491,11 @@ CURLcode Curl_http_done(struct connectdata *conn, static bool use_http_1_1(const struct SessionHandle *data, const struct connectdata *conn) { - return (bool)((data->set.httpversion == CURL_HTTP_VERSION_1_1) || + return ((data->set.httpversion == CURL_HTTP_VERSION_1_1) || ((data->set.httpversion != CURL_HTTP_VERSION_1_0) && ((conn->httpversion == 11) || ((conn->httpversion != 10) && - (data->state.httpversion != 10))))); + (data->state.httpversion != 10))))) ? TRUE : FALSE; } /* check and possibly add an Expect: header */ @@ -1536,6 +1571,31 @@ CURLcode Curl_add_custom_headers(struct connectdata *conn, } } } + else { + ptr = strchr(headers->data, ';'); + if(ptr) { + + ptr++; /* pass the semicolon */ + while(*ptr && ISSPACE(*ptr)) + ptr++; + + if(*ptr) { + /* this may be used for something else in the future */ + } + else { + if(*(--ptr) == ';') { + CURLcode result; + + /* send no-value custom header if terminated by semicolon */ + *ptr = ':'; + result = Curl_add_bufferf(req_buffer, "%s\r\n", + headers->data); + if(result) + return result; + } + } + } + } headers = headers->next; } return CURLE_OK; @@ -1615,7 +1675,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) curl_off_t included_body = 0; const char *httpstring; Curl_send_buffer *req_buffer; - curl_off_t postsize; /* off_t type to be able to hold a large file size */ + curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */ int seekerr = CURL_SEEKFUNC_OK; /* Always consider the DO phase done after this function call, even if there @@ -1648,6 +1708,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(!data->state.first_host) return CURLE_OUT_OF_MEMORY; } + http->writebytecount = http->readbytecount = 0; if((conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_FTP)) && data->set.upload) { @@ -1754,8 +1815,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) } else { if((conn->handler->protocol&CURLPROTO_HTTP) && - data->set.upload && - (data->set.infilesize == -1)) { + data->set.upload && + (data->set.infilesize == -1)) { if(conn->bits.authneg) /* don't enable chunked during auth neg */ ; @@ -1863,8 +1924,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) memcpy(newurl + newlen + (ptr - url), ptr + currlen, /* copy the trailing zero byte too */ urllen - (ptr-url) - currlen + 1); - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; data->change.url_alloc = TRUE; } @@ -1933,7 +1996,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) * 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; + data->state.resume_from = 0; } if(data->state.resume_from && !data->state.this_is_a_follow) { @@ -2024,17 +2087,17 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) curl_off_t total_expected_size= data->state.resume_from + data->set.infilesize; conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s%" FORMAT_OFF_T - "/%" FORMAT_OFF_T "\r\n", - data->state.range, total_expected_size-1, - total_expected_size); + aprintf("Content-Range: bytes %s%" FORMAT_OFF_T + "/%" FORMAT_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 */ conn->allocptr.rangeline = - aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", - data->state.range, data->set.infilesize); + aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n", + data->state.range, data->set.infilesize); } if(!conn->allocptr.rangeline) return CURLE_OUT_OF_MEMORY; @@ -2067,45 +2130,47 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) if(result) return result; - result = Curl_add_bufferf(req_buffer, - "%s" /* ftp typecode (;type=x) */ - " HTTP/%s\r\n" /* HTTP version */ - "%s" /* proxyuserpwd */ - "%s" /* userpwd */ - "%s" /* range */ - "%s" /* user agent */ - "%s" /* host */ - "%s" /* accept */ - "%s" /* TE: */ - "%s" /* accept-encoding */ - "%s" /* referer */ - "%s" /* Proxy-Connection */ - "%s",/* transfer-encoding */ - - ftp_typecode, - httpstring, - conn->allocptr.proxyuserpwd? - conn->allocptr.proxyuserpwd:"", - conn->allocptr.userpwd?conn->allocptr.userpwd:"", - (data->state.use_range && conn->allocptr.rangeline)? - conn->allocptr.rangeline:"", - (data->set.str[STRING_USERAGENT] && - *data->set.str[STRING_USERAGENT] && conn->allocptr.uagent)? - conn->allocptr.uagent:"", - (conn->allocptr.host?conn->allocptr.host:""), /* Host: host */ - http->p_accept?http->p_accept:"", - conn->allocptr.te?conn->allocptr.te:"", - (data->set.str[STRING_ENCODING] && - *data->set.str[STRING_ENCODING] && - conn->allocptr.accept_encoding)? - conn->allocptr.accept_encoding:"", - (data->change.referer && conn->allocptr.ref)? - conn->allocptr.ref:"" /* Referer: <data> */, - (conn->bits.httpproxy && - !conn->bits.tunnel_proxy && - !Curl_checkheaders(data, "Proxy-Connection:"))? - "Proxy-Connection: Keep-Alive\r\n":"", - te + result = + Curl_add_bufferf(req_buffer, + "%s" /* ftp typecode (;type=x) */ + " HTTP/%s\r\n" /* HTTP version */ + "%s" /* proxyuserpwd */ + "%s" /* userpwd */ + "%s" /* range */ + "%s" /* user agent */ + "%s" /* host */ + "%s" /* accept */ + "%s" /* TE: */ + "%s" /* accept-encoding */ + "%s" /* referer */ + "%s" /* Proxy-Connection */ + "%s",/* transfer-encoding */ + + ftp_typecode, + httpstring, + conn->allocptr.proxyuserpwd? + conn->allocptr.proxyuserpwd:"", + conn->allocptr.userpwd?conn->allocptr.userpwd:"", + (data->state.use_range && conn->allocptr.rangeline)? + conn->allocptr.rangeline:"", + (data->set.str[STRING_USERAGENT] && + *data->set.str[STRING_USERAGENT] && + conn->allocptr.uagent)? + conn->allocptr.uagent:"", + (conn->allocptr.host?conn->allocptr.host:""), + http->p_accept?http->p_accept:"", + conn->allocptr.te?conn->allocptr.te:"", + (data->set.str[STRING_ENCODING] && + *data->set.str[STRING_ENCODING] && + conn->allocptr.accept_encoding)? + conn->allocptr.accept_encoding:"", + (data->change.referer && conn->allocptr.ref)? + conn->allocptr.ref:"" /* Referer: <data> */, + (conn->bits.httpproxy && + !conn->bits.tunnel_proxy && + !Curl_checkheaders(data, "Proxy-Connection:"))? + "Proxy-Connection: Keep-Alive\r\n":"", + te ); /* @@ -2130,8 +2195,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) conn->allocptr.cookiehost? conn->allocptr.cookiehost:host, data->state.path, - (bool)(conn->handler->protocol&CURLPROTO_HTTPS? - TRUE:FALSE)); + (conn->handler->protocol&CURLPROTO_HTTPS)? + TRUE:FALSE); Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE); } if(co) { @@ -2145,8 +2210,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) break; } result = Curl_add_bufferf(req_buffer, - "%s%s=%s", count?"; ":"", - co->name, co->value); + "%s%s=%s", count?"; ":"", + co->name, co->value); if(result) break; count++; @@ -2160,8 +2225,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) result = Curl_add_bufferf(req_buffer, "Cookie: "); if(CURLE_OK == result) { result = Curl_add_bufferf(req_buffer, "%s%s", - count?"; ":"", - addcookies); + count?"; ":"", + addcookies); count++; } } @@ -2228,11 +2293,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) http->sending = HTTPSEND_BODY; - if(!data->req.upload_chunky) { + if(!data->req.upload_chunky && + !Curl_checkheaders(data, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - http->postsize); + "Content-Length: %" FORMAT_OFF_T "\r\n", + http->postsize); if(result) return result; } @@ -2299,11 +2365,12 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) else postsize = data->set.infilesize; - if((postsize != -1) && !data->req.upload_chunky) { + if((postsize != -1) && !data->req.upload_chunky && + !Curl_checkheaders(data, "Content-Length:")) { /* only add Content-Length if not uploading chunked */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T "\r\n", - postsize ); + "Content-Length: %" FORMAT_OFF_T "\r\n", + postsize ); if(result) return result; } @@ -2353,8 +2420,8 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* we allow replacing this header if not during auth negotiation, although it isn't very wise to actually set your own */ result = Curl_add_bufferf(req_buffer, - "Content-Length: %" FORMAT_OFF_T"\r\n", - postsize); + "Content-Length: %" FORMAT_OFF_T"\r\n", + postsize); if(result) return result; } @@ -2404,7 +2471,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* We're not sending it 'chunked', append it to the request already now to reduce the number if send() calls */ result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); + (size_t)postsize); included_body = postsize; } else { @@ -2412,10 +2479,10 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize); if(CURLE_OK == result) result = Curl_add_buffer(req_buffer, data->set.postfields, - (size_t)postsize); + (size_t)postsize); if(CURLE_OK == result) result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); + "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); /* CR LF 0 CR LF CR LF */ included_body = postsize + 7; } @@ -2451,7 +2518,7 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) /* Chunky upload is selected and we're negotiating auth still, send end-of-data only */ result = Curl_add_buffer(req_buffer, - "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); + "\x0d\x0a\x30\x0d\x0a\x0d\x0a", 7); /* CR LF 0 CR LF CR LF */ if(result) return result; @@ -2508,6 +2575,17 @@ CURLcode Curl_http(struct connectdata *conn, bool *done) Curl_pgrsSetUploadCounter(data, http->writebytecount); if(Curl_pgrsUpdate(conn)) result = CURLE_ABORTED_BY_CALLBACK; + + if(http->writebytecount >= postsize) { + /* already sent the entire request body, mark the "upload" as + complete */ + infof(data, "upload completely sent off: %" FORMAT_OFF_T " out of " + "%" FORMAT_OFF_T " bytes\n", + http->writebytecount, postsize); + data->req.upload_done = TRUE; + data->req.keepon &= ~KEEP_SEND; /* we're done writing */ + data->req.exp100 = EXP100_SEND_DATA; /* already sent */ + } } return result; @@ -2547,7 +2625,7 @@ checkhttpprefix(struct SessionHandle *data, head = head->next; } - if((rc != TRUE) && (checkprefix("HTTP/", s))) + if(!rc && (checkprefix("HTTP/", s))) rc = TRUE; #ifdef CURL_DOES_CONVERSIONS @@ -2779,17 +2857,6 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, } } - if(417 == k->httpcode) { - /* - * we got: "417 Expectation Failed" this means: - * we have made a HTTP call and our Expect Header - * seems to cause a problem => abort the write operations - * (or prevent them from starting). - */ - k->exp100 = EXP100_FAILED; - k->keepon &= ~KEEP_SEND; - } - /* * When all the headers have been parsed, see if we should give * up and return an error. @@ -2829,6 +2896,46 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, if(result) return result; + if(k->httpcode >= 300) { + if((!conn->bits.authneg) && !conn->bits.close && + !conn->bits.rewindaftersend) { + /* + * 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. + * + * rewindaftersend indicates that something has told libcurl to + * continue sending even if it gets discarded + */ + + switch(data->set.httpreq) { + case HTTPREQ_PUT: + case HTTPREQ_POST: + case HTTPREQ_POST_FORM: + /* 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. + */ + if(!k->upload_done) { + infof(data, "HTTP error before end of send, stop sending\n"); + conn->bits.close = TRUE; /* close after this */ + k->upload_done = TRUE; + k->keepon &= ~KEEP_SEND; /* don't send */ + if(data->state.expect100header) + k->exp100 = EXP100_FAILED; + } + break; + + default: /* default label present to avoid compiler warnings */ + break; + } + } + } + if(conn->bits.rewindaftersend) { /* We rewind after a complete send, so thus we continue sending now */ @@ -2929,23 +3036,23 @@ CURLcode Curl_http_readwrite_headers(struct SessionHandle *data, if(conn->handler->protocol & CURLPROTO_HTTP) { nc = sscanf(HEADER1, - " HTTP/%d.%d %3d", - &httpversion_major, - &conn->httpversion, - &k->httpcode); + " HTTP/%d.%d %3d", + &httpversion_major, + &conn->httpversion, + &k->httpcode); if(nc==3) { conn->httpversion += 10 * httpversion_major; } else { /* this is the real world, not a Nirvana NCSA 1.5.x returns this crap when asked for HTTP/1.1 - */ + */ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode); conn->httpversion = 10; /* If user has set option HTTP200ALIASES, compare header line against list of aliases - */ + */ if(!nc) { if(checkhttpprefix(data, k->p)) { nc = 1; diff --git a/lib/http_chunks.c b/lib/http_chunks.c index 93de1d968..d6a0bec13 100644 --- a/lib/http_chunks.c +++ b/lib/http_chunks.c @@ -19,15 +19,10 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" /* it includes http_chunks.h */ #include "sendf.h" /* for the client write stuff */ @@ -84,9 +79,9 @@ We avoid the use of isxdigit to accommodate non-ASCII hosts. */ static bool Curl_isxdigit(char digit) { - return (bool)( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ - || (digit >= 0x41 && digit <= 0x46) /* A-F */ - || (digit >= 0x61 && digit <= 0x66) ); /* a-f */ + return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */ + || (digit >= 0x41 && digit <= 0x46) /* A-F */ + || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE; } void Curl_httpchunk_init(struct connectdata *conn) diff --git a/lib/http_digest.c b/lib/http_digest.c index c3a39fcee..b41e62306 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -19,15 +19,10 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" @@ -285,7 +280,8 @@ CURLcode Curl_output_digest(struct connectdata *conn, unsigned char *ha1; unsigned char ha2[33];/* 32 digits and 1 zero byte */ char cnoncebuf[7]; - char *cnonce; + char *cnonce = NULL; + size_t cnonce_sz = 0; char *tmp = NULL; struct timeval now; @@ -348,10 +344,12 @@ CURLcode Curl_output_digest(struct connectdata *conn, /* Generate a cnonce */ now = Curl_tvnow(); snprintf(cnoncebuf, sizeof(cnoncebuf), "%06ld", (long)now.tv_sec); - if(Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), &cnonce)) - d->cnonce = cnonce; - else - return CURLE_OUT_OF_MEMORY; + + rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), + &cnonce, &cnonce_sz); + if(rc) + return rc; + d->cnonce = cnonce; } /* diff --git a/lib/http_digest.h b/lib/http_digest.h index 75fcba929..3b22ce10e 100644 --- a/lib/http_digest.h +++ b/lib/http_digest.h @@ -1,5 +1,5 @@ -#ifndef __HTTP_DIGEST_H -#define __HTTP_DIGEST_H +#ifndef HEADER_CURL_HTTP_DIGEST_H +#define HEADER_CURL_HTTP_DIGEST_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" typedef enum { CURLDIGEST_NONE, /* not a digest */ @@ -50,7 +51,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) void Curl_digest_cleanup(struct SessionHandle *data); #else -#define Curl_digest_cleanup(x) do {} while(0) +#define Curl_digest_cleanup(x) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_HTTP_DIGEST_H */ diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 5127e6480..4e68ab762 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -19,27 +19,25 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifdef HAVE_GSSAPI #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif #ifndef CURL_DISABLE_HTTP - /* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" +#include "curl_gssapi.h" #include "rawstr.h" #include "curl_base64.h" #include "http_negotiate.h" #include "curl_memory.h" +#include "url.h" #ifdef HAVE_SPNEGO # include <spnegohelp.h> @@ -134,15 +132,18 @@ log_gss_error(struct connectdata *conn, OM_uint32 error_status, int Curl_input_negotiate(struct connectdata *conn, bool proxy, const char *header) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; + struct SessionHandle *data = conn->data; + struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg: + &data->state.negotiate; OM_uint32 major_status, minor_status, minor_status2; gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER; gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER; int ret; - size_t len, rawlen; + size_t len; + size_t rawlen = 0; bool gss; const char* protocol; + CURLcode error; while(*header && ISSPACE(*header)) header++; @@ -171,7 +172,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, /* 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_cleanup_negotiate(conn->data); + Curl_cleanup_negotiate(data); return -1; } @@ -185,9 +186,9 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, len = strlen(header); if(len > 0) { - rawlen = Curl_base64_decode(header, - (unsigned char **)&input_token.value); - if(rawlen == 0) + error = Curl_base64_decode(header, + (unsigned char **)&input_token.value, &rawlen); + if(error || rawlen == 0) return -1; input_token.length = rawlen; @@ -220,7 +221,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, NULL)) { free(spnegoToken); spnegoToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token failed\n"); + infof(data, "Parse SPNEGO Target Token failed\n"); } else { free(input_token.value); @@ -232,30 +233,25 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, input_token.length = mechTokenLength; free(mechToken); mechToken = NULL; - infof(conn->data, "Parse SPNEGO Target Token succeeded\n"); + infof(data, "Parse SPNEGO Target Token succeeded\n"); } } #endif } - major_status = gss_init_sec_context(&minor_status, - GSS_C_NO_CREDENTIAL, - &neg_ctx->context, - neg_ctx->server_name, - GSS_C_NO_OID, - 0, - 0, - GSS_C_NO_CHANNEL_BINDINGS, - &input_token, - NULL, - &output_token, - NULL, - NULL); + major_status = Curl_gss_init_sec_context(data, + &minor_status, + &neg_ctx->context, + neg_ctx->server_name, + GSS_C_NO_CHANNEL_BINDINGS, + &input_token, + &output_token, + NULL); if(input_token.length > 0) gss_release_buffer(&minor_status2, &input_token); neg_ctx->status = major_status; if(GSS_ERROR(major_status)) { - /* Curl_cleanup_negotiate(conn->data) ??? */ + /* Curl_cleanup_negotiate(data) ??? */ log_gss_error(conn, minor_status, "gss_init_sec_context() failed: "); return -1; @@ -277,8 +273,9 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; char *encoded = NULL; - size_t len; + size_t len = 0; char *userp; + CURLcode error; #ifdef HAVE_SPNEGO /* Handle SPNEGO */ if(checkprefix("Negotiate", neg_ctx->protocol)) { @@ -324,13 +321,21 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) } } #endif - len = Curl_base64_encode(conn->data, - neg_ctx->output_token.value, - neg_ctx->output_token.length, - &encoded); + error = Curl_base64_encode(conn->data, + neg_ctx->output_token.value, + neg_ctx->output_token.length, + &encoded, &len); + if(error) { + Curl_safefree(neg_ctx->output_token.value); + neg_ctx->output_token.value = NULL; + return error; + } - if(len == 0) - return CURLE_OUT_OF_MEMORY; + if(len == 0) { + Curl_safefree(neg_ctx->output_token.value); + neg_ctx->output_token.value = NULL; + return CURLE_REMOTE_ACCESS_DENIED; + } userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded); diff --git a/lib/http_negotiate_sspi.c b/lib/http_negotiate_sspi.c index 809870168..08d016274 100644 --- a/lib/http_negotiate_sspi.c +++ b/lib/http_negotiate_sspi.c @@ -19,17 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ + #include "setup.h" #ifdef USE_WINDOWS_SSPI #ifndef CURL_DISABLE_HTTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> #include "urldata.h" #include "sendf.h" @@ -45,13 +40,16 @@ #include "memdebug.h" static int -get_gss_name(struct connectdata *conn, bool proxy, char *server) +get_gss_name(struct connectdata *conn, bool proxy, + struct negotiatedata *neg_ctx) { - struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: - &conn->data->state.negotiate; const char* service; size_t length; + if(proxy && !conn->proxy.name) + /* proxy auth requested but no given proxy name, error out! */ + return -1; + /* GSSAPI implementation by Globus (known as GSI) requires the name to be of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead of at-sign). Also GSI servers are often identified as 'host' not 'khttp'. @@ -71,7 +69,7 @@ get_gss_name(struct connectdata *conn, bool proxy, char *server) if(length + 1 > sizeof(neg_ctx->server_name)) return EMSGSIZE; - snprintf(server, sizeof(neg_ctx->server_name), "%s/%s", + snprintf(neg_ctx->server_name, sizeof(neg_ctx->server_name), "%s/%s", service, proxy ? conn->proxy.name : conn->host.name); return 0; @@ -84,7 +82,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, { struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; - BYTE *input_token = 0; + BYTE *input_token = 0; SecBufferDesc out_buff_desc; SecBuffer out_sec_buff; SecBufferDesc in_buff_desc; @@ -96,6 +94,7 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, size_t len = 0, input_token_len = 0; bool gss = FALSE; const char* protocol; + CURLcode error; while(*header && ISSPACE(*header)) header++; @@ -129,9 +128,11 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, return -1; } - if(strlen(neg_ctx->server_name) == 0 && - (ret = get_gss_name(conn, proxy, neg_ctx->server_name))) - return ret; + if(0 == strlen(neg_ctx->server_name)) { + ret = get_gss_name(conn, proxy, neg_ctx); + if(ret) + return ret; + } if(!neg_ctx->output_token) { PSecPkgInfo SecurityPackage; @@ -176,9 +177,10 @@ int Curl_input_negotiate(struct connectdata *conn, bool proxy, if(!input_token) return -1; - input_token_len = Curl_base64_decode(header, - (unsigned char **)&input_token); - if(input_token_len == 0) + error = Curl_base64_decode(header, + (unsigned char **)&input_token, + &input_token_len); + if(error || input_token_len == 0) return -1; } @@ -238,16 +240,19 @@ CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy) struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg: &conn->data->state.negotiate; char *encoded = NULL; - size_t len; + size_t len = 0; char *userp; + CURLcode error; - len = Curl_base64_encode(conn->data, - (const char*)neg_ctx->output_token, - neg_ctx->output_token_length, - &encoded); + error = Curl_base64_encode(conn->data, + (const char*)neg_ctx->output_token, + neg_ctx->output_token_length, + &encoded, &len); + if(error) + return error; if(len == 0) - return CURLE_OUT_OF_MEMORY; + return CURLE_REMOTE_ACCESS_DENIED; userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "", neg_ctx->protocol, encoded); diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c deleted file mode 100644 index c3ceadc35..000000000 --- a/lib/http_ntlm.c +++ /dev/null @@ -1,1329 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://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. - * - ***************************************************************************/ -#include "setup.h" - -/* NTLM details: - - http://davenport.sourceforge.net/ntlm.html - http://www.innovation.ch/java/ntlm.html -*/ - -#ifndef CURL_DISABLE_HTTP -#ifdef USE_NTLM - -#define DEBUG_ME 0 - -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - -#if (defined(NETWARE) && !defined(__NOVELL_LIBC__)) -#include <netdb.h> -#endif - -#include "urldata.h" -#include "non-ascii.h" /* for Curl_convert_... prototypes */ -#include "sendf.h" -#include "rawstr.h" -#include "curl_base64.h" -#include "http_ntlm.h" -#include "url.h" -#include "curl_gethostname.h" -#include "curl_memory.h" - -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - -/* "NTLMSSP" signature is always in ASCII regardless of the platform */ -#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50" - -#ifdef USE_SSLEAY -#include "ssluse.h" -# ifdef USE_OPENSSL -# include <openssl/des.h> -# ifndef OPENSSL_NO_MD4 -# include <openssl/md4.h> -# endif -# include <openssl/md5.h> -# include <openssl/ssl.h> -# include <openssl/rand.h> -# else -# include <des.h> -# ifndef OPENSSL_NO_MD4 -# include <md4.h> -# endif -# include <md5.h> -# include <ssl.h> -# include <rand.h> -# endif - -#ifndef OPENSSL_VERSION_NUMBER -#error "OPENSSL_VERSION_NUMBER not defined" -#endif - -#if OPENSSL_VERSION_NUMBER < 0x00907001L -#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 - -/* This is how things were done in the old days */ -#define DESKEY(x) x -#define DESKEYARG(x) x -#else -/* Modern version */ -#define DESKEYARG(x) *x -#define DESKEY(x) &x -#endif - -#ifdef OPENSSL_NO_MD4 -/* This requires MD4, but OpenSSL was compiled without it */ -#define USE_NTRESPONSES 0 -#define USE_NTLM2SESSION 0 -#endif - -#elif defined(USE_GNUTLS) - -#include "gtls.h" -#include <gcrypt.h> - -#define MD5_DIGEST_LENGTH 16 -#define MD4_DIGEST_LENGTH 16 - -#elif defined(USE_NSS) - -#include "curl_md4.h" -#include "nssg.h" -#include <nss.h> -#include <pk11pub.h> -#include <hasht.h> -#define MD5_DIGEST_LENGTH MD5_LENGTH - -#elif defined(USE_WINDOWS_SSPI) - -#include "curl_sspi.h" - -#else -# error "Can't compile NTLM support without a crypto library." -#endif - -/* The last #include file should be: */ -#include "memdebug.h" - -#ifndef USE_NTRESPONSES -/* Define this to make the type-3 message include the NT response message */ -#define USE_NTRESPONSES 1 - -/* Define this to make the type-3 message include the NTLM2Session response - message, requires USE_NTRESPONSES. */ -#define USE_NTLM2SESSION 1 -#endif - -#ifndef USE_WINDOWS_SSPI -/* this function converts from the little endian format used in the incoming - package to whatever endian format we're using natively */ -static unsigned int readint_le(unsigned char *buf) /* must point to a - 4 bytes buffer*/ -{ - return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) | - ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24); -} -#endif - -#if DEBUG_ME -# define DEBUG_OUT(x) x -static void 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_NETWARE) - fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE "); - 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 print_hex(FILE *handle, const char *buf, size_t len) -{ - const char *p = buf; - fprintf(stderr, "0x"); - while(len-- > 0) - fprintf(stderr, "%02.2x", (unsigned int)*p++); -} -#else -# define DEBUG_OUT(x) -#endif - -/* - (*) = A "security buffer" is a triplet consisting of two shorts and one - long: - - 1. a 'short' containing the length of the buffer 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 from the - beginning of the NTLM message, in bytes. -*/ - - -CURLntlm Curl_input_ntlm(struct connectdata *conn, - 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; -#ifndef USE_WINDOWS_SSPI - static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 }; -#endif - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLNTLM_BAD; -#endif - - ntlm = proxy?&conn->proxyntlm:&conn->ntlm; - - /* skip initial whitespaces */ - while(*header && ISSPACE(*header)) - header++; - - if(checkprefix("NTLM", header)) { - header += strlen("NTLM"); - - while(*header && ISSPACE(*header)) - header++; - - if(*header) { - /* We got a type-2 message here: - - 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 (optional) 8 bytes (two consecutive longs) - (40) Target Information (optional) security buffer(*) - 32 (48) start of data block - */ - size_t size; - unsigned char *buffer; - size = Curl_base64_decode(header, &buffer); - if(!buffer) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE2; /* we got a type-2 */ - -#ifdef USE_WINDOWS_SSPI - ntlm->type_2 = malloc(size+1); - if(ntlm->type_2 == NULL) { - free(buffer); - return CURLE_OUT_OF_MEMORY; - } - ntlm->n_type_2 = size; - memcpy(ntlm->type_2, buffer, size); -#else - ntlm->flags = 0; - - if((size < 32) || - (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) || - (memcmp(buffer+8, type2_marker, sizeof(type2_marker)) != 0)) { - /* This was not a good enough type-2 message */ - free(buffer); - return CURLNTLM_BAD; - } - - ntlm->flags = readint_le(&buffer[20]); - memcpy(ntlm->nonce, &buffer[24], 8); - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n nonce="); - print_hex(stderr, (char *)ntlm->nonce, 8); - fprintf(stderr, "\n****\n"); - fprintf(stderr, "**** Header %s\n ", header); - }); -#endif - free(buffer); - } - else { - if(ntlm->state >= NTLMSTATE_TYPE1) - return CURLNTLM_BAD; - - ntlm->state = NTLMSTATE_TYPE1; /* we should sent away a type-1 */ - } - } - return CURLNTLM_FINE; -} - -#ifndef USE_WINDOWS_SSPI - -#ifdef USE_SSLEAY -/* - * 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; - - 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); - - DES_set_odd_parity(&key); - DES_set_key(&key, ks); -} - -#else /* defined(USE_SSLEAY) */ - -/* - * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS. - */ -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); -} - -#if defined(USE_GNUTLS) - -/* - * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. - */ -static void setup_des_key(const unsigned char *key_56, - gcry_cipher_hd_t *des) -{ - char key[8]; - extend_key_56_to_64(key_56, key); - gcry_cipher_setkey(*des, key, 8); -} - -#elif defined(USE_NSS) - -/* - * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using - * the expanded key. The caller is responsible for giving 64 bit of valid - * data is IN and (at least) 64 bit large buffer as OUT. - */ -static bool encrypt_des(const unsigned char *in, unsigned char *out, - const unsigned char *key_56) -{ - const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */ - PK11SlotInfo *slot = NULL; - char key[8]; /* expanded 64 bit key */ - SECItem key_item; - PK11SymKey *symkey = NULL; - SECItem *param = NULL; - PK11Context *ctx = NULL; - int out_len; /* not used, required by NSS */ - bool rv = FALSE; - - /* use internal slot for DES encryption (requires NSS to be initialized) */ - slot = PK11_GetInternalKeySlot(); - if(!slot) - return FALSE; - - /* expand the 56 bit key to 64 bit and wrap by NSS */ - extend_key_56_to_64(key_56, key); - key_item.data = (unsigned char *)key; - key_item.len = /* hard-wired */ 8; - symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT, - &key_item, NULL); - if(!symkey) - goto fail; - - /* create DES encryption context */ - param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL); - if(!param) - goto fail; - ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param); - if(!ctx) - goto fail; - - /* perform the encryption */ - if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8, - (unsigned char *)in, /* inbuflen */ 8) - && SECSuccess == PK11_Finalize(ctx)) - rv = /* all OK */ TRUE; - -fail: - /* cleanup */ - if(ctx) - PK11_DestroyContext(ctx, PR_TRUE); - if(symkey) - PK11_FreeSymKey(symkey); - if(param) - SECITEM_FreeItem(param, PR_TRUE); - PK11_FreeSlot(slot); - return rv; -} - -#endif /* defined(USE_NSS) */ - -#endif /* defined(USE_SSLEAY) */ - - /* - * 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. - */ -static void lm_resp(const unsigned char *keys, - const unsigned char *plaintext, - unsigned char *results) -{ -#ifdef USE_SSLEAY - 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) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys, &des); - gcry_cipher_encrypt(des, results, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+7, &des); - gcry_cipher_encrypt(des, results+8, 8, plaintext, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(keys+14, &des); - gcry_cipher_encrypt(des, results+16, 8, plaintext, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(plaintext, results, keys); - encrypt_des(plaintext, results+8, keys+7); - encrypt_des(plaintext, results+16, keys+14); -#endif -} - - -/* - * Set up lanmanager hashed password - */ -static void mk_lm_hash(struct SessionHandle *data, - const char *password, - unsigned char *lmbuffer /* 21 bytes */) -{ - CURLcode res; - unsigned char pw[14]; - static const unsigned char magic[] = { - 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */ - }; - size_t len = CURLMIN(strlen(password), 14); - - Curl_strntoupper((char *)pw, password, len); - memset(&pw[len], 0, 14-len); - - /* - * The LanManager hashed password needs to be created using the - * password in the network encoding not the host encoding. - */ - res = Curl_convert_to_network(data, (char *)pw, 14); - if(res) - return; - - { - /* Create LanManager hashed password. */ - -#ifdef USE_SSLEAY - 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) - gcry_cipher_hd_t des; - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw, &des); - gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8); - gcry_cipher_close(des); - - gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0); - setup_des_key(pw+7, &des); - gcry_cipher_encrypt(des, lmbuffer+8, 8, magic, 8); - gcry_cipher_close(des); -#elif defined(USE_NSS) - encrypt_des(magic, lmbuffer, pw); - encrypt_des(magic, lmbuffer+8, pw+7); -#endif - - memset(lmbuffer + 16, 0, 21 - 16); - } -} - -#if USE_NTRESPONSES -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'; - } -} - -/* - * Set up nt hashed passwords - */ -static CURLcode mk_nt_hash(struct SessionHandle *data, - const char *password, - unsigned char *ntbuffer /* 21 bytes */) -{ - size_t len = strlen(password); - unsigned char *pw = malloc(len*2); - CURLcode result; - if(!pw) - return CURLE_OUT_OF_MEMORY; - - ascii_to_unicode_le(pw, password, len); - - /* - * The NT hashed password needs to be created using the password in the - * network encoding not the host encoding. - */ - result = Curl_convert_to_network(data, (char *)pw, len*2); - if(result) - return result; - - { - /* Create NT hashed password. */ -#ifdef USE_SSLEAY - MD4_CTX MD4pw; - MD4_Init(&MD4pw); - MD4_Update(&MD4pw, pw, 2*len); - MD4_Final(ntbuffer, &MD4pw); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD4pw; - gcry_md_open(&MD4pw, GCRY_MD_MD4, 0); - gcry_md_write(MD4pw, pw, 2*len); - memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH); - gcry_md_close(MD4pw); -#elif defined(USE_NSS) - Curl_md4it(ntbuffer, pw, 2*len); -#endif - - memset(ntbuffer + 16, 0, 21 - 16); - } - - free(pw); - return CURLE_OK; -} -#endif - - -#endif - -#ifdef USE_WINDOWS_SSPI - -static void -ntlm_sspi_cleanup(struct ntlmdata *ntlm) -{ - if(ntlm->type_2) { - free(ntlm->type_2); - ntlm->type_2 = NULL; - } - if(ntlm->has_handles) { - s_pSecFn->DeleteSecurityContext(&ntlm->c_handle); - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - ntlm->has_handles = 0; - } - if(ntlm->p_identity) { - if(ntlm->identity.User) free(ntlm->identity.User); - if(ntlm->identity.Password) free(ntlm->identity.Password); - if(ntlm->identity.Domain) free(ntlm->identity.Domain); - ntlm->p_identity = NULL; - } -} - -#endif - -#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff) -#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8)&0xff), \ - (((x) >>16)&0xff), (((x)>>24) & 0xff) - -#define HOSTNAME_MAX 1024 - -#ifndef USE_WINDOWS_SSPI -/* 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'; - } -} -#endif - -/* this is for creating ntlm header output */ -CURLcode Curl_output_ntlm(struct connectdata *conn, - bool proxy) -{ - const char *domain=""; /* empty */ - char host [HOSTNAME_MAX+ 1] = ""; /* empty */ -#ifndef USE_WINDOWS_SSPI - size_t domlen = strlen(domain); - size_t hostlen = strlen(host); - size_t hostoff; /* host name offset */ - size_t domoff; /* domain name offset */ -#endif - size_t size; - char *base64=NULL; - unsigned char ntlmbuf[1024]; /* enough, unless the user+host+domain is very - long */ - - /* point to the address of the pointer that holds the string to sent to the - server, which is for a plain host or for a 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 ntlmdata *ntlm; - struct auth *authp; - - DEBUGASSERT(conn); - DEBUGASSERT(conn->data); - -#ifdef USE_NSS - if(CURLE_OK != Curl_nss_force_init(conn->data)) - return CURLE_OUT_OF_MEMORY; -#endif - - if(proxy) { - allocuserpwd = &conn->allocptr.proxyuserpwd; - userp = conn->proxyuser; - passwdp = conn->proxypasswd; - ntlm = &conn->proxyntlm; - authp = &conn->data->state.authproxy; - } - else { - allocuserpwd = &conn->allocptr.userpwd; - userp = conn->user; - passwdp = conn->passwd; - ntlm = &conn->ntlm; - authp = &conn->data->state.authhost; - } - authp->done = FALSE; - - /* not set means empty */ - if(!userp) - userp=""; - - if(!passwdp) - passwdp=""; - -#ifdef USE_WINDOWS_SSPI - if(s_hSecDll == NULL) { - /* not thread safe and leaks - use curl_global_init() to avoid */ - CURLcode err = Curl_sspi_global_init(); - if(s_hSecDll == NULL) - return err; - } -#endif - - switch(ntlm->state) { - case NTLMSTATE_TYPE1: - default: /* for the weird cases we (re)start here */ -#ifdef USE_WINDOWS_SSPI - { - SecBuffer buf; - SecBufferDesc desc; - SECURITY_STATUS status; - ULONG attrs; - const char *user; - int domlen; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - ntlm_sspi_cleanup(ntlm); - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = user - userp; - user++; - } - else { - user = userp; - domain = ""; - domlen = 0; - } - - if(user && *user) { - /* note: initialize all of this before doing the mallocs so that - * it can be cleaned up later without leaking memory. - */ - ntlm->p_identity = &ntlm->identity; - memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity)); - if((ntlm->identity.User = (unsigned char *)strdup(user)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.UserLength = strlen(user); - if((ntlm->identity.Password = (unsigned char *)strdup(passwdp)) == NULL) - return CURLE_OUT_OF_MEMORY; - ntlm->identity.PasswordLength = strlen(passwdp); - if((ntlm->identity.Domain = malloc(domlen+1)) == NULL) - return CURLE_OUT_OF_MEMORY; - strncpy((char *)ntlm->identity.Domain, domain, domlen); - ntlm->identity.Domain[domlen] = '\0'; - ntlm->identity.DomainLength = domlen; - ntlm->identity.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI; - } - else { - ntlm->p_identity = NULL; - } - - if(s_pSecFn->AcquireCredentialsHandleA( - NULL, (char *)"NTLM", SECPKG_CRED_OUTBOUND, NULL, ntlm->p_identity, - NULL, NULL, &ntlm->handle, &tsDummy - ) != SEC_E_OK) { - return CURLE_OUT_OF_MEMORY; - } - - desc.ulVersion = SECBUFFER_VERSION; - desc.cBuffers = 1; - desc.pBuffers = &buf; - buf.cbBuffer = sizeof(ntlmbuf); - buf.BufferType = SECBUFFER_TOKEN; - buf.pvBuffer = ntlmbuf; - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, NULL, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - NULL, 0, - &ntlm->c_handle, &desc, - &attrs, &tsDummy); - - if(status == SEC_I_COMPLETE_AND_CONTINUE || - status == SEC_I_CONTINUE_NEEDED) { - s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc); - } - else if(status != SEC_E_OK) { - s_pSecFn->FreeCredentialsHandle(&ntlm->handle); - return CURLE_RECV_ERROR; - } - - ntlm->has_handles = 1; - size = buf.cbBuffer; - } -#else - hostoff = 0; - domoff = hostoff + hostlen; /* This is 0: remember that host and domain - are empty */ - - /* Create and send a type-1 message: - - 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 start of data block - - */ -#if USE_NTLM2SESSION -#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY -#else -#define NTLM2FLAG 0 -#endif - snprintf((char *)ntlmbuf, sizeof(ntlmbuf), 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| - NTLM2FLAG| - 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 */); - - /* initial packet length */ - size = 32 + hostlen + domlen; -#endif - - 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| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN), - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - print_flags(stderr, - NTLMFLAG_NEGOTIATE_OEM| - NTLMFLAG_REQUEST_TARGET| - NTLMFLAG_NEGOTIATE_NTLM_KEY| - NTLM2FLAG| - NTLMFLAG_NEGOTIATE_ALWAYS_SIGN); - fprintf(stderr, "\n****\n"); - }); - - /* now size is the size of the base64 encoded package size */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - break; - - case NTLMSTATE_TYPE2: - /* We received the type-2 message already, create a type-3 message: - - 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 Domain Name security buffer(*) - 36 User Name security buffer(*) - 44 Workstation Name security buffer(*) - (52) Session Key (optional) security buffer(*) - (60) Flags (optional) long - 52 (64) start of data block - - */ - - { -#ifdef USE_WINDOWS_SSPI - SecBuffer type_2, type_3; - SecBufferDesc type_2_desc, type_3_desc; - SECURITY_STATUS status; - ULONG attrs; - TimeStamp tsDummy; /* For Windows 9x compatibility of SPPI calls */ - - type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION; - type_2_desc.cBuffers = type_3_desc.cBuffers = 1; - type_2_desc.pBuffers = &type_2; - type_3_desc.pBuffers = &type_3; - - type_2.BufferType = SECBUFFER_TOKEN; - type_2.pvBuffer = ntlm->type_2; - type_2.cbBuffer = ntlm->n_type_2; - type_3.BufferType = SECBUFFER_TOKEN; - type_3.pvBuffer = ntlmbuf; - type_3.cbBuffer = sizeof(ntlmbuf); - - status = s_pSecFn->InitializeSecurityContextA(&ntlm->handle, - &ntlm->c_handle, - (char *) host, - ISC_REQ_CONFIDENTIALITY | - ISC_REQ_REPLAY_DETECT | - ISC_REQ_CONNECTION, - 0, SECURITY_NETWORK_DREP, - &type_2_desc, - 0, &ntlm->c_handle, - &type_3_desc, - &attrs, &tsDummy); - - if(status != SEC_E_OK) - return CURLE_RECV_ERROR; - - size = type_3.cbBuffer; - - ntlm_sspi_cleanup(ntlm); - -#else - int lmrespoff; - unsigned char lmresp[24]; /* fixed-size */ -#if USE_NTRESPONSES - int ntrespoff; - unsigned char ntresp[24]; /* fixed-size */ -#endif - bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE)?TRUE:FALSE; - size_t useroff; - const char *user; - size_t userlen; - CURLcode res; - - user = strchr(userp, '\\'); - if(!user) - user = strchr(userp, '/'); - - if(user) { - domain = userp; - domlen = (user - domain); - user++; - } - else - user = userp; - userlen = strlen(user); - - if(Curl_gethostname(host, HOSTNAME_MAX)) { - infof(conn->data, "gethostname() failed, continuing without!"); - hostlen = 0; - } - else { - /* If the workstation if configured with a full DNS name (i.e. - * workstation.somewhere.net) gethostname() returns the fully qualified - * name, which NTLM doesn't like. - */ - char *dot = strchr(host, '.'); - if(dot) - *dot = '\0'; - hostlen = strlen(host); - } - - if(unicode) { - domlen = domlen * 2; - userlen = userlen * 2; - hostlen = hostlen * 2; - } - -#if USE_NTLM2SESSION - /* We don't support NTLM2 if we don't have USE_NTRESPONSES */ - if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) { - unsigned char ntbuffer[0x18]; - unsigned char tmp[0x18]; - unsigned char md5sum[MD5_DIGEST_LENGTH]; - unsigned char entropy[8]; - - /* Need to create 8 bytes random data */ -#ifdef USE_SSLEAY - MD5_CTX MD5pw; - Curl_ossl_seed(conn->data); /* Initiate the seed if not already done */ - RAND_bytes(entropy,8); -#elif defined(USE_GNUTLS) - gcry_md_hd_t MD5pw; - Curl_gtls_seed(conn->data); /* Initiate the seed if not already done */ - gcry_randomize(entropy, 8, GCRY_STRONG_RANDOM); -#elif defined(USE_NSS) - PK11Context *MD5pw; - unsigned int outlen; - Curl_nss_seed(conn->data); /* Initiate the seed if not already done */ - PK11_GenerateRandom(entropy, 8); -#endif - - /* 8 bytes random data as challenge in lmresp */ - memcpy(lmresp,entropy,8); - /* Pad with zeros */ - memset(lmresp+8,0,0x10); - - /* Fill tmp with challenge(nonce?) + entropy */ - memcpy(tmp,&ntlm->nonce[0],8); - memcpy(tmp+8,entropy,8); - -#ifdef USE_SSLEAY - MD5_Init(&MD5pw); - MD5_Update(&MD5pw, tmp, 16); - MD5_Final(md5sum, &MD5pw); -#elif defined(USE_GNUTLS) - gcry_md_open(&MD5pw, GCRY_MD_MD5, 0); - gcry_md_write(MD5pw, tmp, MD5_DIGEST_LENGTH); - memcpy(md5sum, gcry_md_read (MD5pw, 0), MD5_DIGEST_LENGTH); - gcry_md_close(MD5pw); -#elif defined(USE_NSS) - MD5pw = PK11_CreateDigestContext(SEC_OID_MD5); - PK11_DigestOp(MD5pw, tmp, 16); - PK11_DigestFinal(MD5pw, md5sum, &outlen, MD5_DIGEST_LENGTH); - PK11_DestroyContext(MD5pw, PR_TRUE); -#endif - - /* We shall only use the first 8 bytes of md5sum, - but the des code in lm_resp only encrypt the first 8 bytes */ - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, md5sum, ntresp); - - /* End of NTLM2 Session code */ - } - else -#endif - { - -#if USE_NTRESPONSES - unsigned char ntbuffer[0x18]; -#endif - unsigned char lmbuffer[0x18]; - -#if USE_NTRESPONSES - if(mk_nt_hash(conn->data, passwdp, ntbuffer) == CURLE_OUT_OF_MEMORY) - return CURLE_OUT_OF_MEMORY; - lm_resp(ntbuffer, &ntlm->nonce[0], ntresp); -#endif - - mk_lm_hash(conn->data, passwdp, lmbuffer); - lm_resp(lmbuffer, &ntlm->nonce[0], lmresp); - /* A safer but less compatible alternative is: - * lm_resp(ntbuffer, &ntlm->nonce[0], lmresp); - * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */ - } - - lmrespoff = 64; /* size of the message header */ -#if USE_NTRESPONSES - ntrespoff = lmrespoff + 0x18; - domoff = ntrespoff + 0x18; -#else - domoff = lmrespoff + 0x18; -#endif - useroff = domoff + domlen; - hostoff = useroff + userlen; - - /* Create the big type-3 message binary blob */ - size = snprintf((char *)ntlmbuf, sizeof(ntlmbuf), - NTLMSSP_SIGNATURE "%c" - "\x03%c%c%c" /* type-3, 32 bits */ - - "%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, /* zero termination */ - 0,0,0, /* type-3 long, the 24 upper bits */ - - SHORTPAIR(0x18), /* LanManager response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(lmrespoff), - 0x0, 0x0, - -#if USE_NTRESPONSES - SHORTPAIR(0x18), /* NT-response length, twice */ - SHORTPAIR(0x18), - SHORTPAIR(ntrespoff), - 0x0, 0x0, -#else - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, - 0x0, 0x0, -#endif - 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 < (sizeof(ntlmbuf) - 0x18)) { - memcpy(&ntlmbuf[size], lmresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "**** TYPE3 header lmresp="); - print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18); - }); - -#if USE_NTRESPONSES - if(size < (sizeof(ntlmbuf) - 0x18)) { - DEBUGASSERT(size == (size_t)ntrespoff); - memcpy(&ntlmbuf[size], ntresp, 0x18); - size += 0x18; - } - - DEBUG_OUT({ - fprintf(stderr, "\n ntresp="); - print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18); - }); - -#endif - - DEBUG_OUT({ - fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ", - LONGQUARTET(ntlm->flags), ntlm->flags); - print_flags(stderr, ntlm->flags); - fprintf(stderr, "\n****\n"); - }); - - - /* Make sure that the domain, user and host strings fit in the target - buffer before we copy them there. */ - if(size + userlen + domlen + hostlen >= sizeof(ntlmbuf)) { - failf(conn->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; - - /* convert domain, user, and host to ASCII but leave the rest as-is */ - res = Curl_convert_to_network(conn->data, (char *)&ntlmbuf[domoff], - size-domoff); - if(res) - return CURLE_CONV_FAILED; - -#endif - - /* convert the binary blob into base64 */ - size = Curl_base64_encode(NULL, (char *)ntlmbuf, size, &base64); - - if(size >0 ) { - Curl_safefree(*allocuserpwd); - *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n", - proxy?"Proxy-":"", - base64); - DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd)); - free(base64); - } - else - return CURLE_OUT_OF_MEMORY; /* FIX TODO */ - - ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */ - authp->done = TRUE; - } - break; - - case NTLMSTATE_TYPE3: - /* connection is already authenticated, - * don't send a header in future requests */ - if(*allocuserpwd) { - free(*allocuserpwd); - *allocuserpwd=NULL; - } - authp->done = TRUE; - break; - } - - return CURLE_OK; -} - - -void -Curl_ntlm_cleanup(struct connectdata *conn) -{ -#ifdef USE_WINDOWS_SSPI - ntlm_sspi_cleanup(&conn->ntlm); - ntlm_sspi_cleanup(&conn->proxyntlm); -#else - (void)conn; -#endif -} - - -#endif /* USE_NTLM */ -#endif /* !CURL_DISABLE_HTTP */ diff --git a/lib/http_proxy.c b/lib/http_proxy.c index 9fa832e4d..f3b02c975 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -27,6 +27,7 @@ #ifdef HAVE_UNISTD_H #include <unistd.h> #endif + #include "urldata.h" #include <curl/curl.h> #include "http_proxy.h" diff --git a/lib/idn_win32.c b/lib/idn_win32.c index 96d3f0959..70286c0fd 100644 --- a/lib/idn_win32.c +++ b/lib/idn_win32.c @@ -19,13 +19,15 @@ * KIND, either express or implied. * ***************************************************************************/ -/*************************************************************************** - * IDN Implementation using windows native APIs - * Pierre Joye <pierre@php.net> - ***************************************************************************/ -#if defined(WIN32) && defined(USE_WIN32_IDN) -#include <windows.h> -#include <stdio.h> + + /* + * IDN conversions using Windows kernel32 and normaliz libraries. + */ + +#include "setup.h" + +#ifdef USE_WIN32_IDN + #include <tchar.h> #ifdef WANT_IDN_PROTOTYPES @@ -121,7 +123,5 @@ int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8) } return 1; } -#else -typedef int dummy; /* because ISO C forbids an empty translation unit! */ -#endif - /* WIN32 */ + +#endif /* USE_WIN32_IDN */ diff --git a/lib/imap.c b/lib/imap.c index b135443d3..986b79a56 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -26,11 +26,6 @@ #include "setup.h" #ifndef CURL_DISABLE_IMAP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -124,6 +119,7 @@ const struct Curl_handler Curl_handler_imap = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -149,6 +145,7 @@ const struct Curl_handler Curl_handler_imaps = { imap_doing, /* doing */ imap_getsock, /* proto_getsock */ imap_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ imap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -174,6 +171,7 @@ static const struct Curl_handler Curl_handler_imap_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -199,6 +197,7 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -215,9 +214,6 @@ static const struct Curl_handler Curl_handler_imaps_proxy = { * * Sends the formated string as an IMAP command to a server * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * Designed to never block. */ static CURLcode imapsendf(struct connectdata *conn, @@ -343,7 +339,7 @@ static void imap_to_imaps(struct connectdata *conn) conn->handler = &Curl_handler_imaps; } #else -#define imap_to_imaps(x) +#define imap_to_imaps(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -638,7 +634,7 @@ static CURLcode imap_multi_statemach(struct connectdata *conn, else result = Curl_pp_multi_statemach(&imapc->pp); - *done = (bool)(imapc->state == IMAP_STOP); + *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE; return result; } @@ -846,7 +842,7 @@ CURLcode imap_perform(struct connectdata *conn, result = imap_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/inet_ntop.c b/lib/inet_ntop.c index 34cae801a..1bb97443b 100644 --- a/lib/inet_ntop.c +++ b/lib/inet_ntop.c @@ -34,8 +34,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#include <string.h> -#include <errno.h> #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> diff --git a/lib/inet_pton.c b/lib/inet_pton.c index d08c7c666..021f48d52 100644 --- a/lib/inet_pton.c +++ b/lib/inet_pton.c @@ -32,8 +32,6 @@ #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif -#include <string.h> -#include <errno.h> #include "inet_pton.h" diff --git a/lib/krb4.c b/lib/krb4.c index 7da47f31f..b53a6104c 100644 --- a/lib/krb4.c +++ b/lib/krb4.c @@ -44,11 +44,9 @@ #ifndef CURL_DISABLE_FTP #ifdef HAVE_KRB4 -#include <stdlib.h> #ifdef HAVE_NETDB_H #include <netdb.h> #endif -#include <string.h> #include <krb.h> #include <des.h> @@ -203,7 +201,7 @@ krb4_auth(void *app_data, struct connectdata *conn) int ret; char *p; unsigned char *ptr; - size_t len; + size_t len = 0; KTEXT_ST adat; MSG_DAT msg_data; int checksum; @@ -214,6 +212,7 @@ krb4_auth(void *app_data, struct connectdata *conn) int l = sizeof(conn->local_addr); struct SessionHandle *data = conn->data; CURLcode result; + size_t base64_sz = 0; if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)LOCAL_ADDR, &l) < 0) @@ -249,8 +248,10 @@ krb4_auth(void *app_data, struct connectdata *conn) } #endif - if(Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, &p) < 1) { - Curl_failf(data, "Out of memory base64-encoding"); + result = Curl_base64_encode(conn->data, (char *)adat.dat, adat.length, + &p, &base64_sz); + if(result) { + Curl_failf(data, "base64-encoding: %s", curl_easy_strerror(result)); return AUTH_CONTINUE; } @@ -264,7 +265,7 @@ krb4_auth(void *app_data, struct connectdata *conn) if(Curl_GetFTPResponse(&nread, conn, NULL)) return -1; - if(data->state.buffer[0] != '2'){ + if(data->state.buffer[0] != '2') { Curl_failf(data, "Server didn't accept auth data"); return AUTH_ERROR; } @@ -275,10 +276,15 @@ krb4_auth(void *app_data, struct connectdata *conn) return AUTH_ERROR; } p += 5; - len = Curl_base64_decode(p, &ptr); + result = Curl_base64_decode(p, &ptr, &len); + if(result) { + Curl_failf(data, "base64-decoding: %s", curl_easy_strerror(result)); + return AUTH_ERROR; + } if(len > sizeof(adat.dat)-1) { free(ptr); - len=0; + ptr = NULL; + len = 0; } if(!len || !ptr) { Curl_failf(data, "Failed to decode base64 from server"); @@ -332,11 +338,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) char *name; char *p; char passwd[100]; - size_t tmp; + size_t tmp = 0; ssize_t nread; enum protection_level save; CURLcode result; unsigned char *ptr; + size_t base64_sz = 0; save = krb4_set_command_prot(conn, PROT_PRIVATE); @@ -349,7 +356,7 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) if(result) return result; - if(conn->data->state.buffer[0] != '3'){ + if(conn->data->state.buffer[0] != '3') { krb4_set_command_prot(conn, save); return CURLE_FTP_WEIRD_SERVER_REPLY; } @@ -362,10 +369,15 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) } p += 2; - tmp = Curl_base64_decode(p, &ptr); + result = Curl_base64_decode(p, &ptr, &tmp); + if(result) { + Curl_failf(conn->data, "base64-decoding: %s", curl_easy_strerror(result)); + return result; + } if(tmp >= sizeof(tkt.dat)) { free(ptr); - tmp=0; + ptr = NULL; + tmp = 0; } if(!tmp || !ptr) { Curl_failf(conn->data, "Failed to decode base64 in reply"); @@ -406,11 +418,12 @@ CURLcode Curl_krb_kauth(struct connectdata *conn) memset(key, 0, sizeof(key)); memset(schedule, 0, sizeof(schedule)); memset(passwd, 0, sizeof(passwd)); - if(Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, &p) - < 1) { - failf(conn->data, "Out of memory base64-encoding."); + result = Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length, + &p, &base64_sz); + if(result) { + Curl_failf(conn->data, "base64-encoding: %s", curl_easy_strerror(result)); krb4_set_command_prot(conn, save); - return CURLE_OUT_OF_MEMORY; + return result; } memset (tktcopy.dat, 0, tktcopy.length); diff --git a/lib/krb5.c b/lib/krb5.c index f128d515f..96938dd6e 100644 --- a/lib/krb5.c +++ b/lib/krb5.c @@ -39,29 +39,17 @@ #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif -#include <stdlib.h> #ifdef HAVE_NETDB_H #include <netdb.h> #endif -#include <string.h> - -#ifdef HAVE_GSSGNU -# include <gss.h> -#elif defined HAVE_GSSMIT - /* MIT style */ -# include <gssapi/gssapi.h> -# include <gssapi/gssapi_generic.h> -# include <gssapi/gssapi_krb5.h> -#else - /* Heimdal-style */ -# include <gssapi.h> -#endif #include "urldata.h" #include "curl_base64.h" #include "ftp.h" +#include "curl_gssapi.h" #include "sendf.h" #include "krb4.h" #include "curl_memory.h" @@ -94,16 +82,16 @@ krb5_check_prot(void *app_data, int level) } static int -krb5_decode(void *app_data, void *buf, int len, int level, - struct connectdata *conn) +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; - /* shut gcc up */ - level = 0; - conn = NULL; + (void)level; + (void)conn; enc.value = buf; enc.length = len; @@ -133,7 +121,7 @@ krb5_overhead(void *app_data, int level, int len) static int krb5_encode(void *app_data, const void *from, int length, int level, void **to, - struct connectdata *conn) + struct connectdata *conn UNUSED_PARAM) { gss_ctx_id_t *context = app_data; gss_buffer_desc dec, enc; @@ -184,6 +172,7 @@ krb5_auth(void *app_data, struct connectdata *conn) gss_name_t gssname; gss_ctx_id_t *context = app_data; struct gss_channel_bindings_struct chan; + size_t base64_sz = 0; if(getsockname(conn->sock[FIRSTSOCKET], (struct sockaddr *)LOCAL_ADDR, &l) < 0) @@ -201,7 +190,7 @@ krb5_auth(void *app_data, struct connectdata *conn) chan.application_data.value = NULL; /* this loop will execute twice (once for service, once for host) */ - while(1) { + for(;;) { /* this really shouldn't be repeated here, but can't help it */ if(service == srv_host) { result = Curl_ftpsendf(conn, "AUTH GSSAPI"); @@ -242,19 +231,14 @@ krb5_auth(void *app_data, struct connectdata *conn) taken care by a final gss_release_buffer. */ gss_release_buffer(&min, &output_buffer); ret = AUTH_OK; - maj = gss_init_sec_context(&min, - GSS_C_NO_CREDENTIAL, - context, - gssname, - GSS_C_NO_OID, - GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG, - 0, - &chan, - gssresp, - NULL, - &output_buffer, - NULL, - NULL); + maj = Curl_gss_init_sec_context(data, + &min, + context, + gssname, + &chan, + gssresp, + &output_buffer, + NULL); if(gssresp) { free(_gssresp.value); @@ -268,9 +252,10 @@ krb5_auth(void *app_data, struct connectdata *conn) } if(output_buffer.length != 0) { - if(Curl_base64_encode(data, (char *)output_buffer.value, - output_buffer.length, &p) < 1) { - Curl_infof(data, "Out of memory base64-encoding\n"); + result = Curl_base64_encode(data, (char *)output_buffer.value, + output_buffer.length, &p, &base64_sz); + if(result) { + Curl_infof(data,"base64-encoding: %s\n", curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } @@ -289,7 +274,7 @@ krb5_auth(void *app_data, struct connectdata *conn) break; } - if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3'){ + if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') { Curl_infof(data, "Server didn't accept auth data\n"); ret = AUTH_ERROR; break; @@ -298,10 +283,11 @@ krb5_auth(void *app_data, struct connectdata *conn) p = data->state.buffer + 4; p = strstr(p, "ADAT="); if(p) { - _gssresp.length = Curl_base64_decode(p + 5, (unsigned char **) - &_gssresp.value); - if(_gssresp.length < 1) { - Curl_failf(data, "Out of memory base64-encoding\n"); + result = Curl_base64_decode(p + 5, + (unsigned char **)&_gssresp.value, + &_gssresp.length); + if(result) { + Curl_failf(data,"base64-decoding: %s", curl_easy_strerror(result)); ret = AUTH_CONTINUE; break; } diff --git a/lib/ldap.c b/lib/ldap.c index 62a9ffc19..737847649 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -35,14 +35,6 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - #ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */ # include <winldap.h> # ifndef LDAP_VENDOR_NAME @@ -113,11 +105,11 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp); #define LDAP_TRACE(x) do { \ _ldap_trace ("%u: ", __LINE__); \ _ldap_trace x; \ - } while(0) + } WHILE_FALSE static void _ldap_trace (const char *fmt, ...); #else - #define LDAP_TRACE(x) ((void)0) + #define LDAP_TRACE(x) Curl_nop_stmt #endif @@ -138,6 +130,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -162,6 +155,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -184,9 +178,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) struct SessionHandle *data=conn->data; int ldap_proto = LDAP_VERSION3; int ldap_ssl = 0; - char *val_b64; - size_t val_b64_sz; - curl_off_t dlsize=0; + char *val_b64 = NULL; + size_t val_b64_sz = 0; + curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ #endif @@ -413,10 +407,20 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) (char *)attribute + (strlen((char *)attribute) - 7)) == 0)) { /* Binary attribute, encode to base64. */ - val_b64_sz = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64); + CURLcode error = Curl_base64_encode(data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64, + &val_b64_sz); + if(error) { + ldap_value_free_len(vals); + ldap_memfree(attribute); + ldap_memfree(dn); + if(ber) + ber_free(ber, 0); + status = error; + goto quit; + } if(val_b64_sz > 0) { Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); free(val_b64); diff --git a/lib/libcurl.imp b/lib/libcurl.imp index 74943afa7..7c99a9468 100644 --- a/lib/libcurl.imp +++ b/lib/libcurl.imp @@ -9,6 +9,8 @@ curl_easy_init, curl_easy_pause, curl_easy_perform, + curl_easy_recv, + curl_easy_send, curl_easy_setopt, curl_escape, curl_unescape, @@ -38,6 +40,8 @@ curl_multi_perform, curl_multi_cleanup, curl_multi_info_read, + curl_multi_setopt, + curl_multi_timeout, curl_free, curl_version_info, curl_share_init, diff --git a/lib/llist.c b/lib/llist.c index 8b4bc7f20..a302e32d5 100644 --- a/lib/llist.c +++ b/lib/llist.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> - #include "llist.h" #include "curl_memory.h" @@ -49,7 +46,7 @@ Curl_llist_alloc(curl_llist_dtor dtor) struct curl_llist *list; list = malloc(sizeof(struct curl_llist)); - if(NULL == list) + if(!list) return NULL; llist_init(list, dtor); @@ -134,6 +131,10 @@ Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e, list->dtor(user, e->ptr); + e->ptr = NULL; + e->prev = NULL; + e->next = NULL; + free(e); --list->size; @@ -27,7 +27,6 @@ #ifdef USE_NSS #include "curl_md4.h" -#include <string.h> typedef unsigned int UINT4; @@ -24,8 +24,6 @@ #ifndef CURL_DISABLE_CRYPTO_AUTH -#include <string.h> - #include "curl_md5.h" #include "curl_hmac.h" diff --git a/lib/memdebug.c b/lib/memdebug.c index 69e204b6a..0b81621cb 100644 --- a/lib/memdebug.c +++ b/lib/memdebug.c @@ -32,10 +32,6 @@ #define _MPRINTF_REPLACE #include <curl/mprintf.h> #include "urldata.h" -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -46,12 +42,59 @@ #include "memdebug.h" #ifndef HAVE_ASSERT_H -# define assert(x) do { } while (0) +# define assert(x) Curl_nop_stmt +#endif + +/* + * Until 2011-08-17 libcurl's Memory Tracking feature also performed + * automatic malloc and free filling operations using 0xA5 and 0x13 + * values. Our own preinitialization of dynamically allocated memory + * might be useful when not using third party memory debuggers, but + * on the other hand this would fool memory debuggers into thinking + * that all dynamically allocated memory is properly initialized. + * + * As a default setting, libcurl's Memory Tracking feature no longer + * performs preinitialization of dynamically allocated memory on its + * own. If you know what you are doing, and really want to retain old + * behavior, you can achieve this compiling with preprocessor symbols + * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate + * values. + */ + +#ifdef CURL_MT_MALLOC_FILL +# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff) +# error "invalid CURL_MT_MALLOC_FILL or out of range" +# endif +#endif + +#ifdef CURL_MT_FREE_FILL +# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff) +# error "invalid CURL_MT_FREE_FILL or out of range" +# endif +#endif + +#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL) +# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL) +# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL" +# endif +#endif + +#ifdef CURL_MT_MALLOC_FILL +# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len)) +#else +# define mt_malloc_fill(buf,len) Curl_nop_stmt +#endif + +#ifdef CURL_MT_FREE_FILL +# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len)) +#else +# define mt_free_fill(buf,len) Curl_nop_stmt #endif struct memdebug { size_t size; union { + curl_off_t o; double d; void * p; } mem[1]; @@ -76,7 +119,7 @@ static long memsize = 0; /* set number of mallocs allowed */ void curl_memdebug(const char *logname) { if(!logfile) { - if(logname) + if(logname && *logname) logfile = fopen(logname, "w"); else logfile = stderr; @@ -144,7 +187,7 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source) mem = (Curl_cmalloc)(size); if(mem) { /* fill memory with junk */ - memset(mem->mem, 0xA5, wantedsize); + mt_malloc_fill(mem->mem, wantedsize); mem->size = wantedsize; } @@ -170,12 +213,9 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size, user_size = wanted_size * wanted_elements; size = sizeof(struct memdebug) + user_size; - mem = (Curl_cmalloc)(size); - if(mem) { - /* fill memory with zeroes */ - memset(mem->mem, 0, user_size); + mem = (Curl_ccalloc)(1, size); + if(mem) mem->size = user_size; - } if(source) curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", @@ -264,8 +304,8 @@ void curl_dofree(void *ptr, int line, const char *source) # pragma warning(pop) #endif - /* destroy */ - memset(mem->mem, 0x13, mem->size); + /* destroy */ + mt_free_fill(mem->mem, mem->size); /* free for real */ (Curl_cfree)(mem); @@ -289,6 +329,24 @@ curl_socket_t curl_socket(int domain, int type, int protocol, return sockfd; } +#ifdef HAVE_SOCKETPAIR +int curl_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line, const char *source) +{ + const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ? + "FD %s:%d socketpair() = %d %d\n" : + (sizeof(curl_socket_t) == sizeof(long)) ? + "FD %s:%d socketpair() = %ld %ld\n" : + "FD %s:%d socketpair() = %zd %zd\n" ; + + int res = socketpair(domain, type, protocol, socket_vector); + if(source && (0 == res)) + curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]); + return res; +} +#endif + curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, int line, const char *source) { diff --git a/lib/memdebug.h b/lib/memdebug.h index 77a4f4774..1e02645f9 100644 --- a/lib/memdebug.h +++ b/lib/memdebug.h @@ -1,6 +1,6 @@ +#ifndef HEADER_CURL_MEMDEBUG_H +#define HEADER_CURL_MEMDEBUG_H #ifdef CURLDEBUG -#ifndef _CURL_MEMDEBUG_H -#define _CURL_MEMDEBUG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -32,14 +32,11 @@ #include <curl/curl.h> -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif -#include <stdio.h> + +#define CURL_MT_LOGFNAME_BUFSIZE 512 #define logfile curl_debuglogfile @@ -66,6 +63,11 @@ CURL_EXTERN int curl_sclose(curl_socket_t sockfd, int line , const char *source); CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen, int line, const char *source); +#ifdef HAVE_SOCKETPAIR +CURL_EXTERN int curl_socketpair(int domain, int type, int protocol, + curl_socket_t socket_vector[2], + int line , const char *source); +#endif /* FILE functions */ CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line, @@ -91,6 +93,10 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #undef accept /* for those with accept as a macro */ #define accept(sock,addr,len)\ curl_accept(sock,addr,len,__LINE__,__FILE__) +#ifdef HAVE_SOCKETPAIR +#define socketpair(domain,type,protocol,socket_vector)\ + curl_socketpair(domain,type,protocol,socket_vector,__LINE__,__FILE__) +#endif #ifdef HAVE_GETADDRINFO #if defined(getaddrinfo) && defined(__osf__) @@ -133,9 +139,23 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); #endif /* MEMDEBUG_NODEFINES */ -#endif /* _CURL_MEMDEBUG_H */ #endif /* CURLDEBUG */ +/* +** Following section applies even when CURLDEBUG is not defined. +*/ + #ifndef fake_sclose -#define fake_sclose(x) +#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 {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE + +#endif /* HEADER_CURL_MEMDEBUG_H */ diff --git a/lib/mk-ca-bundle.pl b/lib/mk-ca-bundle.pl index 231762e60..189ed01b6 100755 --- a/lib/mk-ca-bundle.pl +++ b/lib/mk-ca-bundle.pl @@ -40,7 +40,7 @@ my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/ # If the OpenSSL commandline is not in search path you can configure it here! my $openssl = 'openssl'; -my $version = '1.15'; +my $version = '1.16'; getopts('bhilnqtuv'); @@ -77,15 +77,13 @@ my $resp; unless ($opt_n and -e $txt) { print "Downloading '$txt' ...\n" if (!$opt_q); - my $ua = new LWP::UserAgent(agent => "$0/$version"); $ua->env_proxy(); $resp = $ua->mirror($url, $txt); -} - -if ($resp && $resp->code eq '304') { + if ($resp && $resp->code eq '304') { print "Not modified\n" unless $opt_q; exit 0; + } } my $currentdate = scalar gmtime($resp ? $resp->last_modified : (stat($txt))[9]); @@ -124,6 +122,7 @@ close(CRT) or die "Couldn't close $crt: $!"; print "Processing '$txt' ...\n" if (!$opt_q); my $caname; my $certnum = 0; +my $skipnum = 0; open(TXT,"$txt") or die "Couldn't open $txt: $!"; while (<TXT>) { if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) { @@ -147,6 +146,7 @@ while (<TXT>) { if (/^CKA_LABEL\s+[A-Z0-9]+\s+\"(.*)\"/) { $caname = $1; } + my $untrusted = 0; if (/^CKA_VALUE MULTILINE_OCTAL/) { my $data; while (<TXT>) { @@ -158,28 +158,37 @@ while (<TXT>) { $data .= chr(oct); } } - my $pem = "-----BEGIN CERTIFICATE-----\n" - . MIME::Base64::encode($data) - . "-----END CERTIFICATE-----\n"; - open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; - print CRT "\n$caname\n"; - print CRT ("=" x length($caname) . "\n"); - if (!$opt_t) { - print CRT $pem; + while (<TXT>) { + last if (/^#$/); + $untrusted = 1 if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_NOT_TRUSTED$/ + or /^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUST_UNKNOWN$/); } - close(CRT) or die "Couldn't close $crt: $!"; - if ($opt_t) { - open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; - print TMP $pem; - close(TMP) or die "Couldn't close openssl pipe: $!"; + if ($untrusted) { + $skipnum ++; + } else { + my $pem = "-----BEGIN CERTIFICATE-----\n" + . MIME::Base64::encode($data) + . "-----END CERTIFICATE-----\n"; + open(CRT, ">>$crt") or die "Couldn't open $crt: $!"; + print CRT "\n$caname\n"; + print CRT ("=" x length($caname) . "\n"); + if (!$opt_t) { + print CRT $pem; + } + close(CRT) or die "Couldn't close $crt: $!"; + if ($opt_t) { + open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!"; + print TMP $pem; + close(TMP) or die "Couldn't close openssl pipe: $!"; + } + print "Parsing: $caname\n" if ($opt_v); + $certnum ++; } - print "Parsing: $caname\n" if ($opt_v); - $certnum ++; } } close(TXT) or die "Couldn't close $txt: $!"; unlink $txt if ($opt_u); -print "Done ($certnum CA certs processed).\n" if (!$opt_q); +print "Done ($certnum CA certs processed, $skipnum untrusted skipped).\n" if (!$opt_q); exit; diff --git a/lib/mprintf.c b/lib/mprintf.c index dd7a1e09b..0990f4024 100644 --- a/lib/mprintf.c +++ b/lib/mprintf.c @@ -36,11 +36,6 @@ */ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> -#include <string.h> #if defined(DJGPP) && (DJGPP_MINOR < 4) #undef _MPRINTF_REPLACE /* don't use x_was_used() here */ @@ -108,7 +103,7 @@ static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; done++; \ else \ return done; /* return immediately on failure */ \ - } while(0) + } WHILE_FALSE /* Data type to read from the arglist */ typedef enum { diff --git a/lib/multi.c b/lib/multi.c index aee190cea..6e4ec37a8 100644 --- a/lib/multi.c +++ b/lib/multi.c @@ -41,6 +41,7 @@ #include "sendf.h" #include "timeval.h" #include "http.h" +#include "select.h" #include "warnless.h" #define _MPRINTF_REPLACE /* use our functions only */ @@ -124,9 +125,9 @@ struct Curl_one_easy { #define CURL_MULTI_HANDLE 0x000bab1e #define GOOD_MULTI_HANDLE(x) \ - ((x)&&(((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) + ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE)) #define GOOD_EASY_HANDLE(x) \ - (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER) + ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER)) /* This is the struct known as CURLM on the outside */ struct Curl_multi { @@ -134,7 +135,7 @@ struct Curl_multi { this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */ long type; - /* We have a linked list with easy handles */ + /* We have a doubly-linked circular list with easy handles */ struct Curl_one_easy easy; int num_easy; /* amount of entries in the linked list above. */ @@ -424,12 +425,13 @@ CURLM *curl_multi_init(void) return (CURLM *) multi; error: - if(multi->sockhash) - Curl_hash_destroy(multi->sockhash); - if(multi->hostcache) - Curl_hash_destroy(multi->hostcache); - if(multi->connc) - Curl_rm_connc(multi->connc); + + Curl_hash_destroy(multi->sockhash); + multi->sockhash = NULL; + Curl_hash_destroy(multi->hostcache); + multi->hostcache = NULL; + Curl_rm_connc(multi->connc); + multi->connc = NULL; free(multi); return NULL; @@ -438,11 +440,12 @@ CURLM *curl_multi_init(void) CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle) { - struct Curl_multi *multi=(struct Curl_multi *)multi_handle; + struct curl_llist *timeoutlist; struct Curl_one_easy *easy; struct closure *cl; - struct closure *prev=NULL; - struct SessionHandle *data = easy_handle; + struct closure *prev = NULL; + struct Curl_multi *multi = (struct Curl_multi *)multi_handle; + struct SessionHandle *data = (struct SessionHandle *)easy_handle; /* First, make some basic checks that the CURLM handle is a good handle */ if(!GOOD_MULTI_HANDLE(multi)) @@ -452,39 +455,74 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, if(!GOOD_EASY_HANDLE(easy_handle)) return CURLM_BAD_EASY_HANDLE; - /* Prevent users to add the same handle more than once! */ - if(((struct SessionHandle *)easy_handle)->multi) + /* Prevent users from adding same easy handle more than + once and prevent adding to more than one multi stack */ + if(data->multi) /* possibly we should create a new unique error code for this condition */ return CURLM_BAD_EASY_HANDLE; - data->state.timeoutlist = Curl_llist_alloc(multi_freetimeout); - if(!data->state.timeoutlist) + /* We want the connection cache to have plenty of room. Before we supported + the shared cache every single easy handle had 5 entries in their cache + by default. */ + if(((multi->num_easy + 1) * 4) > multi->connc->num) { + long newmax = (multi->num_easy + 1) * 4; + + if(multi->maxconnects && (newmax > multi->maxconnects)) + /* don't grow beyond the allowed size */ + newmax = multi->maxconnects; + + if(newmax > multi->connc->num) { + /* we only do this is we can in fact grow the cache */ + CURLcode res = Curl_ch_connc(data, multi->connc, newmax); + if(res) + return CURLM_OUT_OF_MEMORY; + } + } + + /* Allocate and initialize timeout list for easy handle */ + timeoutlist = Curl_llist_alloc(multi_freetimeout); + if(!timeoutlist) return CURLM_OUT_OF_MEMORY; - /* Now, time to add an easy handle to the multi stack */ + /* Allocate new node for the doubly-linked circular list of + Curl_one_easy structs that holds pointers to easy handles */ easy = calloc(1, sizeof(struct Curl_one_easy)); - if(!easy) + if(!easy) { + Curl_llist_destroy(timeoutlist, NULL); return CURLM_OUT_OF_MEMORY; + } + + /* + ** 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. + */ + + /* Make easy handle use timeout list initialized above */ + data->state.timeoutlist = timeoutlist; + timeoutlist = NULL; + /* Remove handle from the list of 'closure handles' in case it is there */ cl = multi->closure; while(cl) { struct closure *next = cl->next; - if(cl->easy_handle == (struct SessionHandle *)easy_handle) { - /* remove this handle from the closure list */ + if(cl->easy_handle == data) { + /* Remove node from list */ free(cl); if(prev) prev->next = next; else multi->closure = next; - break; /* no need to continue since this handle can only be present once - in the list */ + /* No need to continue, handle can only be present once in the list */ + break; } prev = cl; cl = next; } /* set the easy handle */ - easy->easy_handle = easy_handle; + easy->easy_handle = data; multistate(easy, CURLM_STATE_INIT); /* set the back pointer to one_easy to assist in removal */ @@ -505,25 +543,21 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, easy->easy_handle->dns.hostcachetype = HCACHE_MULTI; } - if(easy->easy_handle->state.connc) { - if(easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE) { - /* kill old private version */ - Curl_rm_connc(easy->easy_handle->state.connc); - /* point out our shared one instead */ - easy->easy_handle->state.connc = multi->connc; - } - /* else it is already using multi? */ + /* On a multi stack the connection cache, owned by the multi handle, + is shared between all easy handles within the multi handle. */ + if(easy->easy_handle->state.connc && + (easy->easy_handle->state.connc->type == CONNCACHE_PRIVATE)) { + /* kill old private connection cache */ + Curl_rm_connc(easy->easy_handle->state.connc); + easy->easy_handle->state.connc = NULL; } - else - /* point out our shared one */ - easy->easy_handle->state.connc = multi->connc; - - /* Make sure the type is setup correctly */ + /* Point now to this multi's connection cache */ + easy->easy_handle->state.connc = multi->connc; easy->easy_handle->state.connc->type = CONNCACHE_MULTI; - /* This adds the new entry at the back of the list - to try and maintain a FIFO queue so the pipelined - requests are in order. */ + /* This adds the new entry at the 'end' of the doubly-linked circular + list of Curl_one_easy structs to try and maintain a FIFO queue so + the pipelined requests are in order. */ /* We add this new entry last in the list. We make our 'next' point to the 'first' struct and our 'prev' point to the previous 'prev' */ @@ -537,6 +571,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, the new node */ easy->prev->next = easy; + /* make the SessionHandle refer back to this multi handle */ Curl_easy_addmulti(easy_handle, multi_handle); /* make the SessionHandle struct refer back to this struct */ @@ -553,27 +588,6 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, /* increase the node-counter */ multi->num_easy++; - if((multi->num_easy * 4) > multi->connc->num) { - /* We want the connection cache to have plenty room. Before we supported - the shared cache every single easy handle had 5 entries in their cache - by default. */ - long newmax = multi->num_easy * 4; - - if(multi->maxconnects && (multi->maxconnects < newmax)) - /* don't grow beyond the allowed size */ - newmax = multi->maxconnects; - - if(newmax > multi->connc->num) { - /* we only do this is we can in fact grow the cache */ - CURLcode res = Curl_ch_connc(easy_handle, multi->connc, newmax); - if(res != CURLE_OK) { - /* FIXME: may need to do more cleanup here */ - curl_multi_remove_handle(multi_handle, easy_handle); - return CURLM_OUT_OF_MEMORY; - } - } - } - /* increase the alive-counter */ multi->num_alive++; @@ -628,9 +642,10 @@ CURLMcode curl_multi_remove_handle(CURLM *multi_handle, easy = data->multi_pos; if(easy) { - bool premature = (bool)(easy->state < CURLM_STATE_COMPLETED); - bool easy_owns_conn = (bool)(easy->easy_conn && - (easy->easy_conn->data == easy->easy_handle)); + bool premature = (easy->state < CURLM_STATE_COMPLETED) ? TRUE : FALSE; + bool easy_owns_conn = (easy->easy_conn && + (easy->easy_conn->data == easy->easy_handle)) ? + 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. */ @@ -801,20 +816,12 @@ static int waitconnect_getsock(struct connectdata *conn, } static int domore_getsock(struct connectdata *conn, - curl_socket_t *sock, + curl_socket_t *socks, int numsocks) { - if(!numsocks) - return GETSOCK_BLANK; - - /* 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. It makes a difference in the way: if we - connect to the site we wait for the socket to become writable, if - the site connects to us we wait for it to become readable */ - sock[0] = conn->sock[SECONDARYSOCKET]; - - return GETSOCK_WRITESOCK(0); + if(conn && conn->handler->domore_getsock) + return conn->handler->domore_getsock(conn, socks, numsocks); + return GETSOCK_BLANK; } /* returns bitmapped flags for this handle and its sockets */ @@ -906,11 +913,11 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle, for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) { curl_socket_t s = CURL_SOCKET_BAD; - if(bitmap & GETSOCK_READSOCK(i)) { + if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], read_fd_set); s = sockbunch[i]; } - if(bitmap & GETSOCK_WRITESOCK(i)) { + if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) { FD_SET(sockbunch[i], write_fd_set); s = sockbunch[i]; } @@ -952,8 +959,8 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, data = easy->easy_handle; do { - /* this is a do-while loop just to allow a break to skip to the end - of it */ + /* this is a single-iteration do-while loop just to allow a + break to skip to the end of it */ bool disconnect_conn = FALSE; /* Handle the case when the pipe breaks, i.e., the connection @@ -1039,7 +1046,9 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, /* Add this handle to the send or pend pipeline */ easy->result = addHandleToSendOrPendPipeline(data, easy->easy_conn); - if(CURLE_OK == easy->result) { + if(CURLE_OK != easy->result) + disconnect_conn = TRUE; + else { if(async) /* We're now waiting for an asynchronous name lookup */ multistate(easy, CURLM_STATE_WAITRESOLVE); @@ -1282,7 +1291,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, disconnect_conn = TRUE; } else - retry = (bool)(newurl?TRUE:FALSE); + retry = (newurl)?TRUE:FALSE; Curl_posttransfer(data); drc = Curl_done(&easy->easy_conn, easy->result, FALSE); @@ -1481,14 +1490,14 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, Curl_posttransfer(data); Curl_done(&easy->easy_conn, easy->result, FALSE); } - else if(TRUE == done) { + else if(done) { char *newurl = NULL; bool retry = FALSE; followtype follow=FOLLOW_NONE; easy->result = Curl_retry_request(easy->easy_conn, &newurl); if(!easy->result) - retry = (bool)(newurl?TRUE:FALSE); + retry = (newurl)?TRUE:FALSE; /* call this even if the readwrite function returned error */ Curl_posttransfer(data); @@ -1537,8 +1546,10 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, newurl = data->req.location; data->req.location = NULL; easy->result = Curl_follow(data, newurl, FOLLOW_FAKE); - if(easy->result) + if(easy->result) { + disconnect_conn = TRUE; free(newurl); + } } multistate(easy, CURLM_STATE_DONE); @@ -1615,7 +1626,7 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, return CURLM_INTERNAL_ERROR; } - if(CURLM_STATE_COMPLETED > easy->state) { + if(easy->state < CURLM_STATE_COMPLETED) { if(CURLE_OK != easy->result) { /* * If an error was returned, and we aren't in completed state now, @@ -1639,25 +1650,37 @@ static CURLMcode multi_runsingle(struct Curl_multi *multi, easy->easy_conn->done_pipe); /* Check if we can move pending requests to send pipe */ checkPendPipeline(easy->easy_conn); - } - if(disconnect_conn) { - /* disconnect properly */ - Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE); + if(disconnect_conn) { + /* disconnect properly */ + Curl_disconnect(easy->easy_conn, /* dead_connection */ FALSE); - /* This is where we make sure that the easy_conn pointer is reset. - We don't have to do this in every case block above where a - failure is detected */ - easy->easy_conn = NULL; + /* This is where we make sure that the easy_conn pointer is reset. + We don't have to do this in every case block above where a + failure is detected */ + easy->easy_conn = NULL; + } + } + else if(easy->state == CURLM_STATE_CONNECT) { + /* Curl_connect() failed */ + (void)Curl_posttransfer(data); } multistate(easy, CURLM_STATE_COMPLETED); } /* if there's still a connection to use, call the progress function */ - else if(easy->easy_conn && Curl_pgrsUpdate(easy->easy_conn)) - easy->result = CURLE_ABORTED_BY_CALLBACK; + else if(easy->easy_conn && Curl_pgrsUpdate(easy->easy_conn)) { + /* aborted due to progress callback return code must close the + connection */ + easy->easy_conn->bits.close = TRUE; + + /* if not yet in DONE state, go there, otherwise COMPLETED */ + multistate(easy, (easy->state < CURLM_STATE_DONE)? + CURLM_STATE_DONE: CURLM_STATE_COMPLETED); + result = CURLM_CALL_MULTI_PERFORM; + } } - } while(0); + } WHILE_FALSE; /* just to break out from! */ if(CURLM_STATE_COMPLETED == easy->state) { if(data->dns.hostcachetype == HCACHE_MULTI) { @@ -1787,9 +1810,11 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle) } Curl_rm_connc(multi->connc); + multi->connc = NULL; /* remove the pending list of messages */ Curl_llist_destroy(multi->msglist, NULL); + multi->msglist = NULL; /* remove all easy handles */ easy = multi->easy.next; @@ -2213,7 +2238,7 @@ CURLMcode curl_multi_setopt(CURLM *multi_handle, multi->socket_userp = va_arg(param, void *); break; case CURLMOPT_PIPELINING: - multi->pipelining_enabled = (bool)(0 != va_arg(param, long)); + multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE; break; case CURLMOPT_TIMERFUNCTION: multi->timer_cb = va_arg(param, curl_multi_timer_callback); @@ -2478,7 +2503,7 @@ static bool isHandleAtHead(struct SessionHandle *handle, { struct curl_llist_element *curr = pipeline->head; if(curr) - return (bool)(curr->ptr == handle); + return (curr->ptr == handle) ? TRUE : FALSE; return FALSE; } diff --git a/lib/netrc.c b/lib/netrc.c index 5541a2f29..6764b974d 100644 --- a/lib/netrc.c +++ b/lib/netrc.c @@ -22,10 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #ifdef HAVE_UNISTD_H #include <unistd.h> #endif diff --git a/lib/non-ascii.h b/lib/non-ascii.h index 4e303dff8..6dcbe0044 100644 --- a/lib/non-ascii.h +++ b/lib/non-ascii.h @@ -51,9 +51,9 @@ CURLcode Curl_convert_from_utf8(struct SessionHandle *data, CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form); #else #define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK) -#define Curl_convert_init(x) -#define Curl_convert_setup(x) -#define Curl_convert_close(x) +#define Curl_convert_init(x) Curl_nop_stmt +#define Curl_convert_setup(x) Curl_nop_stmt +#define Curl_convert_close(x) Curl_nop_stmt #define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK) #define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK) diff --git a/lib/nonblock.c b/lib/nonblock.c index cd819506c..529ce8bca 100644 --- a/lib/nonblock.c +++ b/lib/nonblock.c @@ -34,9 +34,6 @@ #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE)) #include <sys/filio.h> @@ -65,7 +62,7 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ /* most recent unix versions */ int flags; flags = fcntl(sockfd, F_GETFL, 0); - if(FALSE != nonblock) + if(nonblock) return fcntl(sockfd, F_SETFL, flags | O_NONBLOCK); else return fcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK)); @@ -73,26 +70,25 @@ int curlx_nonblock(curl_socket_t sockfd, /* operate on this */ #elif defined(HAVE_IOCTL_FIONBIO) /* older unix versions */ - int flags; - flags = nonblock; + int flags = nonblock ? 1 : 0; return ioctl(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_FIONBIO) /* Windows */ - unsigned long flags; - flags = nonblock; + unsigned long flags = nonblock ? 1UL : 0UL; return ioctlsocket(sockfd, FIONBIO, &flags); #elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO) /* Amiga */ - return IoctlSocket(sockfd, FIONBIO, (long)nonblock); + long flags = nonblock ? 1L : 0L; + return IoctlSocket(sockfd, FIONBIO, flags); #elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK) /* BeOS */ - long b = nonblock ? 1 : 0; + long b = nonblock ? 1L : 0L; return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b)); #else @@ -27,9 +27,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -95,7 +92,7 @@ typedef struct { ptr->type = (_type); \ ptr->pValue = (_val); \ ptr->ulValueLen = (_len); \ -} while(0) +} WHILE_FALSE #define CERT_NewTempCertificate __CERT_NewTempCertificate @@ -281,17 +278,16 @@ static int is_file(const char *filename) return 0; } -/* Return on heap allocated filename/nickname of a certificate. The returned - * string should be later deallocated using free(). *is_nickname is set to - * TRUE if the given string is treated as nickname; FALSE if the given string - * is treated as file name. +/* Check if the given string is filename or nickname of a certificate. If the + * given string is recognized as filename, return NULL. If the given string is + * recognized as nickname, return a duplicated string. The returned string + * should be later deallocated using free(). If the OOM failure occurs, we + * return NULL, too. */ -static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind, - bool *is_nickname) +static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind) { const char *str = data->set.str[cert_kind]; const char *n; - *is_nickname = TRUE; if(!is_file(str)) /* no such file exists, use the string as nickname */ @@ -306,10 +302,7 @@ static char *fmt_nickname(struct SessionHandle *data, enum dupstring cert_kind, } /* we'll use the PEM reader to read the certificate from file */ - *is_nickname = FALSE; - - n++; /* skip last slash */ - return aprintf("PEM Token #%d:%s", 1, n); + return NULL; } #ifdef HAVE_PK11_CREATEGENERICOBJECT @@ -326,6 +319,9 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, CK_BBOOL ckfalse = CK_FALSE; CK_ATTRIBUTE attrs[/* max count of attributes */ 4]; int attr_cnt = 0; + CURLcode err = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; const int slot_id = (cacert) ? 0 : 1; char *slot_name = aprintf("PEM Token #%d", slot_id); @@ -335,7 +331,7 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, slot = PK11_FindSlotByName(slot_name); free(slot_name); if(!slot) - return CURLE_SSL_CERTPROBLEM; + return err; PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class)); PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL)); @@ -350,13 +346,17 @@ static CURLcode nss_create_object(struct ssl_connect_data *ssl, obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE); PK11_FreeSlot(slot); if(!obj) - return CURLE_SSL_CERTPROBLEM; + return err; if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) { PK11_DestroyGenericObject(obj); return CURLE_OUT_OF_MEMORY; } + if(!cacert && CKO_CERTIFICATE == obj_class) + /* store reference to a client certificate */ + ssl->obj_clicert = obj; + return CURLE_OK; } @@ -371,76 +371,43 @@ static void nss_destroy_object(void *user, void *ptr) } #endif -static int nss_load_cert(struct ssl_connect_data *ssl, - const char *filename, PRBool cacert) +static CURLcode nss_load_cert(struct ssl_connect_data *ssl, + const char *filename, PRBool cacert) { -#ifdef HAVE_PK11_CREATEGENERICOBJECT - /* All CA and trust objects go into slot 0. Other slots are used - * for storing certificates. - */ - const int slot_id = (cacert) ? 0 : 1; -#endif - CERTCertificate *cert; - char *nickname = NULL; - char *n = NULL; + CURLcode err = (cacert) + ? CURLE_SSL_CACERT_BADFILE + : CURLE_SSL_CERTPROBLEM; - /* If there is no slash in the filename it is assumed to be a regular - * NSS nickname. - */ - if(is_file(filename)) { - n = strrchr(filename, '/'); +#ifdef HAVE_PK11_CREATEGENERICOBJECT + /* libnsspem.so leaks memory if the requested file does not exist. For more + * details, go to <https://bugzilla.redhat.com/734760>. */ + if(is_file(filename)) + err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert); + + if(CURLE_OK == err && !cacert) { + /* we have successfully loaded a client certificate */ + CERTCertificate *cert; + char *nickname = NULL; + char *n = strrchr(filename, '/'); if(n) n++; - if(!mod) - return 1; - } - else { - /* A nickname from the NSS internal database */ - if(cacert) - return 0; /* You can't specify an NSS CA nickname this way */ - nickname = strdup(filename); - if(!nickname) - return 0; - goto done; - } - -#ifdef HAVE_PK11_CREATEGENERICOBJECT - nickname = aprintf("PEM Token #%d:%s", slot_id, n); - if(!nickname) - return 0; - - if(CURLE_OK != nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert)) { - free(nickname); - return 0; - } -#else - /* We don't have PK11_CreateGenericObject but a file-based cert was passed - * in. We need to fail. - */ - return 0; -#endif + /* The following undocumented magic helps to avoid a SIGSEGV on call + * of PK11_ReadRawAttribute() from SelectClientCert() when using an + * immature version of libnsspem.so. For more details, go to + * <https://bugzilla.redhat.com/733685>. */ + nickname = aprintf("PEM Token #1:%s", n); + if(nickname) { + cert = PK11_FindCertFromNickname(nickname, NULL); + if(cert) + CERT_DestroyCertificate(cert); - done: - /* Double-check that the certificate or nickname requested exists in - * either the token or the NSS certificate database. - */ - if(!cacert) { - cert = PK11_FindCertFromNickname((char *)nickname, NULL); - - /* An invalid nickname was passed in */ - if(cert == NULL) { free(nickname); - PR_SetError(SEC_ERROR_UNKNOWN_CERT, 0); - return 0; } - - CERT_DestroyCertificate(cert); } +#endif - free(nickname); - - return 1; + return err; } /* add given CRL to cache if it is not already there */ @@ -529,23 +496,23 @@ fail: return SECFailure; } -static int nss_load_key(struct connectdata *conn, int sockindex, - char *key_file) +static CURLcode nss_load_key(struct connectdata *conn, int sockindex, + char *key_file) { #ifdef HAVE_PK11_CREATEGENERICOBJECT PK11SlotInfo *slot; SECStatus status; struct ssl_connect_data *ssl = conn->ssl; - (void)sockindex; /* unused */ - if(CURLE_OK != nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE)) { + CURLcode rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE); + if(CURLE_OK != rv) { PR_SetError(SEC_ERROR_BAD_KEY, 0); - return 0; + return rv; } slot = PK11_FindSlotByName("PEM Token #1"); if(!slot) - return 0; + return CURLE_SSL_CERTPROBLEM; /* This will force the token to be seen as re-inserted */ SECMOD_WaitForAnyTokenEvent(mod, 0, 0); @@ -554,16 +521,18 @@ static int nss_load_key(struct connectdata *conn, int sockindex, status = PK11_Authenticate(slot, PR_TRUE, conn->data->set.str[STRING_KEY_PASSWD]); PK11_FreeSlot(slot); - return (SECSuccess == status) ? 1 : 0; + return (SECSuccess == status) + ? CURLE_OK + : CURLE_SSL_CERTPROBLEM; #else /* If we don't have PK11_CreateGenericObject then we can't load a file-based * key. */ (void)conn; /* unused */ (void)key_file; /* unused */ - (void)sockindex; /* unused */ - return 0; + return CURLE_SSL_CERTPROBLEM; #endif + (void)sockindex; /* unused */ } static int display_error(struct connectdata *conn, PRInt32 err, @@ -582,34 +551,37 @@ static int display_error(struct connectdata *conn, PRInt32 err, return 0; /* The caller will print a generic error */ } -static int cert_stuff(struct connectdata *conn, - int sockindex, char *cert_file, char *key_file) +static CURLcode cert_stuff(struct connectdata *conn, int sockindex, + char *cert_file, char *key_file) { struct SessionHandle *data = conn->data; - int rv = 0; + CURLcode rv; if(cert_file) { rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE); - if(!rv) { + if(CURLE_OK != rv) { if(!display_error(conn, PR_GetError(), cert_file)) failf(data, "Unable to load client cert %d.", PR_GetError()); - return 0; + + return rv; } } + if(key_file || (is_file(cert_file))) { if(key_file) rv = nss_load_key(conn, sockindex, key_file); else /* In case the cert file also has the key */ rv = nss_load_key(conn, sockindex, cert_file); - if(!rv) { + if(CURLE_OK != rv) { if(!display_error(conn, PR_GetError(), key_file)) failf(data, "Unable to load client key %d.", PR_GetError()); - return 0; + return rv; } } - return 1; + + return CURLE_OK; } static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg) @@ -776,7 +748,6 @@ static SECStatus check_issuer_cert(PRFileDesc *sock, cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner); proto_win = SSL_RevealPinArg(sock); - issuer = NULL; issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win); if((!cert_issuer) || (!issuer)) @@ -800,44 +771,51 @@ static SECStatus SelectClientCert(void *arg, PRFileDesc *sock, struct CERTCertificateStr **pRetCert, struct SECKEYPrivateKeyStr **pRetKey) { - static const char pem_nickname[] = "PEM Token #1"; - const char *pem_slotname = pem_nickname; - struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg; struct SessionHandle *data = connssl->data; const char *nickname = connssl->client_nickname; - if(mod && nickname && - 0 == strncmp(nickname, pem_nickname, /* length of "PEM Token" */ 9)) { - +#ifdef HAVE_PK11_CREATEGENERICOBJECT + if(connssl->obj_clicert) { /* use the cert/key provided by PEM reader */ - PK11SlotInfo *slot; + static const char pem_slotname[] = "PEM Token #1"; + SECItem cert_der = { 0, NULL, 0 }; void *proto_win = SSL_RevealPinArg(sock); - *pRetKey = NULL; - *pRetCert = PK11_FindCertFromNickname(nickname, proto_win); - if(NULL == *pRetCert) { - failf(data, "NSS: client certificate not found: %s", nickname); + PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname); + if(NULL == slot) { + failf(data, "NSS: PK11 slot not found: %s", pem_slotname); return SECFailure; } - slot = PK11_FindSlotByName(pem_slotname); - if(NULL == slot) { - failf(data, "NSS: PK11 slot not found: %s", pem_slotname); + if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE, + &cert_der) != SECSuccess) { + failf(data, "NSS: CKA_VALUE not found in PK11 generic object"); + PK11_FreeSlot(slot); + return SECFailure; + } + + *pRetCert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win); + SECITEM_FreeItem(&cert_der, PR_FALSE); + if(NULL == *pRetCert) { + failf(data, "NSS: client certificate from file not found"); + PK11_FreeSlot(slot); return SECFailure; } *pRetKey = PK11_FindPrivateKeyFromCert(slot, *pRetCert, NULL); PK11_FreeSlot(slot); if(NULL == *pRetKey) { - failf(data, "NSS: private key not found for certificate: %s", nickname); + failf(data, "NSS: private key from file not found"); + CERT_DestroyCertificate(*pRetCert); return SECFailure; } - infof(data, "NSS: client certificate: %s\n", nickname); + infof(data, "NSS: client certificate from file\n"); display_cert_info(data, *pRetCert); return SECSuccess; } +#endif /* use the default NSS hook */ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames, @@ -898,10 +876,42 @@ isTLSIntoleranceError(PRInt32 err) } } -static CURLcode init_nss(struct SessionHandle *data) +static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir) +{ + if(NSS_IsInitialized()) + return CURLE_OK; + + if(cert_dir) { + SECStatus rv; + const bool use_sql = NSS_VersionCheck("3.12.0"); + char *certpath = aprintf("%s%s", use_sql ? "sql:" : "", cert_dir); + if(!certpath) + return CURLE_OUT_OF_MEMORY; + + infof(data, "Initializing NSS with certpath: %s\n", certpath); + rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY); + free(certpath); + + if(rv == SECSuccess) + return CURLE_OK; + + infof(data, "Unable to initialize NSS database\n"); + } + + infof(data, "Initializing NSS with certpath: none\n"); + if(NSS_NoDB_Init(NULL) == SECSuccess) + return CURLE_OK; + + infof(data, "Unable to initialize NSS\n"); + return CURLE_SSL_CACERT_BADFILE; +} + +static CURLcode nss_init(struct SessionHandle *data) { char *cert_dir; struct_stat st; + CURLcode rv; + if(initialized) return CURLE_OK; @@ -922,31 +932,14 @@ static CURLcode init_nss(struct SessionHandle *data) } } - if(!NSS_IsInitialized()) { - SECStatus rv; - initialized = 1; - infof(data, "Initializing NSS with certpath: %s\n", - cert_dir ? cert_dir : "none"); - if(!cert_dir) { - rv = NSS_NoDB_Init(NULL); - } - else { - char *certpath = - PR_smprintf("%s%s", NSS_VersionCheck("3.12.0") ? "sql:" : "", - cert_dir); - rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY); - PR_smprintf_free(certpath); - } - if(rv != SECSuccess) { - infof(data, "Unable to initialize NSS database\n"); - initialized = 0; - return CURLE_SSL_CACERT_BADFILE; - } - } + rv = nss_init_core(data, cert_dir); + if(rv) + return rv; if(num_enabled_ciphers() == 0) NSS_SetDomesticPolicy(); + initialized = 1; return CURLE_OK; } @@ -981,7 +974,7 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data) } PR_Lock(nss_initlock); - rv = init_nss(data); + rv = nss_init(data); PR_Unlock(nss_initlock); return rv; } @@ -1064,6 +1057,7 @@ void Curl_nss_close(struct connectdata *conn, int sockindex) /* destroy all NSS objects in order to avoid failure of NSS shutdown */ Curl_llist_destroy(connssl->obj_list, NULL); connssl->obj_list = NULL; + connssl->obj_clicert = NULL; #endif PR_Close(connssl->handle); connssl->handle = NULL; @@ -1111,8 +1105,11 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, const char *cafile = data->set.ssl.CAfile; const char *capath = data->set.ssl.CApath; - if(cafile && !nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE)) - return CURLE_SSL_CACERT_BADFILE; + if(cafile) { + CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE); + if(CURLE_OK != rv) + return rv; + } if(capath) { struct_stat st; @@ -1132,7 +1129,7 @@ static CURLcode nss_load_ca_certificates(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } - if(!nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) + if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE)) /* This is purposefully tolerant of errors so non-PEM files can * be in the same directory */ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath); @@ -1184,7 +1181,7 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) /* FIXME. NSS doesn't support multiple databases open at the same time. */ PR_Lock(nss_initlock); - curlerr = init_nss(conn->data); + curlerr = nss_init(conn->data); if(CURLE_OK != curlerr) { PR_Unlock(nss_initlock); goto error; @@ -1327,16 +1324,21 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) } if(data->set.str[STRING_CERT]) { - bool is_nickname; - char *nickname = fmt_nickname(data, STRING_CERT, &is_nickname); - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - if(!is_nickname && !cert_stuff(conn, sockindex, data->set.str[STRING_CERT], - data->set.str[STRING_KEY])) { - /* failf() is already done in cert_stuff() */ - free(nickname); - return CURLE_SSL_CERTPROBLEM; + char *nickname = dup_nickname(data, STRING_CERT); + if(nickname) { + /* we are not going to use libnsspem.so to read the client cert */ +#ifdef HAVE_PK11_CREATEGENERICOBJECT + connssl->obj_clicert = NULL; +#endif + } + else { + CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT], + data->set.str[STRING_KEY]); + if(CURLE_OK != rv) { + /* failf() is already done in cert_stuff() */ + curlerr = rv; + goto error; + } } /* store the nickname for SelectClientCert() called during handshake */ @@ -1395,16 +1397,12 @@ CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex) if(data->set.str[STRING_SSL_ISSUERCERT]) { SECStatus ret = SECFailure; - bool is_nickname; - char *nickname = fmt_nickname(data, STRING_SSL_ISSUERCERT, &is_nickname); - if(!nickname) - return CURLE_OUT_OF_MEMORY; - - if(is_nickname) + char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT); + if(nickname) { /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */ ret = check_issuer_cert(connssl->handle, nickname); - - free(nickname); + free(nickname); + } if(SECFailure == ret) { infof(data,"SSL certificate issuer check failed\n"); diff --git a/lib/nssg.h b/lib/nssg.h index 438d5a636..4d7df5efa 100644 --- a/lib/nssg.h +++ b/lib/nssg.h @@ -1,5 +1,5 @@ -#ifndef __NSSG_H -#define __NSSG_H +#ifndef HEADER_CURL_NSSG_H +#define HEADER_CURL_NSSG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #ifdef USE_NSS /* @@ -28,6 +29,7 @@ */ #include "urldata.h" + CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex); CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -55,7 +57,7 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data); #define curlssl_connect Curl_nss_connect /* NSS has its own session ID cache */ -#define curlssl_session_free(x) +#define curlssl_session_free(x) Curl_nop_stmt #define curlssl_close_all Curl_nss_close_all #define curlssl_close Curl_nss_close /* NSS has no shutdown function provided and thus always fail */ @@ -68,4 +70,4 @@ CURLcode Curl_nss_force_init(struct SessionHandle *data); #define curlssl_data_pending(x,y) (x=x, y=y, 0) #endif /* USE_NSS */ -#endif +#endif /* HEADER_CURL_NSSG_H */ diff --git a/lib/nwlib.c b/lib/nwlib.c index f9c8a4298..c87ca0d29 100644 --- a/lib/nwlib.c +++ b/lib/nwlib.c @@ -20,14 +20,12 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "setup.h" -#include <stdlib.h> +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to register as a real lib. */ -#include <errno.h> -#include <string.h> #include <library.h> #include <netware.h> #include <screen.h> diff --git a/lib/nwos.c b/lib/nwos.c index ac365124f..bd695b3f9 100644 --- a/lib/nwos.c +++ b/lib/nwos.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -20,9 +20,9 @@ * ***************************************************************************/ -#ifdef NETWARE /* Novell NetWare */ +#include "setup.h" -#include <stdlib.h> +#ifdef NETWARE /* Novell NetWare */ #ifdef __NOVELL_LIBC__ /* For native LibC-based NLM we need to do nothing. */ @@ -34,7 +34,6 @@ int netware_init ( void ) #else /* __NOVELL_LIBC__ */ /* For native CLib-based NLM we need to initialize the LONG namespace. */ -#include <stdio.h> #include <nwnspace.h> #include <nwthread.h> #include <nwadv.h> @@ -86,10 +85,4 @@ int __deinit_environment ( void ) #endif /* __NOVELL_LIBC__ */ -#else /* NETWARE */ - -#ifdef __POCC__ -# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */ -#endif - #endif /* NETWARE */ diff --git a/lib/openldap.c b/lib/openldap.c index 69523cb37..e5a3369a1 100644 --- a/lib/openldap.c +++ b/lib/openldap.c @@ -83,6 +83,7 @@ const struct Curl_handler Curl_handler_ldap = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -107,6 +108,7 @@ const struct Curl_handler Curl_handler_ldaps = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ldap_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -544,12 +546,21 @@ static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, } } if(binary || binval) { - char *val_b64; + char *val_b64 = NULL; + size_t val_b64_sz = 0; /* Binary value, encode to base64. */ - size_t val_b64_sz = Curl_base64_encode(data, - bvals[i].bv_val, - bvals[i].bv_len, - &val_b64); + CURLcode error = Curl_base64_encode(data, + bvals[i].bv_val, + bvals[i].bv_len, + &val_b64, + &val_b64_sz); + if(error) { + ber_memfree(bvals); + ber_free(ber, 0); + ldap_msgfree(result); + *err = error; + return -1; + } Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); data->req.bytecount += 2; if(val_b64_sz > 0) { diff --git a/lib/parsedate.c b/lib/parsedate.c index 62f1a4181..ec60e78e7 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -72,14 +72,8 @@ 20040911 +0200 */ -#include "setup.h" -#include <stdio.h> -#include <ctype.h> -#include <string.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> /* for strtol() */ -#endif +#include "setup.h" #include <curl/curl.h> #include "rawstr.h" diff --git a/lib/pingpong.c b/lib/pingpong.c index 23ab69fb2..84ce88148 100644 --- a/lib/pingpong.c +++ b/lib/pingpong.c @@ -177,9 +177,6 @@ void Curl_pp_init(struct pingpong *pp) * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -187,12 +184,10 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, va_list args) { ssize_t bytes_written; -/* may still not be big enough for some krb5 tokens */ -#define SBUF_SIZE 1024 - char s[SBUF_SIZE]; size_t write_len; - char *sptr=s; - CURLcode res = CURLE_OK; + char *fmt_crlf; + char *s; + CURLcode error; struct connectdata *conn = pp->conn; struct SessionHandle *data = conn->data; @@ -200,55 +195,64 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, enum protection_level data_sec = conn->data_prot; #endif - vsnprintf(s, SBUF_SIZE-3, fmt, args); + DEBUGASSERT(pp->sendleft == 0); + DEBUGASSERT(pp->sendsize == 0); + DEBUGASSERT(pp->sendthis == NULL); + + fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */ + if(!fmt_crlf) + return CURLE_OUT_OF_MEMORY; - strcat(s, "\r\n"); /* append a trailing CRLF */ + s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */ + free(fmt_crlf); + if(!s) + return CURLE_OUT_OF_MEMORY; - bytes_written=0; + bytes_written = 0; write_len = strlen(s); Curl_pp_init(pp); - res = Curl_convert_to_network(data, s, write_len); + error = Curl_convert_to_network(data, s, write_len); /* Curl_convert_to_network calls failf if unsuccessful */ - if(res) - return res; + if(error) { + free(s); + return error; + } #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) conn->data_prot = PROT_CMD; #endif - res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len, - &bytes_written); + error = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len, + &bytes_written); #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST); conn->data_prot = data_sec; #endif - if(CURLE_OK != res) - return res; + if(error) { + free(s); + return error; + } if(conn->data->set.verbose) Curl_debug(conn->data, CURLINFO_HEADER_OUT, - sptr, (size_t)bytes_written, conn); + s, (size_t)bytes_written, conn); if(bytes_written != (ssize_t)write_len) { - /* the whole chunk was not sent, store the rest of the data */ - write_len -= bytes_written; - sptr += bytes_written; - pp->sendthis = malloc(write_len); - if(pp->sendthis) { - memcpy(pp->sendthis, sptr, write_len); - pp->sendsize = pp->sendleft = write_len; - } - else { - failf(data, "out of memory"); - res = CURLE_OUT_OF_MEMORY; - } + /* 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 + else { + free(s); + pp->sendthis = NULL; + pp->sendleft = pp->sendsize = 0; pp->response = Curl_tvnow(); + } - return res; + return CURLE_OK; } @@ -260,9 +264,6 @@ CURLcode Curl_pp_vsendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, diff --git a/lib/pingpong.h b/lib/pingpong.h index cbbff8f3e..1d104cfbc 100644 --- a/lib/pingpong.h +++ b/lib/pingpong.h @@ -1,5 +1,5 @@ -#ifndef __PINGPONG_H -#define __PINGPONG_H +#ifndef HEADER_CURL_PINGPONG_H +#define HEADER_CURL_PINGPONG_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -22,8 +22,6 @@ * ***************************************************************************/ -#include <stdarg.h> - #include "setup.h" #if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \ @@ -100,9 +98,6 @@ long Curl_pp_state_timeout(struct pingpong *pp); * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_sendf(struct pingpong *pp, @@ -116,9 +111,6 @@ CURLcode Curl_pp_sendf(struct pingpong *pp, * the string should not have any CRLF appended, as this function will * append the necessary things itself. * - * NOTE: we build the command in a fixed-length buffer, which sets length - * restrictions on the command! - * * made to never block */ CURLcode Curl_pp_vsendf(struct pingpong *pp, @@ -144,4 +136,4 @@ CURLcode Curl_pp_disconnect(struct pingpong *pp); int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks, int numsocks); -#endif /* __PINGPONG_H */ +#endif /* HEADER_CURL_PINGPONG_H */ diff --git a/lib/polarssl.c b/lib/polarssl.c index 2e70a28d5..09446f995 100644 --- a/lib/polarssl.c +++ b/lib/polarssl.c @@ -27,11 +27,9 @@ */ #include "setup.h" + #ifdef USE_POLARSSL -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -41,6 +39,15 @@ #include <polarssl/havege.h> #include <polarssl/certs.h> #include <polarssl/x509.h> +#include <polarssl/version.h> + +#if POLARSSL_VERSION_NUMBER<0x01000000 +/* + Earlier versions of polarssl had no WANT_READ or WANT_WRITE, only TRY_AGAIN +*/ +#define POLARSSL_ERR_NET_WANT_READ POLARSSL_ERR_NET_TRY_AGAIN +#define POLARSSL_ERR_NET_WANT_WRITE POLARSSL_ERR_NET_TRY_AGAIN +#endif #include "urldata.h" #include "sendf.h" @@ -188,8 +195,12 @@ Curl_polarssl_connect(struct connectdata *conn, net_recv, &conn->sock[sockindex], net_send, &conn->sock[sockindex]); - ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); +#if POLARSSL_VERSION_NUMBER<0x01000000 + ssl_set_ciphers(&conn->ssl[sockindex].ssl, ssl_default_ciphers); +#else + ssl_set_ciphersuites(&conn->ssl[sockindex].ssl, ssl_default_ciphersuites); +#endif if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) { memcpy(&conn->ssl[sockindex].ssn, old_session, old_session_size); infof(data, "PolarSSL re-using session\n"); @@ -224,7 +235,8 @@ Curl_polarssl_connect(struct connectdata *conn, for(;;) { if(!(ret = ssl_handshake(&conn->ssl[sockindex].ssl))) break; - else if(ret != POLARSSL_ERR_NET_TRY_AGAIN) { + else if(ret != POLARSSL_ERR_NET_WANT_READ && + ret != POLARSSL_ERR_NET_WANT_WRITE) { failf(data, "ssl_handshake returned -0x%04X", -ret); return CURLE_SSL_CONNECT_ERROR; } @@ -254,7 +266,11 @@ Curl_polarssl_connect(struct connectdata *conn, } infof(data, "PolarSSL: Handshake complete, cipher is %s\n", +#if POLARSSL_VERSION_NUMBER<0x01000000 ssl_get_cipher(&conn->ssl[sockindex].ssl)); +#else + ssl_get_ciphersuite_name(&conn->ssl[sockindex].ssl)); +#endif ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl); @@ -318,7 +334,7 @@ static ssize_t polarssl_send(struct connectdata *conn, (unsigned char *)mem, len); if(ret < 0) { - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? + *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ? CURLE_AGAIN : CURLE_SEND_ERROR; ret = -1; } @@ -356,7 +372,7 @@ static ssize_t polarssl_recv(struct connectdata *conn, if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY) return 0; - *curlcode = (ret == POLARSSL_ERR_NET_TRY_AGAIN) ? + *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ? CURLE_AGAIN : CURLE_RECV_ERROR; return -1; } diff --git a/lib/polarssl.h b/lib/polarssl.h index 9e983aac9..91f63afbf 100644 --- a/lib/polarssl.h +++ b/lib/polarssl.h @@ -20,8 +20,8 @@ * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY * KIND, either express or implied. * - * $Id: polarssl.h,v 1.10 2009-02-12 20:48:43 danf Exp $ ***************************************************************************/ +#include "setup.h" #ifdef USE_POLARSSL @@ -40,7 +40,7 @@ int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex); /* API setup for PolarSSL */ #define curlssl_init() (1) -#define curlssl_cleanup() +#define curlssl_cleanup() Curl_nop_stmt #define curlssl_connect Curl_polarssl_connect #define curlssl_session_free(x) Curl_polarssl_session_free(x) #define curlssl_close_all Curl_polarssl_close_all diff --git a/lib/pop3.c b/lib/pop3.c index dc5a1c2fa..cb70679c5 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -27,11 +27,6 @@ #include "setup.h" #ifndef CURL_DISABLE_POP3 -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -124,6 +119,7 @@ const struct Curl_handler Curl_handler_pop3 = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -149,6 +145,7 @@ const struct Curl_handler Curl_handler_pop3s = { pop3_doing, /* doing */ pop3_getsock, /* proto_getsock */ pop3_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ pop3_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -174,6 +171,7 @@ static const struct Curl_handler Curl_handler_pop3_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -199,6 +197,7 @@ static const struct Curl_handler Curl_handler_pop3s_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -285,7 +284,7 @@ static void pop3_to_pop3s(struct connectdata *conn) conn->handler = &Curl_handler_pop3s; } #else -#define pop3_to_pop3s(x) +#define pop3_to_pop3s(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -575,7 +574,7 @@ static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done) struct pop3_conn *pop3c = &conn->proto.pop3c; CURLcode result = Curl_pp_multi_statemach(&pop3c->pp); - *done = (bool)(pop3c->state == POP3_STOP); + *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE; return result; } @@ -792,7 +791,7 @@ CURLcode pop3_perform(struct connectdata *conn, result = pop3_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/progress.c b/lib/progress.c index 8655dc4c2..1514e1edd 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -201,6 +201,8 @@ void Curl_pgrsStartNow(struct SessionHandle *data) { data->progress.speeder_c = 0; /* reset the progress meter display */ data->progress.start = Curl_tvnow(); + /* clear all bits except HIDE and HEADERS_OUT */ + data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT; } void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size) diff --git a/lib/qssl.c b/lib/qssl.c index 60ea6da23..172df3141 100644 --- a/lib/qssl.c +++ b/lib/qssl.c @@ -23,9 +23,9 @@ #include "setup.h" #ifdef USE_QSOSSL + #include <qsossl.h> -#include <errno.h> -#include <string.h> + #ifdef HAVE_LIMITS_H # include <limits.h> #endif diff --git a/lib/qssl.h b/lib/qssl.h index bd195ff7b..a523cb1f3 100644 --- a/lib/qssl.h +++ b/lib/qssl.h @@ -1,5 +1,5 @@ -#ifndef __QSSL_H -#define __QSSL_H +#ifndef HEADER_CURL_QSSL_H +#define HEADER_CURL_QSSL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" /* * This header should only be needed to get included by sslgen.c and qssl.c @@ -45,7 +46,7 @@ int Curl_qsossl_check_cxn(struct connectdata * cxn); #define curlssl_connect Curl_qsossl_connect /* No session handling for QsoSSL */ -#define curlssl_session_free(x) +#define curlssl_session_free(x) Curl_nop_stmt #define curlssl_close_all Curl_qsossl_close_all #define curlssl_close Curl_qsossl_close #define curlssl_shutdown(x,y) Curl_qsossl_shutdown(x,y) @@ -56,4 +57,5 @@ int Curl_qsossl_check_cxn(struct connectdata * cxn); #define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x) #define curlssl_data_pending(x,y) 0 #endif /* USE_QSOSSL */ -#endif + +#endif /* HEADER_CURL_QSSL_H */ diff --git a/lib/rtsp.c b/lib/rtsp.c index 3ce8ad51e..5d62ac7c7 100644 --- a/lib/rtsp.c +++ b/lib/rtsp.c @@ -113,6 +113,7 @@ const struct Curl_handler Curl_handler_rtsp = { 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_readwrite, /* readwrite */ @@ -294,6 +295,7 @@ static CURLcode rtsp_do(struct connectdata *conn, bool *done) case RTSPREQ_GET_PARAMETER: /* GET_PARAMETER's no_body status is determined later */ p_request = "GET_PARAMETER"; + data->set.opt_no_body = FALSE; break; case RTSPREQ_SET_PARAMETER: p_request = "SET_PARAMETER"; diff --git a/lib/security.c b/lib/security.c index 010a5504e..536d7c229 100644 --- a/lib/security.c +++ b/lib/security.c @@ -46,9 +46,6 @@ #ifndef CURL_DISABLE_FTP #if defined(HAVE_KRB4) || defined(HAVE_GSSAPI) -#include <stdarg.h> -#include <string.h> - #ifdef HAVE_NETDB_H #include <netdb.h> #endif @@ -57,6 +54,10 @@ #include <unistd.h> #endif +#ifdef HAVE_LIMITS_H +#include <limits.h> +#endif + #include "urldata.h" #include "curl_base64.h" #include "curl_memory.h" @@ -64,6 +65,7 @@ #include "ftp.h" #include "sendf.h" #include "rawstr.h" +#include "warnless.h" /* The last #include file should be: */ #include "memdebug.h" @@ -283,12 +285,13 @@ static ssize_t sec_recv(struct connectdata *conn, int sockindex, static void do_sec_send(struct connectdata *conn, curl_socket_t fd, const char *from, int length) { - size_t bytes; - size_t htonl_bytes; - char *buffer; + 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; + bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE; DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST); @@ -300,9 +303,17 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, } bytes = conn->mech->encode(conn->app_data, from, length, prot_level, (void**)&buffer, conn); + if(!buffer || bytes <= 0) + return; /* error */ + if(iscmd) { - bytes = Curl_base64_encode(conn->data, buffer, bytes, &cmd_buffer); - if(bytes > 0) { + error = Curl_base64_encode(conn->data, 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) @@ -310,7 +321,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else socket_write(conn, fd, mic, 4); - socket_write(conn, fd, cmd_buffer, bytes); + socket_write(conn, fd, cmd_buffer, cmd_size); socket_write(conn, fd, "\r\n", 2); infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic, cmd_buffer); @@ -320,7 +331,7 @@ static void do_sec_send(struct connectdata *conn, curl_socket_t fd, else { htonl_bytes = htonl(bytes); socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes)); - socket_write(conn, fd, buffer, bytes); + socket_write(conn, fd, buffer, curlx_sitouz(bytes)); } free(buffer); } @@ -365,14 +376,20 @@ int Curl_sec_read_msg(struct connectdata *conn, char *buffer, int decoded_len; char *buf; int ret_code; + size_t decoded_sz = 0; + CURLcode error; DEBUGASSERT(level > PROT_NONE && level < PROT_LAST); - decoded_len = Curl_base64_decode(buffer + 4, (unsigned char **)&buf); - if(decoded_len <= 0) { + 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); diff --git a/lib/select.c b/lib/select.c index 8f6541dee..6cecbf701 100644 --- a/lib/select.c +++ b/lib/select.c @@ -25,9 +25,6 @@ #ifdef HAVE_SYS_SELECT_H #include <sys/select.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE) #error "We can't compile without select() or poll() support." @@ -49,20 +46,6 @@ #include "select.h" #include "warnless.h" -/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1] */ - -#if defined(USE_WINSOCK) || defined(TPF) -#define VERIFY_SOCK(x) do { } while(0) -#else -#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) -#define VERIFY_SOCK(x) do { \ - if(!VALID_SOCK(x)) { \ - SET_SOCKERRNO(EINVAL); \ - return -1; \ - } \ -} while(0) -#endif - /* Convenience local macros */ #define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv) @@ -93,7 +76,7 @@ * -1 = system call error, invalid timeout value, or interrupted * 0 = specified timeout has elapsed */ -static int wait_ms(int timeout_ms) +int Curl_wait_ms(int timeout_ms) { #if !defined(MSDOS) && !defined(USE_WINSOCK) #ifndef HAVE_POLL_FINE @@ -180,7 +163,7 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int ret; if((readfd == CURL_SOCKET_BAD) && (writefd == CURL_SOCKET_BAD)) { - r = wait_ms((int)timeout_ms); + r = Curl_wait_ms((int)timeout_ms); return r; } @@ -364,7 +347,7 @@ int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms) } } if(fds_none) { - r = wait_ms((int)timeout_ms); + r = Curl_wait_ms(timeout_ms); return r; } diff --git a/lib/select.h b/lib/select.h index e012c63f3..56729a3b2 100644 --- a/lib/select.h +++ b/lib/select.h @@ -89,9 +89,27 @@ int Curl_socket_ready(curl_socket_t readfd, curl_socket_t writefd, int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms); +int Curl_wait_ms(int timeout_ms); + #ifdef TPF int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes, fd_set* excepts, struct timeval* tv); #endif +/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which + unfortunately makes it impossible for us to easily check if they're valid +*/ +#if defined(USE_WINSOCK) || defined(TPF) +#define VALID_SOCK(x) 1 +#define VERIFY_SOCK(x) Curl_nop_stmt +#else +#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE)) +#define VERIFY_SOCK(x) do { \ + if(!VALID_SOCK(x)) { \ + SET_SOCKERRNO(EINVAL); \ + return -1; \ + } \ +} WHILE_FALSE +#endif + #endif /* __SELECT_H */ diff --git a/lib/sendf.c b/lib/sendf.c index 0172ae7c3..847090be3 100644 --- a/lib/sendf.c +++ b/lib/sendf.c @@ -22,11 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <errno.h> - #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> /* required for send() & recv() prototypes */ #endif @@ -55,7 +50,6 @@ #define Curl_sec_read(a,b,c,d) -1 #endif -#include <string.h> #include "curl_memory.h" #include "strerror.h" @@ -79,7 +73,7 @@ static size_t convert_lineends(struct SessionHandle *data, return(size); } - if(data->state.prev_block_had_trailing_cr == TRUE) { + 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') { @@ -533,17 +527,17 @@ CURLcode Curl_read_plain(curl_socket_t sockfd, * Returns a regular CURLcode value. */ CURLcode Curl_read(struct connectdata *conn, /* connection data */ - 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 */ + 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 curlcode = CURLE_RECV_ERROR; ssize_t nread = 0; size_t bytesfromsocket = 0; char *buffertofill = NULL; - bool pipelining = (bool)(conn->data->multi && - Curl_multi_canPipeline(conn->data->multi)); + bool pipelining = (conn->data->multi && + Curl_multi_canPipeline(conn->data->multi)) ? TRUE : FALSE; /* 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 diff --git a/lib/sendf.h b/lib/sendf.h index 8f0ea24d7..39911d016 100644 --- a/lib/sendf.h +++ b/lib/sendf.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -32,9 +32,9 @@ void Curl_failf(struct SessionHandle *, const char *fmt, ...); #if defined(CURL_DISABLE_VERBOSE_STRINGS) #if defined(HAVE_VARIADIC_MACROS_C99) -#define infof(...) do { } while (0) +#define infof(...) Curl_nop_stmt #elif defined(HAVE_VARIADIC_MACROS_GCC) -#define infof(x...) do { } while (0) +#define infof(x...) Curl_nop_stmt #else #define infof (void) #endif diff --git a/lib/setup.h b/lib/setup.h index 1e96c76dd..84c9b1feb 100644 --- a/lib/setup.h +++ b/lib/setup.h @@ -251,6 +251,12 @@ # endif #endif +#ifdef USE_LWIPSOCK +# include <lwip/init.h> +# include <lwip/sockets.h> +# include <lwip/netdb.h> +#endif + #ifdef HAVE_EXTRA_STRICMP_H # include <extra/stricmp.h> #endif @@ -279,7 +285,6 @@ #ifdef HAVE_ASSERT_H #include <assert.h> #endif -#include <errno.h> #ifdef __TANDEM /* for nsr-tandem-nsk systems */ #include <floss.h> @@ -563,6 +568,7 @@ int netware_init(void); #define USE_HTTP_NEGOTIATE #endif +/* Single point where USE_NTLM definition might be done */ #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM) #if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || \ defined(USE_GNUTLS) || defined(USE_NSS) @@ -580,6 +586,15 @@ int netware_init(void); #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) #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. */ +#ifndef __GNUC__ +#define UNUSED_PARAM /*NOTHING*/ +#else +#define UNUSED_PARAM __attribute__((unused)) +#endif + /* * Include macros and defines that should only be processed once. */ @@ -588,4 +603,27 @@ int netware_init(void); #include "setup_once.h" #endif +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } WHILE_FALSE +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + +#if defined(__LWIP_OPT_H__) +# if defined(SOCKET) || \ + defined(USE_WINSOCK) || \ + defined(HAVE_ERRNO_H) || \ + defined(HAVE_WINSOCK_H) || \ + defined(HAVE_WINSOCK2_H) || \ + defined(HAVE_WS2TCPIP_H) +# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + #endif /* HEADER_CURL_LIB_SETUP_H */ diff --git a/lib/setup_once.h b/lib/setup_once.h index b449807db..8bdb472df 100644 --- a/lib/setup_once.h +++ b/lib/setup_once.h @@ -42,7 +42,10 @@ #include <string.h> #include <stdarg.h> #include <ctype.h> + +#ifdef HAVE_ERRNO_H #include <errno.h> +#endif #ifdef HAVE_SYS_TYPES_H #include <sys/types.h> @@ -254,10 +257,13 @@ struct timeval { #define ISPRINT(x) (isprint((int) ((unsigned char)x))) #define ISUPPER(x) (isupper((int) ((unsigned char)x))) #define ISLOWER(x) (islower((int) ((unsigned char)x))) +#define ISASCII(x) (isascii((int) ((unsigned char)x))) #define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \ (((unsigned char)x) == '\t')) +#define TOLOWER(x) (tolower((int) ((unsigned char)x))) + /* * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms. @@ -300,6 +306,27 @@ struct timeval { /* + * Macro WHILE_FALSE may be used to build single-iteration do-while loops, + * avoiding compiler warnings. Mostly intended for other macro definitions. + */ + +#define WHILE_FALSE while(0) + +#if defined(_MSC_VER) && !defined(__POCC__) +# undef WHILE_FALSE +# if (_MSC_VER < 1500) +# define WHILE_FALSE while(1, 0) +# else +# define WHILE_FALSE \ +__pragma(warning(push)) \ +__pragma(warning(disable:4127)) \ +while(0) \ +__pragma(warning(pop)) +# endif +#endif + + +/* * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type. */ @@ -336,7 +363,7 @@ typedef int sig_atomic_t; #ifdef DEBUGBUILD #define DEBUGF(x) x #else -#define DEBUGF(x) do { } while (0) +#define DEBUGF(x) do { } WHILE_FALSE #endif @@ -347,7 +374,7 @@ typedef int sig_atomic_t; #if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H) #define DEBUGASSERT(x) assert(x) #else -#define DEBUGASSERT(x) do { } while (0) +#define DEBUGASSERT(x) do { } WHILE_FALSE #endif @@ -487,5 +514,5 @@ typedef int sig_atomic_t; #define ZERO_NULL 0 -#endif /* __SETUP_ONCE_H */ +#endif /* __SETUP_ONCE_H */ diff --git a/lib/share.c b/lib/share.c index 33dcecf4c..71c2ef308 100644 --- a/lib/share.c +++ b/lib/share.c @@ -21,12 +21,11 @@ ***************************************************************************/ #include "setup.h" -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> + #include <curl/curl.h> #include "urldata.h" #include "share.h" +#include "sslgen.h" #include "curl_memory.h" /* The last #include file should be: */ @@ -74,17 +73,32 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) } break; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) 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) return CURLSHE_NOMEM; } break; -#endif /* CURL_DISABLE_HTTP */ +#else /* CURL_DISABLE_HTTP */ + return CURLSHE_NOT_BUILT_IN; +#endif + + case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(!share->sslsession) { + share->nsslsession = 8; + share->sslsession = calloc(share->nsslsession, + sizeof(struct curl_ssl_session)); + if(!share->sslsession) + return CURLSHE_NOMEM; + } + break; +#else + return CURLSHE_NOT_BUILT_IN; +#endif - case CURL_LOCK_DATA_SSL_SESSION: /* not supported (yet) */ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */ default: @@ -104,17 +118,28 @@ curl_share_setopt(CURLSH *sh, CURLSHoption option, ...) } break; -#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) case CURL_LOCK_DATA_COOKIE: +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(share->cookies) { Curl_cookie_cleanup(share->cookies); share->cookies = NULL; } break; -#endif /* CURL_DISABLE_HTTP */ +#else /* CURL_DISABLE_HTTP */ + return CURLSHE_NOT_BUILT_IN; +#endif case CURL_LOCK_DATA_SSL_SESSION: +#ifdef USE_SSL + if(share->sslsession) { + free(share->sslsession); + share->sslsession = NULL; + share->nsslsession = 0; + } break; +#else + return CURLSHE_NOT_BUILT_IN; +#endif case CURL_LOCK_DATA_CONNECT: break; @@ -169,8 +194,19 @@ curl_share_cleanup(CURLSH *sh) share->hostcache = NULL; } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(share->cookies) Curl_cookie_cleanup(share->cookies); +#endif + +#ifdef USE_SSL + if(share->sslsession) { + unsigned int i; + for(i = 0; i < share->nsslsession; ++i) + Curl_ssl_kill_session(&(share->sslsession[i])); + free(share->sslsession); + } +#endif if(share->unlockfunc) share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata); diff --git a/lib/share.h b/lib/share.h index ea8e233d2..c9546567d 100644 --- a/lib/share.h +++ b/lib/share.h @@ -8,7 +8,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2005, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -26,6 +26,7 @@ #include "setup.h" #include <curl/curl.h> #include "cookie.h" +#include "urldata.h" /* SalfordC says "A structure member may not be volatile". Hence: */ @@ -45,7 +46,12 @@ struct Curl_share { void *clientdata; struct curl_hash *hostcache; +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) struct CookieInfo *cookies; +#endif + + struct curl_ssl_session *sslsession; + unsigned int nsslsession; }; CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data, diff --git a/lib/slist.c b/lib/slist.c index e2006f4be..4ddebb609 100644 --- a/lib/slist.c +++ b/lib/slist.c @@ -22,11 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> - -#include <string.h> #include "curl_memory.h" #include "slist.h" @@ -124,10 +119,7 @@ void curl_slist_free_all(struct curl_slist *list) item = list; do { next = item->next; - - if(item->data) { - free(item->data); - } + Curl_safefree(item->data); free(item); item = next; } while(next); diff --git a/lib/smtp.c b/lib/smtp.c index 1626ae7da..8835b07a5 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -29,11 +29,6 @@ #include "setup.h" #ifndef CURL_DISABLE_SMTP -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> #ifdef HAVE_UNISTD_H #include <unistd.h> @@ -90,6 +85,7 @@ #include "curl_md5.h" #include "curl_hmac.h" #include "curl_gethostname.h" +#include "curl_ntlm_msgs.h" #include "warnless.h" #include "http_proxy.h" @@ -116,7 +112,6 @@ static CURLcode smtp_doing(struct connectdata *conn, static CURLcode smtp_setup_connection(struct connectdata * conn); static CURLcode smtp_state_upgrade_tls(struct connectdata *conn); - /* * SMTP protocol handler. */ @@ -132,6 +127,7 @@ const struct Curl_handler Curl_handler_smtp = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -140,7 +136,6 @@ const struct Curl_handler Curl_handler_smtp = { PROTOPT_CLOSEACTION /* flags */ }; - #ifdef USE_SSL /* * SMTPS protocol handler. @@ -157,6 +152,7 @@ const struct Curl_handler Curl_handler_smtps = { smtp_doing, /* doing */ smtp_getsock, /* proto_getsock */ smtp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ smtp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -182,6 +178,7 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -190,7 +187,6 @@ static const struct Curl_handler Curl_handler_smtp_proxy = { PROTOPT_NONE /* flags */ }; - #ifdef USE_SSL /* * HTTP-proxyed SMTPS protocol handler. @@ -207,6 +203,7 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -217,7 +214,6 @@ static const struct Curl_handler Curl_handler_smtps_proxy = { #endif #endif - /* Function that checks for an ending smtp status code at the start of the given string. As a side effect, it also flags allowed authentication mechanisms according @@ -272,6 +268,8 @@ static int smtp_endofresp(struct pingpong *pp, int *resp) smtpc->authmechs |= SMTP_AUTH_GSSAPI; else if(wordlen == 8 && !memcmp(line, "EXTERNAL", 8)) smtpc->authmechs |= SMTP_AUTH_EXTERNAL; + else if(wordlen == 4 && !memcmp(line, "NTLM", 4)) + smtpc->authmechs |= SMTP_AUTH_NTLM; line += wordlen; len -= wordlen; @@ -288,7 +286,7 @@ static void state(struct connectdata *conn, struct smtp_conn *smtpc = &conn->proto.smtpc; #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) /* for debug purposes */ - static const char * const names[]={ + static const char * const names[] = { "STOP", "SERVERGREET", "EHLO", @@ -299,6 +297,8 @@ static void state(struct connectdata *conn, "AUTHLOGIN", "AUTHPASSWD", "AUTHCRAM", + "AUTHNTLM", + "AUTHNTLM_TYPE2MSG", "AUTH", "MAIL", "RCPT", @@ -320,6 +320,8 @@ static CURLcode smtp_state_ehlo(struct connectdata *conn) struct smtp_conn *smtpc = &conn->proto.smtpc; smtpc->authmechs = 0; /* No known authentication mechanisms yet. */ + smtpc->authused = 0; /* Clear the authentication mechanism used + for esmtp connections */ /* send EHLO */ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain); @@ -336,6 +338,9 @@ static CURLcode smtp_state_helo(struct connectdata *conn) CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; + smtpc->authused = 0; /* No authentication mechanism used in smtp + connections */ + /* send HELO */ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain); @@ -346,7 +351,8 @@ static CURLcode smtp_state_helo(struct connectdata *conn) return CURLE_OK; } -static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_plain_data(struct connectdata *conn, + char **outptr, size_t *outlen) { char plainauth[2 * MAX_CURL_USER_LENGTH + MAX_CURL_PASSWORD_LENGTH]; size_t ulen; @@ -355,8 +361,11 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) ulen = strlen(conn->user); plen = strlen(conn->passwd); - if(2 * ulen + plen + 2 > sizeof plainauth) - return 0; + if(2 * ulen + plen + 2 > sizeof plainauth) { + *outlen = 0; + *outptr = NULL; + return CURLE_OUT_OF_MEMORY; /* plainauth too small */ + } memcpy(plainauth, conn->user, ulen); plainauth[ulen] = '\0'; @@ -364,89 +373,108 @@ static size_t smtp_auth_plain_data(struct connectdata * conn, char * * outptr) plainauth[2 * ulen + 1] = '\0'; memcpy(plainauth + 2 * ulen + 2, conn->passwd, plen); return Curl_base64_encode(conn->data, plainauth, 2 * ulen + plen + 2, - outptr); + outptr, outlen); } -static size_t smtp_auth_login_user(struct connectdata * conn, char * * outptr) +static CURLcode smtp_auth_login_user(struct connectdata *conn, + char **outptr, size_t *outlen) { - size_t ulen; - - ulen = strlen(conn->user); + size_t ulen = strlen(conn->user); if(!ulen) { *outptr = strdup("="); - return *outptr? 1: 0; + if(*outptr) { + *outlen = (size_t) 1; + return CURLE_OK; + } + *outlen = 0; + return CURLE_OUT_OF_MEMORY; } - return Curl_base64_encode(conn->data, conn->user, ulen, outptr); + return Curl_base64_encode(conn->data, conn->user, ulen, outptr, outlen); +} + +#ifdef USE_NTLM +static CURLcode smtp_auth_ntlm_type1_message(struct connectdata *conn, + char **outptr, size_t *outlen) +{ + return Curl_ntlm_create_type1_message(conn->user, conn->passwd, + &conn->ntlm, outptr, outlen); } +#endif static CURLcode smtp_authenticate(struct connectdata *conn) { CURLcode result = CURLE_OK; struct smtp_conn *smtpc = &conn->proto.smtpc; - char * initresp; - const char * mech; - size_t l; - smtpstate state1; - smtpstate state2; - - if(!conn->bits.user_passwd) - state(conn, SMTP_STOP); /* End of connect phase. */ - else { - initresp = (char *) NULL; - l = 1; + char *initresp = NULL; + const char *mech = NULL; + size_t len = 0; + smtpstate state1 = SMTP_STOP; + smtpstate state2 = SMTP_STOP; + + /* Check we have a username and password to authenticate with and end the + connect phase if we don't. */ + if(!conn->bits.user_passwd) { + state(conn, SMTP_STOP); - /* Check supported authentication mechanisms by decreasing order of - preference. */ - mech = (const char *) NULL; /* Avoid compiler warnings. */ - state1 = SMTP_STOP; - state2 = SMTP_STOP; + return result; + } + /* Check supported authentication mechanisms by decreasing order of + security. */ #ifndef CURL_DISABLE_CRYPTO_AUTH - if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { - mech = "CRAM-MD5"; - state1 = SMTP_AUTHCRAM; - } - else + if(smtpc->authmechs & SMTP_AUTH_CRAM_MD5) { + mech = "CRAM-MD5"; + state1 = SMTP_AUTHCRAM; + smtpc->authused = SMTP_AUTH_CRAM_MD5; + } + else #endif - if(smtpc->authmechs & SMTP_AUTH_PLAIN) { - mech = "PLAIN"; - state1 = SMTP_AUTHPLAIN; - state2 = SMTP_AUTH; - l = smtp_auth_plain_data(conn, &initresp); - } - else if(smtpc->authmechs & SMTP_AUTH_LOGIN) { - mech = "LOGIN"; - state1 = SMTP_AUTHLOGIN; - state2 = SMTP_AUTHPASSWD; - l = smtp_auth_login_user(conn, &initresp); - } - else { - infof(conn->data, "No known auth mechanisms supported!\n"); - result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ - } +#ifdef USE_NTLM + if(smtpc->authmechs & SMTP_AUTH_NTLM) { + mech = "NTLM"; + state1 = SMTP_AUTHNTLM; + state2 = SMTP_AUTHNTLM_TYPE2MSG; + smtpc->authused = SMTP_AUTH_NTLM; + result = smtp_auth_ntlm_type1_message(conn, &initresp, &len); + } + else +#endif + if(smtpc->authmechs & SMTP_AUTH_LOGIN) { + mech = "LOGIN"; + state1 = SMTP_AUTHLOGIN; + state2 = SMTP_AUTHPASSWD; + smtpc->authused = SMTP_AUTH_LOGIN; + result = smtp_auth_login_user(conn, &initresp, &len); + } + else if(smtpc->authmechs & SMTP_AUTH_PLAIN) { + mech = "PLAIN"; + state1 = SMTP_AUTHPLAIN; + state2 = SMTP_AUTH; + smtpc->authused = SMTP_AUTH_PLAIN; + result = smtp_auth_plain_data(conn, &initresp, &len); + } + else { + infof(conn->data, "No known auth mechanisms supported!\n"); + result = CURLE_LOGIN_DENIED; /* Other mechanisms not supported. */ + } - if(!result) { - if(!l) - result = CURLE_OUT_OF_MEMORY; - else if(initresp && - l + strlen(mech) <= 512 - 8) { /* AUTH <mech> ...<crlf> */ - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - free(initresp); + if(!result) { + if(initresp && + strlen(mech) + len <= 512 - 8) { /* AUTH <mech> ...<crlf> */ + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp); - if(!result) - state(conn, state2); - } - else { - Curl_safefree(initresp); - - result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); + if(!result) + state(conn, state2); + } + else { + result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech); - if(!result) - state(conn, state1); - } + if(!result) + state(conn, state1); } + Curl_safefree(initresp); } return result; @@ -466,7 +494,7 @@ static void smtp_to_smtps(struct connectdata *conn) conn->handler = &Curl_handler_smtps; } #else -#define smtp_to_smtps(x) +#define smtp_to_smtps(x) Curl_nop_stmt #endif /* for STARTTLS responses */ @@ -499,6 +527,7 @@ static CURLcode smtp_state_starttls_resp(struct connectdata *conn, } } } + return result; } @@ -566,6 +595,7 @@ static CURLcode smtp_state_helo_resp(struct connectdata *conn, /* end the connect phase */ state(conn, SMTP_STOP); } + return result; } @@ -576,8 +606,8 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * plainauth; + size_t len = 0; + char *plainauth = NULL; (void)instate; /* no use for this yet */ @@ -586,16 +616,16 @@ static CURLcode smtp_state_authplain_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_plain_data(conn, &plainauth); + result = smtp_auth_plain_data(conn, &plainauth, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - free(plainauth); + if(!result) { + if(plainauth) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(plainauth); } } @@ -609,8 +639,8 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, { CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; - size_t l; - char * authuser; + size_t len = 0; + char *authuser = NULL; (void)instate; /* no use for this yet */ @@ -619,16 +649,16 @@ static CURLcode smtp_state_authlogin_resp(struct connectdata *conn, result = CURLE_LOGIN_DENIED; } else { - l = smtp_auth_login_user(conn, &authuser); + result = smtp_auth_login_user(conn, &authuser, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - free(authuser); + if(!result) { + if(authuser) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser); - if(!result) - state(conn, SMTP_AUTHPASSWD); + if(!result) + state(conn, SMTP_AUTHPASSWD); + } + Curl_safefree(authuser); } } @@ -643,8 +673,8 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; size_t plen; - size_t l; - char *authpasswd; + size_t len = 0; + char *authpasswd = NULL; (void)instate; /* no use for this yet */ @@ -658,16 +688,16 @@ static CURLcode smtp_state_authpasswd_resp(struct connectdata *conn, if(!plen) result = Curl_pp_sendf(&conn->proto.smtpc.pp, "="); else { - l = Curl_base64_encode(data, conn->passwd, plen, &authpasswd); + result = Curl_base64_encode(data, conn->passwd, plen, &authpasswd, &len); - if(!l) - result = CURLE_OUT_OF_MEMORY; - else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - free(authpasswd); + if(!result) { + if(authpasswd) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd); - if(!result) - state(conn, SMTP_AUTH); + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(authpasswd); } } } @@ -687,9 +717,9 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, char * chlg64 = data->state.buffer; unsigned char * chlg; size_t chlglen; - size_t l; - char * rplyb64; - HMAC_context * ctxt; + size_t len = 0; + char *rplyb64 = NULL; + HMAC_context *ctxt; unsigned char digest[16]; char reply[MAX_CURL_USER_LENGTH + 32 /* 2 * size of MD5 digest */ + 1]; @@ -708,17 +738,17 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, chlglen = 0; if(*chlg64 != '=') { - for(l = strlen(chlg64); l--;) - if(chlg64[l] != '\r' && chlg64[l] != '\n' && chlg64[l] != ' ' && - chlg64[l] != '\t') + for(len = strlen(chlg64); len--;) + if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' && + chlg64[len] != '\t') break; - if(++l) { - chlg64[l] = '\0'; + if(++len) { + chlg64[len] = '\0'; - chlglen = Curl_base64_decode(chlg64, &chlg); - if(!chlglen) - return CURLE_OUT_OF_MEMORY; + result = Curl_base64_decode(chlg64, &chlg, &chlglen); + if(result) + return result; } } @@ -728,17 +758,14 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, (unsigned int)(strlen(conn->passwd))); if(!ctxt) { - if(chlg) - free(chlg); - + Curl_safefree(chlg); return CURLE_OUT_OF_MEMORY; } if(chlglen > 0) Curl_HMAC_update(ctxt, chlg, (unsigned int)(chlglen)); - if(chlg) - free(chlg); + Curl_safefree(chlg); Curl_HMAC_final(ctxt, digest); @@ -751,21 +778,94 @@ static CURLcode smtp_state_authcram_resp(struct connectdata *conn, digest[12], digest[13], digest[14], digest[15]); /* Encode it to base64 and send it. */ - l = Curl_base64_encode(data, reply, 0, &rplyb64); + result = Curl_base64_encode(data, reply, 0, &rplyb64, &len); + + if(!result) { + if(rplyb64) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); + + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(rplyb64); + } + + return result; +} + +#endif - if(!l) - result = CURLE_OUT_OF_MEMORY; +#ifdef USE_NTLM +/* for the AUTH NTLM (without initial response) response. */ +static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type1msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(smtpcode != 334) { + failf(data, "Access denied: %d", smtpcode); + result = CURLE_LOGIN_DENIED; + } else { - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64); - free(rplyb64); + result = smtp_auth_ntlm_type1_message(conn, &type1msg, &len); - if(!result) - state(conn, SMTP_AUTH); + if(!result) { + if(type1msg) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg); + + if(!result) + state(conn, SMTP_AUTHNTLM_TYPE2MSG); + } + Curl_safefree(type1msg); + } } return result; } +/* for the NTLM type-2 response (sent in reponse to our type-1 message). */ +static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn, + int smtpcode, + smtpstate instate) +{ + CURLcode result = CURLE_OK; + struct SessionHandle *data = conn->data; + char *type3msg = NULL; + size_t len = 0; + + (void)instate; /* no use for this yet */ + + if(smtpcode != 334) { + failf(data, "Access denied: %d", smtpcode); + result = CURLE_LOGIN_DENIED; + } + else { + result = Curl_ntlm_decode_type2_message(data, data->state.buffer + 4, + &conn->ntlm); + if(!result) { + result = Curl_ntlm_create_type3_message(conn->data, conn->user, + conn->passwd, &conn->ntlm, + &type3msg, &len); + if(!result) { + if(type3msg) { + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg); + + if(!result) + state(conn, SMTP_AUTH); + } + Curl_safefree(type3msg); + } + } + } + + return result; +} #endif /* for final responses to AUTH sequences. */ @@ -791,20 +891,49 @@ static CURLcode smtp_state_auth_resp(struct connectdata *conn, /* start the DO phase */ static CURLcode smtp_mail(struct connectdata *conn) { + char *from = NULL; + char *size = NULL; CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; + /* calculate the FROM parameter */ + if(!data->set.str[STRING_MAIL_FROM]) + /* null reverse-path, RFC-2821, sect. 3.7 */ + from = strdup("<>"); + else if(data->set.str[STRING_MAIL_FROM][0] == '<') + from = aprintf("%s", data->set.str[STRING_MAIL_FROM]); + else + from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]); + + if(!from) + return CURLE_OUT_OF_MEMORY; + + /* calculate the optional SIZE parameter */ + if(conn->data->set.infilesize > 0) { + size = aprintf("%" FORMAT_OFF_T, data->set.infilesize); + + if(!size) { + Curl_safefree(from); + + return CURLE_OUT_OF_MEMORY; + } + } + /* send MAIL FROM */ - if(data->set.str[STRING_MAIL_FROM][0] == '<') - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", - data->set.str[STRING_MAIL_FROM]); + if(!size) + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s", from); else - result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:<%s>", - data->set.str[STRING_MAIL_FROM]); + result = Curl_pp_sendf(&conn->proto.smtpc.pp, "MAIL FROM:%s SIZE=%s", + from, size); + + Curl_safefree(size); + Curl_safefree(from); + if(result) return result; state(conn, SMTP_MAIL); + return result; } @@ -824,6 +953,7 @@ static CURLcode smtp_rcpt_to(struct connectdata *conn) if(!result) state(conn, SMTP_RCPT); } + return result; } @@ -884,6 +1014,7 @@ static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, state(conn, SMTP_DATA); } + return result; } @@ -924,6 +1055,7 @@ static CURLcode smtp_state_postdata_resp(struct connectdata *conn, result = CURLE_RECV_ERROR; state(conn, SMTP_STOP); + return result; } @@ -931,7 +1063,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) { CURLcode result; curl_socket_t sock = conn->sock[FIRSTSOCKET]; - struct SessionHandle *data=conn->data; + struct SessionHandle *data = conn->data; int smtpcode; struct smtp_conn *smtpc = &conn->proto.smtpc; struct pingpong *pp = &smtpc->pp; @@ -993,6 +1125,17 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; #endif +#ifdef USE_NTLM + case SMTP_AUTHNTLM: + result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state); + break; + + case SMTP_AUTHNTLM_TYPE2MSG: + result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode, + smtpc->state); + break; +#endif + case SMTP_AUTH: result = smtp_state_auth_resp(conn, smtpcode, smtpc->state); break; @@ -1021,6 +1164,7 @@ static CURLcode smtp_statemach_act(struct connectdata *conn) break; } } + return result; } @@ -1036,7 +1180,7 @@ static CURLcode smtp_multi_statemach(struct connectdata *conn, else result = Curl_pp_multi_statemach(&smtpc->pp); - *done = (bool)(smtpc->state == SMTP_STOP); + *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE; return result; } @@ -1087,20 +1231,20 @@ static CURLcode smtp_init(struct connectdata *conn) * smtp_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 is not. When called as - * a part of the easy interface, it will always be TRUE. + * 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. When + * called as a part of the easy interface, it will always be TRUE. */ static CURLcode smtp_connect(struct connectdata *conn, bool *done) /* see description above */ { CURLcode result; struct smtp_conn *smtpc = &conn->proto.smtpc; - struct SessionHandle *data=conn->data; - struct pingpong *pp=&smtpc->pp; + struct SessionHandle *data = conn->data; + struct pingpong *pp = &smtpc->pp; const char *path = conn->data->state.path; int len; - char localhost[1024 + 1]; + char localhost[HOSTNAME_MAX + 1]; *done = FALSE; /* default to not done yet */ @@ -1204,7 +1348,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, { struct SessionHandle *data = conn->data; struct FTP *smtp = data->state.proto.smtp; - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; ssize_t bytes_written; (void)premature; @@ -1234,7 +1378,7 @@ static CURLcode smtp_done(struct connectdata *conn, CURLcode status, if(status == CURLE_OK) { struct smtp_conn *smtpc = &conn->proto.smtpc; - struct pingpong *pp= &smtpc->pp; + struct pingpong *pp = &smtpc->pp; pp->response = Curl_tvnow(); /* timeout relative now */ state(conn, SMTP_POSTDATA); @@ -1268,7 +1412,7 @@ CURLcode smtp_perform(struct connectdata *conn, bool *dophase_done) { /* this is SMTP and no proxy */ - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; DEBUGF(infof(conn->data, "DO phase starts\n")); @@ -1292,7 +1436,7 @@ CURLcode smtp_perform(struct connectdata *conn, result = smtp_easy_statemach(conn); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -1361,9 +1505,10 @@ static CURLcode smtp_quit(struct connectdata *conn) * Disconnect from an SMTP server. Cleanup protocol-specific per-connection * resources. BLOCKING. */ -static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) +static CURLcode smtp_disconnect(struct connectdata *conn, + bool dead_connection) { - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; /* We cannot send quit unconditionally. If this connection is stale or bad in any way, sending quit and waiting around here will make the @@ -1377,6 +1522,13 @@ static CURLcode smtp_disconnect(struct connectdata *conn, bool dead_connection) Curl_pp_disconnect(&smtpc->pp); +#ifdef USE_NTLM + /* Cleanup the ntlm structure */ + if(smtpc->authused == SMTP_AUTH_NTLM) { + Curl_ntlm_sspi_cleanup(&conn->ntlm); + } +#endif + /* This won't already be freed in some error cases */ Curl_safefree(smtpc->domain); smtpc->domain = NULL; @@ -1389,7 +1541,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected) { struct FTP *smtp = conn->data->state.proto.smtp; - struct smtp_conn *smtpc= &conn->proto.smtpc; + struct smtp_conn *smtpc = &conn->proto.smtpc; (void)connected; if(smtp->transfer != FTPTRANSFER_BODY) @@ -1404,7 +1556,7 @@ static CURLcode smtp_dophase_done(struct connectdata *conn, /* called from multi.c while DOing */ static CURLcode smtp_doing(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { CURLcode result; result = smtp_multi_statemach(conn, dophase_done); @@ -1414,6 +1566,7 @@ static CURLcode smtp_doing(struct connectdata *conn, DEBUGF(infof(conn->data, "DO phase is complete\n")); } + return result; } @@ -1428,10 +1581,10 @@ static CURLcode smtp_doing(struct connectdata *conn, */ static CURLcode smtp_regular_transfer(struct connectdata *conn, - bool *dophase_done) + bool *dophase_done) { - CURLcode result=CURLE_OK; - bool connected=FALSE; + CURLcode result = CURLE_OK; + bool connected = FALSE; struct SessionHandle *data = conn->data; data->req.size = -1; /* make sure this is unknown at this point */ @@ -1458,7 +1611,7 @@ CURLcode smtp_regular_transfer(struct connectdata *conn, return result; } -static CURLcode smtp_setup_connection(struct connectdata * conn) +static CURLcode smtp_setup_connection(struct connectdata *conn) { struct SessionHandle *data = conn->data; @@ -1505,42 +1658,43 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) struct SessionHandle *data = conn->data; if(data->state.scratch == NULL) - data->state.scratch = malloc(2*BUFSIZE); + data->state.scratch = malloc(2 * BUFSIZE); if(data->state.scratch == NULL) { failf (data, "Failed to alloc scratch buffer!"); return CURLE_OUT_OF_MEMORY; } /* This loop can be improved by some kind of Boyer-Moore style of approach but that is saved for later... */ - for(i = 0, si = 0; i < nread; i++, si++) { - ssize_t left = nread - i; - - if(left>= (ssize_t)(SMTP_EOB_LEN-smtpc->eob)) { - if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - SMTP_EOB_LEN-smtpc->eob)) { - /* It matched, copy the replacement data to the target buffer - instead. Note that the replacement does not contain the - trailing CRLF but we instead continue to match on that one - to deal with repeated sequences. Like CRLF.CRLF.CRLF etc - */ - memcpy(&data->state.scratch[si], SMTP_EOB_REPL, - SMTP_EOB_REPL_LEN); - si+=SMTP_EOB_REPL_LEN-1; /* minus one since the for() increments - it */ - i+=SMTP_EOB_LEN-smtpc->eob-1-2; - smtpc->eob = 0; /* start over */ - continue; - } + for(i = 0, si = 0; i < nread; i++) { + + if(SMTP_EOB[smtpc->eob] == data->req.upload_fromhere[i]) + smtpc->eob++; + else if(smtpc->eob) { + /* previously a substring matched, output that first */ + memcpy(&data->state.scratch[si], SMTP_EOB, smtpc->eob); + si += smtpc->eob; + + /* then compare the first byte */ + if(SMTP_EOB[0] == data->req.upload_fromhere[i]) + smtpc->eob = 1; + else + smtpc->eob = 0; } - else if(!memcmp(SMTP_EOB+smtpc->eob, &data->req.upload_fromhere[i], - left)) { - /* the last piece of the data matches the EOB so we can't send that - until we know the rest of it */ - smtpc->eob += left; - break; + + if(SMTP_EOB_LEN == smtpc->eob) { + /* It matched, copy the replacement data to the target buffer + instead. Note that the replacement does not contain the + trailing CRLF but we instead continue to match on that one + to deal with repeated sequences. Like CRLF.CRLF.CRLF etc + */ + memcpy(&data->state.scratch[si], SMTP_EOB_REPL, + SMTP_EOB_REPL_LEN); + si += SMTP_EOB_REPL_LEN; + smtpc->eob = 2; /* start over at two bytes */ } + else if(!smtpc->eob) + data->state.scratch[si++] = data->req.upload_fromhere[i]; - data->state.scratch[si] = data->req.upload_fromhere[i]; } /* for() */ if(si != nread) { @@ -1553,6 +1707,7 @@ CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread) /* set the new amount too */ data->req.upload_present = nread; } + return CURLE_OK; } diff --git a/lib/smtp.h b/lib/smtp.h index bc4b91eaa..144d49615 100644 --- a/lib/smtp.h +++ b/lib/smtp.h @@ -40,6 +40,8 @@ typedef enum { SMTP_AUTHLOGIN, SMTP_AUTHPASSWD, SMTP_AUTHCRAM, + SMTP_AUTHNTLM, + SMTP_AUTHNTLM_TYPE2MSG, SMTP_AUTH, SMTP_MAIL, /* MAIL FROM */ SMTP_RCPT, /* RCPT TO */ @@ -57,6 +59,7 @@ struct smtp_conn { size_t eob; /* number of bytes of the EOB (End Of Body) that has been received thus far */ unsigned int authmechs; /* Accepted authentication methods. */ + unsigned int authused; /* Authentication method used for the connection */ smtpstate state; /* always use smtp.c:state() to change state! */ struct curl_slist *rcpt; bool ssldone; /* is connect() over SSL done? only relevant in multi mode */ @@ -69,6 +72,7 @@ struct smtp_conn { #define SMTP_AUTH_DIGEST_MD5 0x0008 #define SMTP_AUTH_GSSAPI 0x0010 #define SMTP_AUTH_EXTERNAL 0x0020 +#define SMTP_AUTH_NTLM 0x0040 extern const struct Curl_handler Curl_handler_smtp; extern const struct Curl_handler Curl_handler_smtps; diff --git a/lib/socks.c b/lib/socks.c index 82293019b..b382de798 100644 --- a/lib/socks.c +++ b/lib/socks.c @@ -23,11 +23,7 @@ #include "setup.h" #if !defined(CURL_DISABLE_PROXY) || defined(USE_WINDOWS_SSPI) -#include <string.h> -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -60,28 +56,21 @@ int Curl_blockread_all(struct connectdata *conn, /* connection data */ curl_socket_t sockfd, /* read from this socket */ char *buf, /* store read data here */ ssize_t buffersize, /* max amount to read */ - ssize_t *n, /* amount bytes read */ - long conn_timeout) /* timeout for data wait - relative to - conn->created */ + ssize_t *n) /* amount bytes read */ { ssize_t nread; ssize_t allread = 0; int result; - struct timeval tvnow; - long conntime; + long timeleft; *n = 0; for(;;) { - tvnow = Curl_tvnow(); - /* calculating how long connection is establishing */ - conntime = Curl_tvdiff(tvnow, conn->created); - if(conntime > conn_timeout) { + timeleft = Curl_timeleft(conn->data, NULL, TRUE); + if(timeleft < 0) { /* we already got the timeout */ result = CURLE_OPERATION_TIMEDOUT; break; } - if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, - conn_timeout - conntime) <= 0) { + if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) { result = ~CURLE_OK; break; } @@ -133,13 +122,9 @@ CURLcode Curl_SOCKS4(const char *proxy_name, int result; CURLcode code; curl_socket_t sock = conn->sock[sockindex]; - long timeout; struct SessionHandle *data = conn->data; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - - if(timeout < 0) { + if(Curl_timeleft(data, NULL, TRUE) < 0) { /* time-out, bail out, go home */ failf(data, "Connection time-out"); return CURLE_OPERATION_TIMEDOUT; @@ -264,7 +249,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Receive response */ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); + &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS4 connect request ack."); return CURLE_COULDNT_CONNECT; @@ -299,10 +284,7 @@ CURLcode Curl_SOCKS4(const char *proxy_name, /* Result */ switch(socksreq[1]) { case 90: - if(protocol4a) - infof(data, "SOCKS4a request granted.\n"); - else - infof(data, "SOCKS4 request granted.\n"); + infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":""); break; case 91: failf(data, @@ -386,7 +368,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curl_socket_t sock = conn->sock[sockindex]; struct SessionHandle *data = conn->data; long timeout; - bool socks5_resolve_local = (bool)(conn->proxytype == CURLPROXY_SOCKS5); + bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE; const size_t hostname_len = strlen(hostname); ssize_t packetsize = 0; @@ -466,8 +448,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, curlx_nonblock(sock, FALSE); - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if((result != CURLE_OK) || (actualread != 2)) { failf(data, "Unable to receive initial SOCKS5 response."); return CURLE_COULDNT_CONNECT; @@ -527,8 +508,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, return CURLE_COULDNT_CONNECT; } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread, - timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread); if((result != CURLE_OK) || (actualread != 2)) { failf(data, "Unable to receive SOCKS5 sub-negotiation response."); return CURLE_COULDNT_CONNECT; @@ -664,7 +644,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, else #endif result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize, - &actualread, timeout); + &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; @@ -720,7 +700,7 @@ CURLcode Curl_SOCKS5(const char *proxy_name, if(packetsize > 10) { packetsize -= 10; result = Curl_blockread_all(conn, sock, (char *)&socksreq[10], - packetsize, &actualread, timeout); + packetsize, &actualread); if((result != CURLE_OK) || (actualread != packetsize)) { failf(data, "Failed to receive SOCKS5 connect request ack."); return CURLE_COULDNT_CONNECT; diff --git a/lib/socks.h b/lib/socks.h index 42b8080b0..fc4cc7f02 100644 --- a/lib/socks.h +++ b/lib/socks.h @@ -39,8 +39,7 @@ int Curl_blockread_all(struct connectdata *conn, curl_socket_t sockfd, char *buf, ssize_t buffersize, - ssize_t *n, - long conn_timeout); + ssize_t *n); /* * This function logs in to a SOCKS4(a) proxy and sends the specifics to the diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 653306cce..d23a944d7 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -27,16 +27,13 @@ #ifdef HAVE_GSSAPI #ifdef HAVE_OLD_GSSMIT #define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name +#define NCOMPAT 1 #endif #ifndef gss_nt_service_name #define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE #endif -#include <string.h> - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif +#include "curl_gssapi.h" #include "urldata.h" #include "sendf.h" #include "connect.h" @@ -121,7 +118,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; OM_uint32 gss_major_status, gss_minor_status, gss_status; OM_uint32 gss_ret_flags; int gss_conf_state, gss_enc; @@ -137,9 +133,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for gssapi exchange header only */ char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - /* GSSAPI request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | @@ -183,19 +176,14 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, /* As long as we need to keep sending some context info, and there's no */ /* errors, keep sending it... */ for(;;) { - gss_major_status = gss_init_sec_context(&gss_minor_status, - GSS_C_NO_CREDENTIAL, - &gss_context, server, - GSS_C_NULL_OID, - GSS_C_MUTUAL_FLAG | - GSS_C_REPLAY_FLAG, - 0, - NULL, - gss_token, - NULL, - &gss_send_token, - &gss_ret_flags, - NULL); + gss_major_status = Curl_gss_init_sec_context(data, + &gss_minor_status, + &gss_context, + server, + NULL, + gss_token, + &gss_send_token, + &gss_ret_flags); if(gss_token != GSS_C_NO_BUFFER) gss_release_buffer(&gss_status, &gss_recv_token); @@ -253,8 +241,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive GSSAPI authentication response."); gss_release_name(&gss_status, &server); @@ -294,8 +281,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive GSSAPI authentication token."); @@ -452,8 +438,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, gss_release_buffer(&gss_status, &gss_w_token); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive GSSAPI encryption response."); gss_delete_sec_context(&gss_status, &gss_context, NULL); @@ -485,8 +470,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value, - gss_recv_token.length, - &actualread, timeout); + gss_recv_token.length, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive GSSAPI encryptrion type."); diff --git a/lib/socks_sspi.c b/lib/socks_sspi.c index 6d42af3a5..d96a82e8a 100644 --- a/lib/socks_sspi.c +++ b/lib/socks_sspi.c @@ -20,17 +20,10 @@ * ***************************************************************************/ - #include "setup.h" #ifdef USE_WINDOWS_SSPI -#include <string.h> - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - #include "urldata.h" #include "sendf.h" #include "connect.h" @@ -167,7 +160,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, ssize_t actualread; ssize_t written; int result; - long timeout; /* Needs GSSAPI authentication */ SECURITY_STATUS sspi_major_status, sspi_minor_status=0; unsigned long sspi_ret_flags=0; @@ -186,9 +178,6 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, unsigned char socksreq[4]; /* room for gssapi exchange header only */ char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE]; - /* get timeout */ - timeout = Curl_timeleft(data, NULL, TRUE); - /* GSSAPI request looks like * +----+------+-----+----------------+ * |VER | MTYP | LEN | TOKEN | @@ -283,7 +272,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "InitializeSecurityContextA") ){ + "InitializeSecurityContextA") ) { free(service_name); service_name=NULL; s_pSecFn->FreeCredentialsHandle(&cred_handle); @@ -344,8 +333,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, * +----+------+-----+----------------+ */ - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive SSPI authentication response."); free(service_name); @@ -390,8 +378,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, return CURLE_OUT_OF_MEMORY; } result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer, - sspi_recv_token.cbBuffer, - &actualread, timeout); + sspi_recv_token.cbBuffer, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive SSPI authentication token."); @@ -416,7 +403,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, &names); s_pSecFn->FreeCredentialsHandle(&cred_handle); if(check_sspi_err(data,sspi_major_status,sspi_minor_status, - "QueryCredentialAttributes") ){ + "QueryCredentialAttributes") ) { s_pSecFn->DeleteSecurityContext(&sspi_context); s_pSecFn->FreeContextBuffer(names.sUserName); failf(data, "Failed to determine user name."); @@ -499,7 +486,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, sspi_w_token[1].cbBuffer = 1; sspi_w_token[1].pvBuffer = malloc(1); - if(!sspi_w_token[1].pvBuffer){ + if(!sspi_w_token[1].pvBuffer) { s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer); s_pSecFn->DeleteSecurityContext(&sspi_context); return CURLE_OUT_OF_MEMORY; @@ -592,8 +579,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer); } - result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, - &actualread, timeout); + result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread); if(result != CURLE_OK || actualread != 4) { failf(data, "Failed to receive SSPI encryption response."); s_pSecFn->DeleteSecurityContext(&sspi_context); @@ -626,8 +612,7 @@ CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex, } result=Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer, - sspi_w_token[0].cbBuffer, - &actualread, timeout); + sspi_w_token[0].cbBuffer, &actualread); if(result != CURLE_OK || actualread != us_length) { failf(data, "Failed to receive SSPI encryption type."); diff --git a/lib/speedcheck.c b/lib/speedcheck.c index 56ac34aef..ca2323f57 100644 --- a/lib/speedcheck.c +++ b/lib/speedcheck.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <stdio.h> -#include <string.h> - #include <curl/curl.h> #include "urldata.h" #include "sendf.h" @@ -44,12 +41,12 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, (Curl_tvlong(data->state.keeps_speed) != 0) && (data->progress.current_speed < data->set.low_speed_limit)) { long howlong = Curl_tvdiff(now, data->state.keeps_speed); + long nextcheck = (data->set.low_speed_time * 1000) - howlong; /* We are now below the "low speed limit". If we are below it for "low speed time" seconds we consider that enough reason to abort the download. */ - - if((howlong/1000) > data->set.low_speed_time) { + if(nextcheck <= 0) { /* we have been this slow for long enough, now die */ failf(data, "Operation too slow. " @@ -58,7 +55,10 @@ CURLcode Curl_speedcheck(struct SessionHandle *data, data->set.low_speed_time); return CURLE_OPERATION_TIMEDOUT; } - Curl_expire(data, howlong); + else { + /* wait complete low_speed_time */ + Curl_expire(data, nextcheck); + } } else { /* we keep up the required speed all right */ diff --git a/lib/splay.h b/lib/splay.h index 832e4e2bb..49a6dec41 100644 --- a/lib/splay.h +++ b/lib/splay.h @@ -1,5 +1,5 @@ -#ifndef __SPLAY_H -#define __SPLAY_H +#ifndef HEADER_CURL_SPLAY_H +#define HEADER_CURL_SPLAY_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1997 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1997 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" struct Curl_tree { struct Curl_tree *smaller; /* smaller node */ @@ -59,7 +60,7 @@ int Curl_splayremovebyaddr(struct Curl_tree *t, #ifdef DEBUGBUILD void Curl_splayprint(struct Curl_tree * t, int d, char output); #else -#define Curl_splayprint(x,y,z) +#define Curl_splayprint(x,y,z) Curl_nop_stmt #endif -#endif +#endif /* HEADER_CURL_SPLAY_H */ @@ -25,11 +25,7 @@ #include "setup.h" #ifdef USE_LIBSSH2 -#include <stdio.h> -#include <string.h> -#include <stdlib.h> -#include <stdarg.h> -#include <ctype.h> + #ifdef HAVE_LIMITS_H # include <limits.h> #endif @@ -45,11 +41,6 @@ #include <fcntl.h> #endif -#ifdef HAVE_TIME_H -#include <time.h> -#endif - -#ifndef WIN32 #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -69,7 +60,6 @@ #include <in.h> #include <inet.h> #endif -#endif /* !WIN32 */ #if (defined(NETWARE) && defined(__NOVELL_LIBC__)) #undef in_addr_t @@ -108,6 +98,11 @@ /* The last #include file should be: */ #include "memdebug.h" +#ifdef WIN32 +# undef PATH_MAX +# define PATH_MAX MAX_PATH +#endif + #ifndef PATH_MAX #define PATH_MAX 1024 /* just an extra precaution since there are systems that have their definition hidden well */ @@ -170,6 +165,7 @@ const struct Curl_handler Curl_handler_scp = { scp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ scp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -194,6 +190,7 @@ const struct Curl_handler Curl_handler_sftp = { sftp_doing, /* doing */ ssh_getsock, /* proto_getsock */ ssh_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ssh_perform_getsock, /* perform_getsock */ sftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -649,6 +646,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) const char *fingerprint; #endif /* CURL_LIBSSH2_DEBUG */ const char *host_public_key_md5; + char *new_readdir_line; int rc = LIBSSH2_ERROR_NONE, i; int err; int seekerr = CURL_SEEKFUNC_OK; @@ -1581,7 +1579,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) SEEK_SET); } - if(seekerr != CURL_SEEKFUNC_OK){ + if(seekerr != CURL_SEEKFUNC_OK) { if(seekerr != CURL_SEEKFUNC_CANTSEEK) { failf(data, "Could not seek stream"); @@ -1864,10 +1862,13 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } Curl_safefree(sshc->readdir_linkPath); sshc->readdir_linkPath = NULL; - sshc->readdir_line = realloc(sshc->readdir_line, - sshc->readdir_totalLen + 4 + - sshc->readdir_len); - if(!sshc->readdir_line) { + + new_readdir_line = realloc(sshc->readdir_line, + sshc->readdir_totalLen + 4 + + sshc->readdir_len); + if(!new_readdir_line) { + Curl_safefree(sshc->readdir_line); + sshc->readdir_line = NULL; Curl_safefree(sshc->readdir_filename); sshc->readdir_filename = NULL; Curl_safefree(sshc->readdir_longentry); @@ -1876,6 +1877,7 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) sshc->actualcode = CURLE_OUT_OF_MEMORY; break; } + sshc->readdir_line = new_readdir_line; sshc->readdir_currLen += snprintf(sshc->readdir_line + sshc->readdir_currLen, @@ -2388,10 +2390,39 @@ static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block) } 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 + + Curl_safefree(sshc->rsa_pub); + Curl_safefree(sshc->rsa); + + Curl_safefree(sshc->quote_path1); + Curl_safefree(sshc->quote_path2); + + Curl_safefree(sshc->homedir); + + Curl_safefree(sshc->readdir_filename); + Curl_safefree(sshc->readdir_longentry); + Curl_safefree(sshc->readdir_line); + Curl_safefree(sshc->readdir_linkPath); + + /* the code we are about to return */ + result = sshc->actualcode; + + memset(sshc, 0, sizeof(struct ssh_conn)); + conn->bits.close = TRUE; + sshc->state = SSH_SESSION_FREE; /* current */ sshc->nextstate = SSH_NO_STATE; state(conn, SSH_STOP); - result = sshc->actualcode; break; case SSH_QUIT: @@ -2488,7 +2519,7 @@ static void ssh_block2waitfor(struct connectdata *conn, bool block) } #else /* no libssh2 directional support so we simply don't know */ -#define ssh_block2waitfor(x,y) +#define ssh_block2waitfor(x,y) Curl_nop_stmt #endif /* called repeatedly until done from multi.c */ @@ -2500,7 +2531,7 @@ static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done) implementation */ result = ssh_statemach_act(conn, &block); - *done = (bool)(sshc->state == SSH_STOP); + *done = (sshc->state == SSH_STOP) ? TRUE : FALSE; ssh_block2waitfor(conn, block); return result; @@ -2706,7 +2737,7 @@ CURLcode scp_perform(struct connectdata *conn, result = ssh_easy_statemach(conn, FALSE); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); @@ -2913,7 +2944,7 @@ CURLcode sftp_perform(struct connectdata *conn, result = ssh_easy_statemach(conn, FALSE); *dophase_done = TRUE; /* with the easy interface we are done here */ } - *connected = conn->bits.tcpconnect; + *connected = conn->bits.tcpconnect[FIRSTSOCKET]; if(*dophase_done) { DEBUGF(infof(conn->data, "DO phase is complete\n")); diff --git a/lib/sslgen.c b/lib/sslgen.c index 779d9e9c3..3b7340244 100644 --- a/lib/sslgen.c +++ b/lib/sslgen.c @@ -43,9 +43,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif @@ -65,6 +62,7 @@ #include "url.h" #include "curl_memory.h" #include "progress.h" +#include "share.h" /* The last #include file should be: */ #include "memdebug.h" @@ -72,10 +70,10 @@ static bool safe_strequal(char* str1, char* str2) { if(str1 && str2) /* both pointers point to something then compare them */ - return (bool)(0 != Curl_raw_equal(str1, str2)); + return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE; else /* if both pointers are NULL then treat them as equal */ - return (bool)(!str1 && !str2); + return (!str1 && !str2) ? TRUE : FALSE; } bool @@ -213,7 +211,7 @@ Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex, /* mark this is being ssl requested from here on. */ conn->ssl[sockindex].use = TRUE; res = curlssl_connect_nonblocking(conn, sockindex, done); - if(!res && *done == TRUE) + if(!res && *done) Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */ return res; #else @@ -239,6 +237,10 @@ int Curl_ssl_getsessionid(struct connectdata *conn, /* session ID re-use is disabled */ return TRUE; + /* Lock for reading if shared */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SHARED); + for(i=0; i< data->set.ssl.numsessions; i++) { check = &data->state.session[i]; if(!check->sessionid) @@ -257,13 +259,19 @@ int Curl_ssl_getsessionid(struct connectdata *conn, } } *ssl_sessionid = NULL; + + /* Unlock for reading */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + + return TRUE; } /* * Kill a single session ID entry in the cache. */ -static int kill_session(struct curl_ssl_session *session) +int Curl_ssl_kill_session(struct curl_ssl_session *session) { if(session->sessionid) { /* defensive check */ @@ -291,14 +299,23 @@ static int kill_session(struct curl_ssl_session *session) void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid) { int i; - for(i=0; i< conn->data->set.ssl.numsessions; i++) { - struct curl_ssl_session *check = &conn->data->state.session[i]; + struct SessionHandle *data=conn->data; + + if(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, + CURL_LOCK_ACCESS_SINGLE); + + for(i=0; i< data->set.ssl.numsessions; i++) { + struct curl_ssl_session *check = &data->state.session[i]; if(check->sessionid == ssl_sessionid) { - kill_session(check); + Curl_ssl_kill_session(check); break; } } + + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } /* @@ -328,6 +345,10 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, /* 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(data->share && data->share->sslsession == data->state.session) + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + /* find an empty slot for us, or find the oldest */ for(i=1; (i<data->set.ssl.numsessions) && data->state.session[i].sessionid; i++) { @@ -338,7 +359,7 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, } if(i == data->set.ssl.numsessions) /* cache is full, we must "kill" the oldest entry! */ - kill_session(store); + Curl_ssl_kill_session(store); else store = &data->state.session[i]; /* use this slot */ @@ -352,6 +373,11 @@ CURLcode Curl_ssl_addsessionid(struct connectdata *conn, store->name = clone_host; /* clone host name */ store->remote_port = conn->remote_port; /* port number */ + + /* Unlock */ + if(data->share && data->share->sslsession == data->state.session) + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); + if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) { store->sessionid = NULL; /* let caller free sessionid */ free(clone_host); @@ -366,14 +392,20 @@ void Curl_ssl_close_all(struct SessionHandle *data) { long i; /* kill the session ID cache */ - if(data->state.session) { + if(data->state.session && + !(data->share && data->share->sslsession == data->state.session)) { + + Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE); + for(i=0; i< data->set.ssl.numsessions; i++) /* the single-killer function handles empty table slots */ - kill_session(&data->state.session[i]); + Curl_ssl_kill_session(&data->state.session[i]); /* free the cache data */ free(data->state.session); data->state.session = NULL; + + Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION); } curlssl_close_all(data); @@ -472,9 +504,12 @@ void Curl_ssl_free_certinfo(struct SessionHandle *data) struct curl_certinfo *ci = &data->info.certs; if(ci->num_of_certs) { /* free all individual lists used */ - for(i=0; i<ci->num_of_certs; i++) + for(i=0; i<ci->num_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; } } diff --git a/lib/sslgen.h b/lib/sslgen.h index b0a0fab12..516817618 100644 --- a/lib/sslgen.h +++ b/lib/sslgen.h @@ -1,5 +1,5 @@ -#ifndef __SSLGEN_H -#define __SSLGEN_H +#ifndef HEADER_CURL_SSLGEN_H +#define HEADER_CURL_SSLGEN_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" bool Curl_ssl_config_matches(struct ssl_config_data* data, struct ssl_config_data* needle); @@ -63,6 +64,8 @@ int Curl_ssl_getsessionid(struct connectdata *conn, CURLcode Curl_ssl_addsessionid(struct connectdata *conn, void *ssl_sessionid, size_t idsize); +/* Kill a single session ID entry in the cache */ +int Curl_ssl_kill_session(struct curl_ssl_session *session); /* delete a session from the cache */ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); @@ -71,10 +74,10 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); #else /* When SSL support is not present, just define away these function calls */ #define Curl_ssl_init() 1 -#define Curl_ssl_cleanup() do { } while (0) +#define Curl_ssl_cleanup() Curl_nop_stmt #define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN -#define Curl_ssl_close_all(x) -#define Curl_ssl_close(x,y) +#define Curl_ssl_close_all(x) Curl_nop_stmt +#define Curl_ssl_close(x,y) Curl_nop_stmt #define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN #define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN @@ -85,8 +88,9 @@ void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid); #define Curl_ssl_version(x,y) 0 #define Curl_ssl_data_pending(x,y) 0 #define Curl_ssl_check_cxn(x) 0 -#define Curl_ssl_free_certinfo(x) +#define Curl_ssl_free_certinfo(x) Curl_nop_stmt #define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN +#define Curl_ssl_kill_session(x) 0 #endif -#endif /* USE_SSL */ +#endif /* HEADER_CURL_SSLGEN_H */ diff --git a/lib/ssluse.c b/lib/ssluse.c index 5bdc536a3..d65fd98b9 100644 --- a/lib/ssluse.c +++ b/lib/ssluse.c @@ -32,9 +32,6 @@ #include "setup.h" -#include <string.h> -#include <stdlib.h> -#include <ctype.h> #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -123,7 +120,7 @@ /* 0.9.6 didn't have X509_STORE_set_flags() */ #define HAVE_X509_STORE_SET_FLAGS 1 #else -#define X509_STORE_set_flags(x,y) +#define X509_STORE_set_flags(x,y) Curl_nop_stmt #endif /* @@ -169,14 +166,14 @@ static int passwd_callback(char *buf, int num, int verify #define seed_enough(x) rand_enough() static bool rand_enough(void) { - return (bool)(0 != RAND_status()); + return (0 != RAND_status()) ? TRUE : FALSE; } #else #define seed_enough(x) rand_enough(x) static bool rand_enough(int nread) { /* this is a very silly decision to make */ - return (bool)(nread > 500); + return (nread > 500) ? TRUE : FALSE; } #endif @@ -813,18 +810,16 @@ struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data) { struct curl_slist *list = NULL; #if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H) - struct curl_slist *beg = NULL; + struct curl_slist *beg; ENGINE *e; for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) { - list = curl_slist_append(list, ENGINE_get_id(e)); - if(list == NULL) { - curl_slist_free_all(beg); + beg = curl_slist_append(list, ENGINE_get_id(e)); + if(!beg) { + curl_slist_free_all(list); return NULL; } - else if(beg == NULL) { - beg = list; - } + list = beg; } #endif (void) data; @@ -1410,7 +1405,7 @@ static void ssl_tls_trace(int direction, int ssl_ver, int content_type, #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME # define use_sni(x) sni = (x) #else -# define use_sni(x) do { } while (0) +# define use_sni(x) Curl_nop_stmt #endif static CURLcode @@ -1492,6 +1487,10 @@ ossl_connect_step1(struct connectdata *conn, return CURLE_OUT_OF_MEMORY; } +#ifdef SSL_MODE_RELEASE_BUFFERS + SSL_CTX_set_mode(connssl->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 so we only @@ -1856,15 +1855,15 @@ static CURLcode push_certinfo_len(struct SessionHandle *data, equivalent of curl_slist_append but doesn't strdup() the given data as like in this place the extra malloc/free is totally pointless */ nl = curl_slist_append(ci->certinfo[certnum], output); + free(output); if(!nl) { curl_slist_free_all(ci->certinfo[certnum]); + ci->certinfo[certnum] = NULL; res = CURLE_OUT_OF_MEMORY; } else ci->certinfo[certnum] = nl; - free(output); - return res; } @@ -1918,7 +1917,7 @@ do { \ pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \ } \ } \ -} while(0) +} WHILE_FALSE static int X509V3_ext(struct SessionHandle *data, int certnum, @@ -2563,7 +2562,7 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, { if(conn->ssl[connindex].handle) /* SSL is in use */ - return (bool)(0 != SSL_pending(conn->ssl[connindex].handle)); + return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE; else return FALSE; } diff --git a/lib/ssluse.h b/lib/ssluse.h index 2ac0ad2ec..732ec7c72 100644 --- a/lib/ssluse.h +++ b/lib/ssluse.h @@ -1,5 +1,5 @@ -#ifndef __SSLUSE_H -#define __SSLUSE_H +#ifndef HEADER_CURL_SSLUSE_H +#define HEADER_CURL_SSLUSE_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -22,12 +22,15 @@ * ***************************************************************************/ +#include "setup.h" + #ifdef USE_SSLEAY /* * This header should only be needed to get included by sslgen.c and ssluse.c */ #include "urldata.h" + CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex); CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn, int sockindex, @@ -81,4 +84,4 @@ bool Curl_ossl_data_pending(const struct connectdata *conn, #define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y) #endif /* USE_SSLEAY */ -#endif /* __SSLUSE_H */ +#endif /* HEADER_CURL_SSLUSE_H */ diff --git a/lib/strdup.c b/lib/strdup.c index a3107cff7..02d480c26 100644 --- a/lib/strdup.c +++ b/lib/strdup.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "strdup.h" #ifndef HAVE_STRDUP diff --git a/lib/strequal.c b/lib/strequal.c index 15896b9fd..89ad8a6e8 100644 --- a/lib/strequal.c +++ b/lib/strequal.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <ctype.h> - #ifdef HAVE_STRINGS_H #include <strings.h> #endif diff --git a/lib/strerror.c b/lib/strerror.c index 0a883421e..fcb617cf2 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -34,9 +34,6 @@ #endif #include <curl/curl.h> -#include <stdlib.h> -#include <string.h> -#include <errno.h> #ifdef USE_LIBIDN #include <idna.h> @@ -387,6 +384,9 @@ curl_share_strerror(CURLSHcode error) case CURLSHE_NOMEM: return "Out of memory"; + case CURLSHE_NOT_BUILT_IN: + return "Feature not enabled in this library"; + case CURLSHE_LAST: break; } diff --git a/lib/strtok.c b/lib/strtok.c index 91c254156..94eac0e64 100644 --- a/lib/strtok.c +++ b/lib/strtok.c @@ -24,7 +24,6 @@ #ifndef HAVE_STRTOK_R #include <stddef.h> -#include <string.h> #include "strtok.h" diff --git a/lib/strtoofft.c b/lib/strtoofft.c index 55a6ffd0d..c61459de8 100644 --- a/lib/strtoofft.c +++ b/lib/strtoofft.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "strtoofft.h" /* @@ -32,15 +33,11 @@ */ #ifdef NEED_CURL_STRTOLL -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> /* 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 -#include <string.h> #define NO_RANGE_TEST diff --git a/lib/telnet.c b/lib/telnet.c index 80592d27e..59094b674 100644 --- a/lib/telnet.c +++ b/lib/telnet.c @@ -23,28 +23,19 @@ #include "setup.h" #ifndef CURL_DISABLE_TELNET -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#if defined(WIN32) -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -59,8 +50,6 @@ #include <sys/param.h> #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -99,7 +88,7 @@ #define CURL_SB_LEN(x) (x->subend - x->subpointer) #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define printoption(a,b,c,d) do { } while(0) +#define printoption(a,b,c,d) Curl_nop_stmt #endif #ifdef USE_WINSOCK @@ -193,6 +182,7 @@ const struct Curl_handler Curl_handler_telnet = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -774,18 +764,24 @@ static void printsub(struct SessionHandle *data, static CURLcode check_telnet_options(struct connectdata *conn) { struct curl_slist *head; + struct curl_slist *beg; char option_keyword[128]; char option_arg[256]; - char *buf; struct SessionHandle *data = conn->data; struct TELNET *tn = (struct TELNET *)conn->data->state.proto.telnet; + CURLcode result = CURLE_OK; /* Add the user name as an environment variable if it was given on the command line */ if(conn->bits.user_passwd) { snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user); - tn->telnet_vars = curl_slist_append(tn->telnet_vars, option_arg); - + beg = curl_slist_append(tn->telnet_vars, option_arg); + 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; } @@ -811,24 +807,33 @@ static CURLcode check_telnet_options(struct connectdata *conn) /* Environment variable */ if(Curl_raw_equal(option_keyword, "NEW_ENV")) { - buf = strdup(option_arg); - if(!buf) - return CURLE_OUT_OF_MEMORY; - tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf); + beg = curl_slist_append(tn->telnet_vars, option_arg); + if(!beg) { + result = CURLE_OUT_OF_MEMORY; + break; + } + tn->telnet_vars = beg; tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES; continue; } failf(data, "Unknown telnet option %s", head->data); - return CURLE_UNKNOWN_TELNET_OPTION; + result = CURLE_UNKNOWN_TELNET_OPTION; + break; } else { failf(data, "Syntax error in telnet option: %s", head->data); - return CURLE_TELNET_OPTION_SYNTAX; + result = CURLE_TELNET_OPTION_SYNTAX; + break; } } - return CURLE_OK; + if(result) { + curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; + } + + return result; } /* @@ -1120,6 +1125,7 @@ static CURLcode telnet_done(struct connectdata *conn, (void)premature; /* not used */ curl_slist_free_all(tn->telnet_vars); + tn->telnet_vars = NULL; free(conn->data->state.proto.telnet); conn->data->state.proto.telnet = NULL; @@ -1238,13 +1244,6 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) return CURLE_FAILED_INIT; } - /* 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; - /* Tell winsock what events we want to listen to */ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) == SOCKET_ERROR) { @@ -1253,9 +1252,17 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) 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) { + 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 */ @@ -1273,20 +1280,41 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) case WAIT_TIMEOUT: { for(;;) { - if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; + if(obj_count == 1) { + /* read from user-supplied method */ + code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in); + if(code == CURL_READFUNC_ABORT) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } + + if(code == CURL_READFUNC_PAUSE) + break; + + if(code == 0) /* no bytes */ + break; + + readfile_read = code; /* fall thru with number of bytes read */ } + else { + /* read from stdin */ + if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL, + &readfile_read, NULL)) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } - if(!readfile_read) - break; + if(!readfile_read) + break; - if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), - &readfile_read, NULL)) { - keepon = FALSE; - code = CURLE_READ_ERROR; - break; + if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer), + &readfile_read, NULL)) { + keepon = FALSE; + code = CURLE_READ_ERROR; + break; + } } code = send_telnet_data(conn, buf, readfile_read); @@ -1375,7 +1403,7 @@ static CURLcode telnet_do(struct connectdata *conn, bool *done) } /* We called WSACreateEvent, so call WSACloseEvent */ - if(close_event_func(event_handle) == FALSE) { + if(!close_event_func(event_handle)) { infof(data,"WSACloseEvent failed (%d)", SOCKERRNO); } diff --git a/lib/tftp.c b/lib/tftp.c index 46b3ecfcb..9b44a9b3d 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -23,27 +23,19 @@ #include "setup.h" #ifndef CURL_DISABLE_TFTP -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> - -#if defined(WIN32) -#include <time.h> -#include <io.h> -#else + #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif +#ifdef HAVE_NETINET_IN_H #include <netinet/in.h> -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> #endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif +#ifdef HAVE_NETDB_H #include <netdb.h> +#endif #ifdef HAVE_ARPA_INET_H #include <arpa/inet.h> #endif @@ -58,8 +50,6 @@ #include <sys/param.h> #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "transfer.h" @@ -194,6 +184,7 @@ const struct Curl_handler Curl_handler_tftp = { tftp_doing, /* doing */ tftp_getsock, /* proto_getsock */ tftp_getsock, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ tftp_disconnect, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -216,7 +207,7 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) { time_t maxtime, timeout; long timeout_ms; - bool start = (bool)(state->state == TFTP_STATE_START); + bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE; time(&state->start_time); @@ -258,11 +249,11 @@ static CURLcode tftp_set_timeouts(tftp_state_data_t *state) state->max_time = state->start_time+maxtime; - /* Set per-block timeout to 10% of total */ - timeout = maxtime/10 ; + /* Set per-block timeout to total */ + timeout = maxtime; - /* Average reposting an ACK after 15 seconds */ - state->retry_max = (int)timeout/15; + /* Average reposting an ACK after 5 seconds */ + state->retry_max = (int)timeout/5; } /* But bound the total number */ if(state->retry_max<3) @@ -601,15 +592,10 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) /* Is this the block we expect? */ rblock = getrpacketblock(&state->rpacket); if(NEXT_BLOCKNUM(state->block) != rblock) { - /* No, log it, up the retry count and fail if over the limit */ + /* No, log it */ infof(data, - "Received unexpected DATA packet block %d\n", rblock); - state->retries++; - if(state->retries > state->retry_max) { - failf(data, "tftp_rx: giving up waiting for block %d", - NEXT_BLOCKNUM(state->block)); - return CURLE_TFTP_ILLEGAL; - } + "Received unexpected DATA packet block %d, expecting block %d\n", + rblock, NEXT_BLOCKNUM(state->block)); break; } /* This is the expected block. Reset counters and ACK it. */ @@ -627,7 +613,7 @@ static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) } /* Check if completed (That is, a less than full packet is received) */ - if(state->rbytes < (ssize_t)state->blksize+4){ + if(state->rbytes < (ssize_t)state->blksize+4) { state->state = TFTP_STATE_FIN; } else { @@ -1344,7 +1330,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) result = tftp_state_machine(state, event); if(result != CURLE_OK) return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); @@ -1366,7 +1352,7 @@ static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done) result = tftp_state_machine(state, state->event); if(result != CURLE_OK) return(result); - *done = (bool)(state->state == TFTP_STATE_FIN); + *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE; if(*done) /* Tell curl we're done */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); diff --git a/lib/transfer.c b/lib/transfer.c index 94cd6d6f9..413a28082 100644 --- a/lib/transfer.c +++ b/lib/transfer.c @@ -22,31 +22,16 @@ #include "setup.h" -/* -- WIN32 approved -- */ -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - #include "strtoofft.h" #include "strequal.h" #include "rawstr.h" -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -78,8 +63,6 @@ #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #include "urldata.h" #include <curl/curl.h> #include "netrc.h" @@ -95,7 +78,7 @@ #include "getinfo.h" #include "sslgen.h" #include "http_digest.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" #include "http_negotiate.h" #include "share.h" #include "curl_memory.h" @@ -186,11 +169,12 @@ CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp) const char *endofline_native; const char *endofline_network; int hexlen; + + if( #ifdef CURL_DO_LINEEND_CONV - if((data->set.crlf) || (data->set.prefer_ascii)) { -#else - if(data->set.crlf) { -#endif /* CURL_DO_LINEEND_CONV */ + (data->set.prefer_ascii) || +#endif + (data->set.crlf)) { /* \n will become \r\n later on */ endofline_native = "\n"; endofline_network = "\x0a"; @@ -302,7 +286,7 @@ CURLcode Curl_readrewind(struct connectdata *conn) 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 - ourself with fseek() */ + ourselves with fseek() */ if(data->set.fread_func == (curl_read_callback)fread) { if(-1 != fseek(data->set.in, 0, SEEK_SET)) /* successful rewind */ @@ -446,7 +430,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, *didwhat |= KEEP_RECV; /* indicates data of zero size, i.e. empty file */ - is_empty_data = (bool)((nread == 0) && (k->bodywrites == 0)); + is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE; /* NUL terminate, allowing string ops to be used */ if(0 < nread || is_empty_data) { @@ -522,7 +506,6 @@ static CURLcode readwrite_data(struct SessionHandle *data, is non-headers. */ if(k->str && !k->header && (nread > 0 || is_empty_data)) { - #ifndef CURL_DISABLE_HTTP if(0 == k->bodywrites && !is_empty_data) { /* These checks are only made the first time we are about to @@ -570,9 +553,10 @@ static CURLcode readwrite_data(struct SessionHandle *data, } } /* we have a time condition */ - } /* this is HTTP */ + } /* this is HTTP or RTSP */ } /* this is the first time we write a body part */ #endif /* CURL_DISABLE_HTTP */ + k->bodywrites++; /* pass data to the debug function before it gets "dechunked" */ @@ -606,7 +590,7 @@ static CURLcode readwrite_data(struct SessionHandle *data, failf(data, "Failed writing data"); return CURLE_WRITE_ERROR; } - failf(data, "Received problem %d in the chunky parser", (int)res); + failf(data, "Problem (%d) in the Chunked-Encoded data", (int)res); return CURLE_RECV_ERROR; } else if(CHUNKE_STOP == res) { @@ -816,6 +800,9 @@ static CURLcode readwrite_upload(struct SessionHandle *data, /* * We loop here to do the READ and SEND loop until we run out of * data to send or until we get EWOULDBLOCK back + * + * FIXME: above comment is misleading. Currently no looping is + * actually done in do-while loop below. */ do { @@ -892,13 +879,12 @@ static CURLcode readwrite_upload(struct SessionHandle *data, #endif /* CURL_DISABLE_SMTP */ /* convert LF to CRLF if so asked */ - if((!sending_http_headers) && + if((!sending_http_headers) && ( #ifdef CURL_DO_LINEEND_CONV - /* always convert if we're FTPing in ASCII mode */ - ((data->set.crlf) || (data->set.prefer_ascii))) { -#else - (data->set.crlf)) { + /* always convert if we're FTPing in ASCII mode */ + (data->set.prefer_ascii) || #endif + (data->set.crlf))) { if(data->state.scratch == NULL) data->state.scratch = malloc(2*BUFSIZE); if(data->state.scratch == NULL) { @@ -988,7 +974,7 @@ static CURLcode readwrite_upload(struct SessionHandle *data, Curl_pgrsSetUploadCounter(data, k->writebytecount); - } while(0); /* just to break out from! */ + } WHILE_FALSE; /* just to break out from! */ return CURLE_OK; } @@ -1043,6 +1029,12 @@ CURLcode Curl_readwrite(struct connectdata *conn, if(result || *done) return result; } + else if(k->keepon & KEEP_RECV) { + DEBUGF(infof(data, "additional stuff not fine %s:%d: %d %d\n", + __FILE__, __LINE__, + select_res & CURL_CSELECT_IN, + conn->bits.stream_was_rewound)); + } /* If we still have writing to do, we check if we have a writable socket. */ if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) { @@ -1136,7 +1128,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, (conn->chunk.state != CHUNK_STOP)) { /* * In chunked mode, return an error if the connection is closed prior to - * the empty (terminiating) chunk is read. + * the empty (terminating) chunk is read. * * The condition above used to check for * conn->proto.http->chunk.datasize != 0 which is true after reading @@ -1151,8 +1143,8 @@ CURLcode Curl_readwrite(struct connectdata *conn, } /* Now update the "done" boolean we return */ - *done = (bool)(0 == (k->keepon&(KEEP_RECV|KEEP_SEND| - KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))); + *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND| + KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE; return CURLE_OK; } @@ -1213,11 +1205,11 @@ int Curl_single_getsock(const struct connectdata *conn, /* * Determine optimum sleep time based on configured rate, current rate, * and packet size. - * Returns value in mili-seconds. + * Returns value in milliseconds. * * The basic idea is to adjust the desired rate up/down in this method * based on whether we are running too slow or too fast. Then, calculate - * how many miliseconds to wait for the next packet to achieve this new + * how many milliseconds to wait for the next packet to achieve this new * rate. */ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, @@ -1243,7 +1235,7 @@ long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps, rate_bps += rate_bps >> 6; } - /* Determine number of miliseconds to wait until we do + /* Determine number of milliseconds to wait until we do * the next packet at the adjusted rate. We should wait * longer when using larger packets, for instance. */ @@ -1448,8 +1440,10 @@ static CURLcode loadhostpairs(struct SessionHandle *data) if(data->share) Curl_share_unlock(data, CURL_LOCK_DATA_DNS); - if(!dns) + if(!dns) { + Curl_freeaddrinfo(addr); return CURLE_OUT_OF_MEMORY; + } } } data->change.resolve = NULL; /* dealt with now */ @@ -1613,7 +1607,7 @@ static bool is_absolute_url(const char *url) char prot[16]; /* URL protocol string storage */ char letter; /* used for a silly sscanf */ - return (bool)(2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)); + return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE; } /* @@ -1705,26 +1699,37 @@ static char *concat_url(const char *base, const char *relurl) } } else { - /* We got a new absolute path for this server, cut off from the - first slash */ - pathsep = strchr(protsep, '/'); - if(pathsep) { - /* When people use badly formatted URLs, such as - "http://www.url.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; + /* We got a new absolute path for this server */ + + if((relurl[0] == '/') && (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 */ } else { - /* There was no slash. Now, since we might be operating on a badly - formatted URL, such as "http://www.url.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) + /* 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.url.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.url.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; + } } } @@ -1737,8 +1742,8 @@ static char *concat_url(const char *base, const char *relurl) urllen = strlen(url_clone); - newest = malloc( urllen + 1 + /* possible slash */ - newlen + 1 /* zero byte */); + newest = malloc(urllen + 1 + /* possible slash */ + newlen + 1 /* zero byte */); if(!newest) { free(url_clone); /* don't leak this */ @@ -1801,15 +1806,14 @@ CURLcode Curl_follow(struct SessionHandle *data, when we get the next URL. We pick the ->url field, which may or may not be 100% correct */ - if(data->change.referer_alloc) - /* If we already have an allocated referer, free this first */ - free(data->change.referer); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } data->change.referer = strdup(data->change.url); - if(!data->change.referer) { - data->change.referer_alloc = FALSE; + if(!data->change.referer) return CURLE_OUT_OF_MEMORY; - } data->change.referer_alloc = TRUE; /* yes, free this later */ } } @@ -1856,12 +1860,13 @@ CURLcode Curl_follow(struct SessionHandle *data, if(disallowport) data->state.allow_port = FALSE; - if(data->change.url_alloc) - free(data->change.url); - else - data->change.url_alloc = TRUE; /* the URL is allocated */ + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = newurl; + data->change.url_alloc = TRUE; newurl = NULL; /* don't free! */ infof(data, "Issue another request to this URL: '%s'\n", data->change.url); @@ -1889,19 +1894,18 @@ CURLcode Curl_follow(struct SessionHandle *data, case 301: /* Moved Permanently */ /* (quote from RFC2616, section 10.3.2): * - * Note: When automatically redirecting a POST request after receiving a - * 301 status code, some existing HTTP/1.0 user agents will erroneously - * change it into a GET request. + * When automatically redirecting a POST request after receiving a 301 + * status code, some existing HTTP/1.0 user agents will erroneously change + * it into a GET request. * * ---- * - * Warning: Because most of importants user agents do this obvious RFC2616 - * violation, many webservers expect this misbehavior. 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. + * As most of the important user agents do this obvious RFC2616 violation, + * 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 behaviour can be overridden with CURLOPT_POSTREDIR. + * This behavior can be overridden with CURLOPT_POSTREDIR. */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM) @@ -1929,7 +1933,7 @@ CURLcode Curl_follow(struct SessionHandle *data, 302 status code may be used instead, since most user agents react to a 302 response as described here for 303. - This behaviour can be overriden with CURLOPT_POSTREDIR + This behavior can be overridden with CURLOPT_POSTREDIR */ if((data->set.httpreq == HTTPREQ_POST || data->set.httpreq == HTTPREQ_POST_FORM) @@ -2092,7 +2096,7 @@ CURLcode Curl_retry_request(struct connectdata *conn, transferred! */ if(data->state.proto.http->writebytecount) - Curl_readrewind(conn); + return Curl_readrewind(conn); } return CURLE_OK; } @@ -20,30 +20,14 @@ * ***************************************************************************/ -/* -- WIN32 approved -- */ - #include "setup.h" -#include <stdio.h> -#include <string.h> -#include <stdarg.h> -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> - -#ifdef WIN32 -#include <time.h> -#include <io.h> -#else #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif #ifdef HAVE_NETINET_IN_H #include <netinet/in.h> #endif -#ifdef HAVE_SYS_TIME_H -#include <sys/time.h> -#endif #ifdef HAVE_UNISTD_H #include <unistd.h> #endif @@ -73,8 +57,6 @@ #error "We can't compile without socket() support!" #endif -#endif /* WIN32 */ - #ifdef HAVE_LIMITS_H #include <limits.h> #endif @@ -137,7 +119,8 @@ int curl_win32_idn_to_ascii(const char *in, char **out); #include "url.h" #include "connect.h" #include "inet_ntop.h" -#include "http_ntlm.h" +#include "curl_ntlm.h" +#include "curl_ntlm_wb.h" #include "socks.h" #include "curl_rtmp.h" #include "gopher.h" @@ -153,6 +136,7 @@ int curl_win32_idn_to_ascii(const char *in, char **out); static long ConnectionKillOne(struct SessionHandle *data); static void conn_free(struct connectdata *conn); static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke); +static CURLcode do_init(struct connectdata *conn); /* * Protocol table. @@ -262,6 +246,7 @@ static const struct Curl_handler Curl_handler_dummy = { ZERO_NULL, /* doing */ ZERO_NULL, /* proto_getsock */ ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* domore_getsock */ ZERO_NULL, /* perform_getsock */ ZERO_NULL, /* disconnect */ ZERO_NULL, /* readwrite */ @@ -270,12 +255,6 @@ static const struct Curl_handler Curl_handler_dummy = { PROTOPT_NONE /* flags */ }; -void Curl_safefree(void *ptr) -{ - if(ptr) - free(ptr); -} - static void close_connections(struct SessionHandle *data) { /* Loop through all open connections and kill them one by one */ @@ -298,10 +277,7 @@ static CURLcode setstropt(char **charp, 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. */ - if(*charp) { - free(*charp); - *charp = (char *) NULL; - } + Curl_safefree(*charp); if(s) { s = strdup(s); @@ -480,6 +456,7 @@ CURLcode Curl_close(struct SessionHandle *data) /* free the connection cache if allocated privately */ Curl_rm_connc(data->state.connc); + data->state.connc = NULL; } } @@ -501,6 +478,8 @@ CURLcode Curl_close(struct SessionHandle *data) /* Free the pathbuffer */ Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + Curl_safefree(data->state.proto.generic); /* Close down all open SSL info and sessions */ @@ -509,11 +488,17 @@ CURLcode Curl_close(struct SessionHandle *data) Curl_safefree(data->state.scratch); Curl_ssl_free_certinfo(data); - if(data->change.referer_alloc) - free(data->change.referer); + if(data->change.referer_alloc) { + Curl_safefree(data->change.referer); + data->change.referer_alloc = FALSE; + } + data->change.referer = NULL; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = NULL; Curl_safefree(data->state.headerbuff); @@ -640,13 +625,19 @@ CURLcode Curl_ch_connc(struct SessionHandle *data, curl_multi_cleanup(). */ void Curl_rm_connc(struct conncache *c) { + if(!c) + return; + if(c->connects) { long i; - for(i = 0; i < c->num; ++i) + for(i = 0; i < c->num; ++i) { conn_free(c->connects[i]); - + c->connects[i] = NULL; + } free(c->connects); + c->connects = NULL; } + c->num = 0; free(c); } @@ -844,7 +835,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, { /* remember we want this enabled */ long use_cache = va_arg(param, long); - data->set.global_dns_cache = (bool)(0 != use_cache); + data->set.global_dns_cache = (0 != use_cache)?TRUE:FALSE; } break; case CURLOPT_SSL_CIPHER_LIST: @@ -880,33 +871,33 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * 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 = (bool)(0 != va_arg(param, long)); + data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE; 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 = (bool)(0 != va_arg(param, long)); + data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE; 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 = (bool)(0 != va_arg(param, long)); + data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HEADER: /* * Set to include the header in the general data output stream. */ - data->set.include_header = (bool)(0 != va_arg(param, long)); + data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NOPROGRESS: /* * Shut off the internal supported progress meter */ - data->set.hide_progress = (bool)(0 != va_arg(param, long)); + data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.hide_progress) data->progress.flags |= PGRS_HIDE; else @@ -916,14 +907,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Do not include the body part in the output data stream. */ - data->set.opt_no_body = (bool)(0 != va_arg(param, long)); + data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FAILONERROR: /* * Don't output the >=300 error code HTML-page, but instead only * return error. */ - data->set.http_fail_on_error = (bool)(0 != va_arg(param, long)); + data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UPLOAD: case CURLOPT_PUT: @@ -931,7 +922,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We want to sent data to the remote host. If this is HTTP, that equals * using the PUT request. */ - data->set.upload = (bool)(0 != va_arg(param, long)); + data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE; if(data->set.upload) { /* If this is HTTP, PUT is what's needed to "upload" */ data->set.httpreq = HTTPREQ_PUT; @@ -947,7 +938,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * 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 = (bool)(0 != va_arg(param, long)); + data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_CREATE_MISSING_DIRS: /* @@ -988,13 +979,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * An option that changes the command to one that asks for a list * only, no file info details. */ - data->set.ftp_list_only = (bool)(0 != va_arg(param, long)); + data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_APPEND: /* * We want to upload and append to an existing file. */ - data->set.ftp_append = (bool)(0 != va_arg(param, long)); + data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_FILEMETHOD: /* @@ -1022,7 +1013,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * * Transfer using ASCII (instead of BINARY). */ - data->set.prefer_ascii = (bool)(0 != va_arg(param, long)); + data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_TIMECONDITION: /* @@ -1051,7 +1042,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Switch on automatic referer that gets set if curl follows locations. */ - data->set.http_auto_referer = (bool)(0 != va_arg(param, long)); + data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_ACCEPT_ENCODING: @@ -1071,14 +1062,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_TRANSFER_ENCODING: - data->set.http_transfer_encoding = (bool)(0 != va_arg(param, long)); + data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FOLLOWLOCATION: /* * Follow Location: header hints on a HTTP-server. */ - data->set.http_follow_location = (bool)(0 != va_arg(param, long)); + data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_UNRESTRICTED_AUTH: @@ -1087,7 +1078,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * hostname changed. */ data->set.http_disable_hostname_check_before_authentication = - (bool)(0 != va_arg(param, long)); + (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_MAXREDIRS: @@ -1109,8 +1100,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * other - POST is kept as POST after 301 and 302 */ long postRedir = va_arg(param, long); - data->set.post301 = (bool)((postRedir & CURL_REDIR_POST_301)?TRUE:FALSE); - data->set.post302 = (bool)((postRedir & CURL_REDIR_POST_302)?TRUE:FALSE); + data->set.post301 = (postRedir & CURL_REDIR_POST_301)?TRUE:FALSE; + data->set.post302 = (postRedir & CURL_REDIR_POST_302)?TRUE:FALSE; } break; @@ -1231,7 +1222,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * String to set in the HTTP Referer: field. */ if(data->change.referer_alloc) { - free(data->change.referer); + Curl_safefree(data->change.referer); data->change.referer_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_REFERER], @@ -1280,10 +1271,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* append the cookie file name to the list of file names, and deal with them later */ cl = curl_slist_append(data->change.cookielist, argptr); - - if(!cl) + if(!cl) { + curl_slist_free_all(data->change.cookielist); + data->change.cookielist = NULL; return CURLE_OUT_OF_MEMORY; - + } data->change.cookielist = cl; /* store the list for later use */ } break; @@ -1319,7 +1311,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * We run mostly with the original cookie spec, as hardly anyone implements * anything else. */ - data->set.cookiesession = (bool)(0 != va_arg(param, long)); + data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_COOKIELIST: @@ -1394,8 +1386,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* 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 = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1404,7 +1395,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + 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_HTTP_NEGOTIATE auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or @@ -1437,7 +1431,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Tunnel operations through the proxy instead of normal proxy use */ - data->set.tunnel_thru_httpproxy = (bool)(0 != va_arg(param, long)); + data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_PROXYPORT: @@ -1456,8 +1450,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* 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 = (bool)((auth & CURLAUTH_DIGEST_IE)? - TRUE:FALSE); + data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE; if(auth & CURLAUTH_DIGEST_IE) { auth |= CURLAUTH_DIGEST; /* set standard digest bit */ @@ -1465,7 +1458,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, } /* switch off bits we can't support */ #ifndef USE_NTLM - auth &= ~CURLAUTH_NTLM; /* no NTLM without SSL */ + 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_HTTP_NEGOTIATE auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or @@ -1531,7 +1527,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * set flag for nec socks5 support */ - data->set.socks5_gssapi_nec = (bool)(0 != va_arg(param, long)); + data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE; break; #endif @@ -1560,19 +1556,20 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_FTPPORT], va_arg(param, char *)); - data->set.ftp_use_port = (bool)(NULL != data->set.str[STRING_FTPPORT]); + data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ? + TRUE:FALSE; break; case CURLOPT_FTP_USE_EPRT: - data->set.ftp_use_eprt = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_EPSV: - data->set.ftp_use_epsv = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_USE_PRET: - data->set.ftp_use_pret = (bool)(0 != va_arg(param, long)); + data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_SSL_CCC: @@ -1584,7 +1581,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * 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 = (bool)(0 != va_arg(param, long)); + data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_INFILE: @@ -1642,8 +1639,8 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ if(data->change.url_alloc) { /* the already set URL is allocated, free it first! */ - free(data->change.url); - data->change.url_alloc=FALSE; + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; } result = setstropt(&data->set.str[STRING_SET_URL], va_arg(param, char *)); @@ -1954,7 +1951,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * Kludgy option to enable CRLF conversions. Subject for removal. */ - data->set.crlf = (bool)(0 != va_arg(param, long)); + data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_INTERFACE: @@ -1983,7 +1980,13 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, */ result = setstropt(&data->set.str[STRING_KRB_LEVEL], va_arg(param, char *)); - data->set.krb = (bool)(NULL != data->set.str[STRING_KRB_LEVEL]); + data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE; + break; + case CURLOPT_GSSAPI_DELEGATION: + /* + * GSSAPI credential delegation + */ + data->set.gssapi_delegation = va_arg(param, long); break; case CURLOPT_SSL_VERIFYPEER: /* @@ -2015,7 +2018,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->set.ssl.fsslctxp = va_arg(param, void *); break; case CURLOPT_CERTINFO: - data->set.ssl.certinfo = (bool)(0 != va_arg(param, long)); + data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE; break; #endif case CURLOPT_CAINFO: @@ -2075,7 +2078,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * The application asks not to set any signal() or alarm() handlers, * even when using a timeout. */ - data->set.no_signal = (bool)(0 != va_arg(param, long)); + data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_SHARE: @@ -2092,8 +2095,15 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->dns.hostcachetype = HCACHE_NONE; } +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) if(data->share->cookies == data->cookies) data->cookies = NULL; +#endif + + if(data->share->sslsession == data->state.session) { + data->state.session = NULL; + data->set.ssl.numsessions = 0; + } data->share->dirty--; @@ -2126,6 +2136,10 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, data->cookies = data->share->cookies; } #endif /* CURL_DISABLE_HTTP */ + if(data->share->sslsession) { + data->set.ssl.numsessions = data->share->nsslsession; + data->state.session = data->share->sslsession; + } Curl_share_unlock(data, CURL_LOCK_DATA_SHARE); } @@ -2179,7 +2193,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, * Enable or disable TCP_NODELAY, which will disable/enable the Nagle * algorithm */ - data->set.tcp_nodelay = (bool)(0 != va_arg(param, long)); + data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ACCOUNT: @@ -2188,14 +2202,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_IGNORE_CONTENT_LENGTH: - data->set.ignorecl = (bool)(0 != va_arg(param, long)); + data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CONNECT_ONLY: /* * No data transfer, set up connection and let application use the socket */ - data->set.connect_only = (bool)(0 != va_arg(param, long)); + data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_FTP_ALTERNATIVE_TO_USER: @@ -2248,7 +2262,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_SSL_SESSIONID_CACHE: - data->set.ssl.sessionid = (bool)(0 != va_arg(param, long)); + data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE; break; #ifdef USE_LIBSSH2 @@ -2309,14 +2323,14 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, /* * disable libcurl transfer encoding is used */ - data->set.http_te_skip = (bool)(0 == va_arg(param, long)); + data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_HTTP_CONTENT_DECODING: /* * raw data passed to the application when content encoding is used */ - data->set.http_ce_skip = (bool)(0 == va_arg(param, long)); + data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_NEW_FILE_PERMS: @@ -2478,7 +2492,7 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, break; case CURLOPT_WILDCARDMATCH: - data->set.wildcardmatch = (bool)(0 != va_arg(param, long)); + data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE; break; case CURLOPT_CHUNK_BGN_FUNCTION: data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback); @@ -2543,6 +2557,10 @@ static void conn_free(struct connectdata *conn) if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET]) Curl_closesocket(conn, conn->sock[FIRSTSOCKET]); +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + Curl_ntlm_wb_cleanup(conn); +#endif + Curl_safefree(conn->user); Curl_safefree(conn->passwd); Curl_safefree(conn->proxyuser); @@ -2567,6 +2585,11 @@ static void conn_free(struct connectdata *conn) Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->localdev); Curl_free_ssl_config(&conn->ssl_config); @@ -2621,7 +2644,7 @@ CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection) if(has_host_ntlm || has_proxy_ntlm) { data->state.authproblem = FALSE; - Curl_ntlm_cleanup(conn); + Curl_http_ntlm_cleanup(conn); } } @@ -2773,11 +2796,11 @@ static struct SessionHandle* gethandleathead(struct curl_llist *pipeline) void Curl_getoff_all_pipelines(struct SessionHandle *data, struct connectdata *conn) { - bool recv_head = (bool)(conn->readchannel_inuse && - (gethandleathead(conn->recv_pipe) == data)); + bool recv_head = (conn->readchannel_inuse && + (gethandleathead(conn->recv_pipe) == data)) ? TRUE : FALSE; - bool send_head = (bool)(conn->writechannel_inuse && - (gethandleathead(conn->send_pipe) == data)); + bool send_head = (conn->writechannel_inuse && + (gethandleathead(conn->send_pipe) == data)) ? TRUE : FALSE; if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head) conn->readchannel_inuse = FALSE; @@ -3002,7 +3025,8 @@ ConnectionExists(struct SessionHandle *data, } if((needle->handler->protocol & CURLPROTO_FTP) || ((needle->handler->protocol & CURLPROTO_HTTP) && - (data->state.authhost.want==CURLAUTH_NTLM))) { + ((data->state.authhost.want==CURLAUTH_NTLM) || + (data->state.authhost.want==CURLAUTH_NTLM_WB)))) { /* This is FTP or HTTP+NTLM, verify that we're using the same name and password as well */ if(!strequal(needle->user, check->user) || @@ -3203,8 +3227,13 @@ static CURLcode ConnectPlease(struct SessionHandle *data, /* All is cool, we store the current information */ conn->ip_addr = addr; - if(*connected) + if(*connected) { result = Curl_connected_proxy(conn); + if(!result) { + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; + Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ + } + } } if(result) @@ -3297,7 +3326,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, *protocol_done = FALSE; - if(conn->bits.tcpconnect && conn->bits.protoconnstart) { + if(conn->bits.tcpconnect[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. @@ -3310,7 +3339,7 @@ CURLcode Curl_protocol_connect(struct connectdata *conn, return CURLE_OK; } - if(!conn->bits.tcpconnect) { + if(!conn->bits.tcpconnect[FIRSTSOCKET]) { Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */ Curl_verboseconnect(conn); @@ -3504,18 +3533,20 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) #else /* CURL_DISABLE_PROXY */ - conn->bits.proxy = (bool)(data->set.str[STRING_PROXY] && - *data->set.str[STRING_PROXY]); - conn->bits.httpproxy = (bool)(conn->bits.proxy && - (conn->proxytype == CURLPROXY_HTTP || - conn->proxytype == CURLPROXY_HTTP_1_0)); + /* 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->proxytype == CURLPROXY_HTTP || + conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE; conn->bits.proxy_user_passwd = - (bool)(NULL != data->set.str[STRING_PROXYUSERNAME]); + (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE; conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy; #endif /* CURL_DISABLE_PROXY */ - conn->bits.user_passwd = (bool)(NULL != data->set.str[STRING_USERNAME]); + conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE; conn->bits.ftp_use_epsv = data->set.ftp_use_epsv; conn->bits.ftp_use_eprt = data->set.ftp_use_eprt; @@ -3524,6 +3555,13 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) conn->ip_version = data->set.ipver; +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD; + conn->ntlm_auth_hlpr_pid = 0; + conn->challenge_header = NULL; + conn->response_header = NULL; +#endif + if(data->multi && Curl_multi_canPipeline(data->multi) && !conn->master_buffer) { /* Allocate master_buffer to be used for pipelining */ @@ -3566,6 +3604,12 @@ static struct connectdata *allocate_conn(struct SessionHandle *data) Curl_llist_destroy(conn->recv_pipe, NULL); Curl_llist_destroy(conn->pend_pipe, NULL); Curl_llist_destroy(conn->done_pipe, NULL); + + conn->send_pipe = NULL; + conn->recv_pipe = NULL; + conn->pend_pipe = NULL; + conn->done_pipe = NULL; + Curl_safefree(conn->master_buffer); Curl_safefree(conn->localdev); Curl_safefree(conn); @@ -3852,7 +3896,7 @@ static CURLcode setup_range(struct SessionHandle *data) else s->range = strdup(data->set.str[STRING_SET_RANGE]); - s->rangestringalloc = (bool)(s->range?TRUE:FALSE); + s->rangestringalloc = (s->range)?TRUE:FALSE; if(!s->range) return CURLE_OUT_OF_MEMORY; @@ -4392,8 +4436,10 @@ static CURLcode parse_remote_port(struct SessionHandle *data, if(!url) return CURLE_OUT_OF_MEMORY; - if(data->change.url_alloc) - free(data->change.url); + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } data->change.url = url; data->change.url_alloc = TRUE; @@ -4617,11 +4663,12 @@ static void reuse_conn(struct connectdata *old_conn, /* host can change, when doing keepalive with a proxy ! */ if(conn->bits.proxy) { - free(conn->host.rawalloc); + Curl_safefree(conn->host.rawalloc); conn->host=old_conn->host; } else - free(old_conn->host.rawalloc); /* free the newly allocated name buffer */ + /* free the newly allocated name buffer */ + Curl_safefree(old_conn->host.rawalloc); /* persist connection info in session handle */ Curl_persistconninfo(conn); @@ -4633,10 +4680,17 @@ static void reuse_conn(struct connectdata *old_conn, Curl_safefree(old_conn->passwd); Curl_safefree(old_conn->proxyuser); Curl_safefree(old_conn->proxypasswd); + Curl_llist_destroy(old_conn->send_pipe, NULL); Curl_llist_destroy(old_conn->recv_pipe, NULL); Curl_llist_destroy(old_conn->pend_pipe, NULL); Curl_llist_destroy(old_conn->done_pipe, NULL); + + old_conn->send_pipe = NULL; + old_conn->recv_pipe = NULL; + old_conn->pend_pipe = NULL; + old_conn->done_pipe = NULL; + Curl_safefree(old_conn->master_buffer); } @@ -4713,14 +4767,19 @@ static CURLcode create_conn(struct SessionHandle *data, */ Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; + data->state.pathbuffer = malloc(urllen+2); if(NULL == data->state.pathbuffer) return CURLE_OUT_OF_MEMORY; /* really bad error */ data->state.path = data->state.pathbuffer; conn->host.rawalloc = malloc(urllen+2); - if(NULL == conn->host.rawalloc) + if(NULL == conn->host.rawalloc) { + Curl_safefree(data->state.pathbuffer); + data->state.path = NULL; return CURLE_OUT_OF_MEMORY; + } conn->host.name = conn->host.rawalloc; conn->host.name[0] = 0; @@ -4745,6 +4804,11 @@ static CURLcode create_conn(struct SessionHandle *data, return CURLE_OUT_OF_MEMORY; } + if(data->change.url_alloc) { + Curl_safefree(data->change.url); + data->change.url_alloc = FALSE; + } + data->change.url = reurl; data->change.url_alloc = TRUE; /* free this later */ } @@ -4821,6 +4885,8 @@ static CURLcode create_conn(struct SessionHandle *data, conn->bits.httpproxy = TRUE; #endif } + else + conn->bits.httpproxy = FALSE; /* not a HTTP proxy */ conn->bits.proxy = TRUE; } else { @@ -4862,7 +4928,7 @@ static CURLcode create_conn(struct SessionHandle *data, /* Setup a "faked" transfer that'll do nothing */ if(CURLE_OK == result) { conn->data = data; - conn->bits.tcpconnect = TRUE; /* we are "connected */ + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */ ConnectionStore(data, conn); @@ -4970,6 +5036,9 @@ static CURLcode create_conn(struct SessionHandle *data, ConnectionStore(data, conn); } + /* Setup and init stuff before DO starts, in preparing for the transfer. */ + do_init(conn); + /* * Setup whatever necessary for a resumed transfer */ @@ -5007,7 +5076,7 @@ static CURLcode create_conn(struct SessionHandle *data, CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done) { - CURLcode result=CURLE_OK; + CURLcode result = CURLE_OK; struct SessionHandle *data = conn->data; Curl_pgrsTime(data, TIMER_NAMELOOKUP); @@ -5053,13 +5122,19 @@ CURLcode Curl_setup_conn(struct connectdata *conn, result = ConnectPlease(data, conn, &connected); + if(result && !conn->ip_addr) { + /* transport connection failure not related with authentication */ + conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; + return result; + } + if(connected) { result = Curl_protocol_connect(conn, protocol_done); if(CURLE_OK == result) - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; } else - conn->bits.tcpconnect = FALSE; + conn->bits.tcpconnect[FIRSTSOCKET] = FALSE; /* if the connection was closed by the server while exchanging authentication informations, retry with the new set @@ -5078,7 +5153,7 @@ CURLcode Curl_setup_conn(struct connectdata *conn, else { Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */ - conn->bits.tcpconnect = TRUE; + conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; *protocol_done = TRUE; Curl_verboseconnect(conn); Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]); @@ -5316,9 +5391,6 @@ CURLcode Curl_do(struct connectdata **connp, bool *done) struct connectdata *conn = *connp; struct SessionHandle *data = conn->data; - /* setup and init stuff before DO starts, in preparing for the transfer */ - do_init(conn); - if(conn->handler->do_it) { /* generic protocol-specific function pointer set in curl_connect() */ result = conn->handler->do_it(conn, done); @@ -1,5 +1,5 @@ -#ifndef __URL_H -#define __URL_H +#ifndef HEADER_CURL_URL_H +#define HEADER_CURL_URL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -21,8 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ - -#include <stdarg.h> /* to make sure we have ap_list */ +#include "setup.h" /* * Prototypes for library-wide functions provided by url.c @@ -44,7 +43,6 @@ CURLcode Curl_disconnect(struct connectdata *, bool dead_connection); CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done); CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done); CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done); -void Curl_safefree(void *ptr); CURLcode Curl_setup_conn(struct connectdata *conn, bool *protocol_done); @@ -88,10 +86,10 @@ void Curl_reset_reqproto(struct connectdata *conn); CURLcode Curl_connected_proxy(struct connectdata *conn); #ifdef CURL_DISABLE_VERBOSE_STRINGS -#define Curl_verboseconnect(x) do { } while (0) +#define Curl_verboseconnect(x) Curl_nop_stmt #else void Curl_verboseconnect(struct connectdata *conn); #endif -#endif +#endif /* HEADER_CURL_URL_H */ diff --git a/lib/urldata.h b/lib/urldata.h index d256968db..5b3dc059e 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -273,6 +273,7 @@ struct ssl_connect_data { struct SessionHandle *data; #ifdef HAVE_PK11_CREATEGENERICOBJECT struct curl_llist *obj_list; + PK11GenericObject *obj_clicert; #endif #endif /* USE_NSS */ #ifdef USE_QSOSSL @@ -360,7 +361,7 @@ struct ntlmdata { SEC_WINNT_AUTH_IDENTITY *p_identity; int has_handles; void *type_2; - int n_type_2; + unsigned long n_type_2; #else unsigned int flags; unsigned char nonce[8]; @@ -411,7 +412,7 @@ struct ConnectBits { bool do_more; /* this is set TRUE if the ->curl_do_more() function is supposed to be called, after ->curl_do() */ - bool tcpconnect; /* the TCP layer (or similar) is connected, this is set + bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set the first time on the first connect function call */ bool protoconnstart;/* the protocol layer has STARTED its operation after the TCP layer connect */ @@ -670,6 +671,12 @@ struct Curl_handler { curl_socket_t *socks, int numsocks); + /* Called from the multi interface during the DO_MORE phase, and it should + then return a proper fd set */ + int (*domore_getsock)(struct connectdata *conn, + curl_socket_t *socks, + int numsocks); + /* 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. */ @@ -905,6 +912,14 @@ struct connectdata { single requests! */ struct ntlmdata proxyntlm; /* NTLM data for proxy */ +#if defined(USE_NTLM) && 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_header; + char* response_header; +#endif + char syserr_buf [256]; /* buffer for Curl_strerror() */ #ifdef CURLRES_ASYNCH @@ -1517,6 +1532,9 @@ struct UserDefined { curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds to pattern (e.g. if WILDCARDMATCH is on) */ void *fnmatch_data; + + long gssapi_delegation; /* GSSAPI credential delegation, see the + documentation of CURLOPT_GSSAPI_DELEGATION */ }; struct Names { diff --git a/lib/version.c b/lib/version.c index c471dc106..c56ad3962 100644 --- a/lib/version.c +++ b/lib/version.c @@ -22,9 +22,6 @@ #include "setup.h" -#include <string.h> -#include <stdio.h> - #include <curl/curl.h> #include "urldata.h" #include "sslgen.h" @@ -243,6 +240,9 @@ static curl_version_info_data version_info = { #ifdef USE_NTLM | CURL_VERSION_NTLM #endif +#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED) + | CURL_VERSION_NTLM_WB +#endif #ifdef USE_WINDOWS_SSPI | CURL_VERSION_SSPI #endif diff --git a/lib/warnless.c b/lib/warnless.c index 37d15ce87..0f5fb5f4d 100644 --- a/lib/warnless.c +++ b/lib/warnless.c @@ -268,6 +268,25 @@ size_t curlx_sotouz(curl_off_t sonum) #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 +} + #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset) diff --git a/lib/warnless.h b/lib/warnless.h index 9ac59ac29..27cf57c31 100644 --- a/lib/warnless.h +++ b/lib/warnless.h @@ -38,6 +38,8 @@ ssize_t curlx_uztosz(size_t uznum); size_t curlx_sotouz(curl_off_t sonum); +size_t curlx_sitouz(int sinum); + #if defined(__INTEL_COMPILER) && defined(__unix__) int curlx_FD_ISSET(int fd, fd_set *fdset); diff --git a/lib/wildcard.c b/lib/wildcard.c index 9fe5d5135..6f4c7380c 100644 --- a/lib/wildcard.c +++ b/lib/wildcard.c @@ -21,6 +21,7 @@ ***************************************************************************/ #include "setup.h" + #include "wildcard.h" #include "llist.h" #include "fileinfo.h" diff --git a/m4/curl-compilers.m4 b/m4/curl-compilers.m4 index adafaa61d..c0f18c897 100644 --- a/m4/curl-compilers.m4 +++ b/m4/curl-compilers.m4 @@ -21,7 +21,7 @@ #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. -# serial 57 +# serial 58 dnl CURL_CHECK_COMPILER @@ -423,35 +423,39 @@ dnl GNUC versions these warnings are not silenced. AC_DEFUN([CURL_CONVERT_INCLUDE_TO_ISYSTEM], [ AC_REQUIRE([CURL_SHFUNC_SQUEEZE])dnl - 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 + AC_REQUIRE([CURL_CHECK_COMPILER])dnl + if test "$compiler_id" = "GNU_C" || + test "$compiler_id" = "CLANG"; then + 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 fi ]) diff --git a/m4/curl-confopts.m4 b/m4/curl-confopts.m4 index 30fb025fd..9d4315626 100644 --- a/m4/curl-confopts.m4 +++ b/m4/curl-confopts.m4 @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -21,7 +21,7 @@ #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. -# serial 14 +# serial 16 dnl CURL_CHECK_OPTION_THREADED_RESOLVER dnl ------------------------------------------------- @@ -496,3 +496,64 @@ AC_DEFUN([CURL_CHECK_LIB_ARES], [ 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, +AC_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)]) +AC_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 "$ac_cv_native_windows" = "yes" || + test "x$SSL_ENABLED" = "x"; then + want_ntlm_wb_file="" + 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 +]) + diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 index ec57b5423..419571a26 100644 --- a/m4/curl-functions.m4 +++ b/m4/curl-functions.m4 @@ -21,7 +21,7 @@ #*************************************************************************** # File version for 'aclocal' use. Keep it a single number. -# serial 65 +# serial 68 dnl CURL_INCLUDES_ARPA_INET @@ -5624,6 +5624,95 @@ AC_DEFUN([CURL_CHECK_FUNC_SOCKET], [ ]) +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.]) + ac_cv_func_socketpair="yes" + else + AC_MSG_RESULT([no]) + ac_cv_func_socketpair="no" + fi +]) + + dnl CURL_CHECK_FUNC_STRCASECMP dnl ------------------------------------------------- dnl Verify if strcasecmp is available, prototyped, and diff --git a/m4/curl-openssl.m4 b/m4/curl-openssl.m4 index 9adc80fd5..cd9074b02 100644 --- a/m4/curl-openssl.m4 +++ b/m4/curl-openssl.m4 @@ -55,7 +55,7 @@ AC_DEFUN([CURL_CHECK_OPENSSL_API_HEADERS], [ tst_verfix=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 5` tst_api=0x$tst_vermaj$tst_vermin$tst_verfix ;; - x11) + x11|x10) tst_vermaj=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 3` tst_vermin=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 5` tst_verfix=`echo $curl_cv_def_OPENSSL_VERSION_NUMBER | cut -c 7` @@ -43,7 +43,7 @@ patch=`echo $libversion |cut -d. -f3 | cut -d- -f1 | sed -e "s/[^0-9]//g"` numeric=`perl -e 'printf("%02x%02x%02x\n", '"$major, $minor, $patch);"` HEADER=include/curl/curlver.h -CHEADER=src/version.h +CHEADER=src/tool_version.h # requires a date command that knows -u for UTC time zone datestamp=`date -u` @@ -94,6 +94,9 @@ findprog() echo "maketgz: cp lib/curl_config.h.in src/curl_config.h.in" cp lib/curl_config.h.in src/curl_config.h.in +echo "maketgz: cp lib/config-win32.h src/config-win32.h" +cp lib/config-win32.h src/config-win32.h + ############################################################################ # # Enforce a rerun of configure (updates the VERSION) diff --git a/packages/OS400/README.OS400 b/packages/OS400/README.OS400 index 0cd5633aa..0dba7654a 100644 --- a/packages/OS400/README.OS400 +++ b/packages/OS400/README.OS400 @@ -147,6 +147,10 @@ use: CURLINFO_EFFECTIVE_URL CURLINFO_CONTENT_TYPE CURLINFO_FTP_ENTRY_PATH + CURLINFO_REDIRECT_URL + CURLINFO_PRIMARY_IP + CURLINFO_RTSP_SESSION_ID + CURLINFO_LOCAL_IP Other options are processed like in curl_easy_getinfo(). Standard compilation environment does support neither autotools nor make; @@ -159,14 +163,27 @@ OS/400. Protocols currently implemented on OS/400: -_ HTTP -_ HTTPS +_ DICT +_ FILE _ FTP _ FTPS -_ FTP with secure transmission. +_ FTP with secure transmission +_ GOPHER +_ HTTP +_ HTTPS +_ IMAP +_ IMAPS +_ IMAP with secure transmission _ LDAP -_ DICT +_ POP3 +_ POP3S +_ POP3 with secure transmission +_ RTSP +_ SMTP +_ SMTPS +_ SMTP with secure transmission _ TELNET +_ TFTP diff --git a/packages/OS400/curl.inc.in b/packages/OS400/curl.inc.in index 65c1e72be..ce70ba471 100644 --- a/packages/OS400/curl.inc.in +++ b/packages/OS400/curl.inc.in @@ -913,7 +913,7 @@ d CURLOPT_SHARE c 10100 d CURLOPT_PROXYTYPE... d c 00101 - d CURLOPT_ENCODING... + d CURLOPT_ACCEPT_ENCODING... d c 10102 d CURLOPT_PRIVATE... d c 10103 @@ -1105,6 +1105,12 @@ 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 * /if not defined(CURL_NO_OLDIES) d CURLOPT_SSLKEYPASSWD... @@ -1117,6 +1123,8 @@ d c 00050 d CURLOPT_KRB4LEVEL... d c 10063 + d CURLOPT_ENCODING... + d c 10102 d CURLOPT_SERVER_RESPONSE_TIMEOUT... d c 00112 d CURLOPT_FTP_SSL... @@ -1623,6 +1631,9 @@ d curl_fnmatch_callback... d s * based(######ptr######) procptr * + d curl_closesocket_callback... + d s * based(######ptr######) procptr + * ************************************************************************** * Prototypes ************************************************************************** diff --git a/packages/OS400/initscript.sh b/packages/OS400/initscript.sh index 9bf93a8e6..97e978158 100644 --- a/packages/OS400/initscript.sh +++ b/packages/OS400/initscript.sh @@ -155,7 +155,7 @@ db2_name() { basename "${1}" | - tr '[a-z-]' '[A-Z_]' | + tr 'a-z-' 'A-Z_' | sed -e 's/\..*//' \ -e 's/^\(..........\).*/\1/' } diff --git a/packages/OS400/make-lib.sh b/packages/OS400/make-lib.sh index 9b3e335ab..46c479c3f 100644 --- a/packages/OS400/make-lib.sh +++ b/packages/OS400/make-lib.sh @@ -46,9 +46,7 @@ make_module OS400SYS "${SCRIPTDIR}/os400sys.c" make_module CCSIDCURL "${SCRIPTDIR}/ccsidcurl.c" for SRC in ${CSOURCES} -do MODULE=`basename "${SRC}" .c | - tr '[a-z]' '[A-Z]' | - sed -e 's/^\(..........\).*/\1/'` +do MODULE=`db2_name "${SRC}"` make_module "${MODULE}" "${SRC}" done diff --git a/packages/OS400/make-tests.sh b/packages/OS400/make-tests.sh index cee3ed95d..e40b41046 100644 --- a/packages/OS400/make-tests.sh +++ b/packages/OS400/make-tests.sh @@ -22,6 +22,8 @@ cd libtest # _ Retain only lines that begins with "identifier =". # _ Turn these lines into shell variable assignments. +top_srcdir="${TOPDIR}" +export top_srcdir eval "`sed -e ': begin' \ -e '/\\\\$/{' \ -e 'N' \ diff --git a/packages/Symbian/group/curl.mmp b/packages/Symbian/group/curl.mmp index 706cba68b..3c47db3de 100644 --- a/packages/Symbian/group/curl.mmp +++ b/packages/Symbian/group/curl.mmp @@ -8,8 +8,44 @@ UID 0x00000000 0xF0206442 SOURCEPATH ../../../src SOURCE \ - main.c hugehelp.c urlglob.c writeout.c writeenv.c \ - getpass.c homedir.c curlutil.c os-specific.c xattr.c + hugehelp.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_skt.c \ + tool_cb_wrt.c \ + tool_cfgable.c \ + tool_convert.c \ + tool_dirhie.c \ + tool_doswin.c \ + tool_easysrc.c \ + tool_formparse.c \ + tool_getparam.c \ + tool_getpass.c \ + tool_help.c \ + tool_helpers.c \ + tool_homedir.c \ + tool_libinfo.c \ + tool_main.c \ + tool_mfiles.c \ + tool_msgs.c \ + tool_operate.c \ + tool_operhlp.c \ + tool_panykey.c \ + tool_paramhlp.c \ + tool_parsecfg.c \ + tool_setopt.c \ + tool_sleep.c \ + tool_urlglob.c \ + tool_util.c \ + tool_vms.c \ + tool_writeenv.c \ + tool_writeout.c \ + tool_xattr.c SOURCEPATH ../../../lib SOURCE \ diff --git a/packages/Symbian/group/libcurl.mmp b/packages/Symbian/group/libcurl.mmp index 274ba1fe7..5cab131b0 100644 --- a/packages/Symbian/group/libcurl.mmp +++ b/packages/Symbian/group/libcurl.mmp @@ -28,7 +28,7 @@ SOURCE \ curl_fnmatch.c fileinfo.c ftplistparser.c wildcard.c krb5.c \ memdebug.c http_chunks.c strtok.c connect.c llist.c hash.c multi.c \ content_encoding.c share.c http_digest.c md4.c md5.c curl_rand.c \ - http_negotiate.c http_ntlm.c inet_pton.c strtoofft.c strerror.c \ + http_negotiate.c curl_ntlm_msgs.c inet_pton.c strtoofft.c strerror.c \ hostasyn.c hostip4.c hostip6.c hostsyn.c inet_ntop.c parsedate.c \ select.c gtls.c sslgen.c tftp.c splay.c strdup.c socks.c ssh.c nss.c \ qssl.c rawstr.c curl_addrinfo.c socks_gssapi.c socks_sspi.c \ @@ -36,7 +36,7 @@ SOURCE \ pingpong.c rtsp.c curl_threads.c warnless.c hmac.c polarssl.c \ curl_rtmp.c openldap.c curl_gethostname.c gopher.c axtls.c \ idn_win32.c http_negotiate_sspi.c cyassl.c http_proxy.c non-ascii.c \ - asyn-ares.c asyn-thread.c + asyn-ares.c asyn-thread.c curl_ntlm.c curl_ntlm_wb.c curl_ntlm_core.c USERINCLUDE ../../../lib ../../../include/curl #ifdef ENABLE_SSL diff --git a/src/.gitignore b/src/.gitignore index 17de5c6a7..d99cc3f7c 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -6,4 +6,6 @@ stamp-h2 Makefile.vc8.dist Makefile.vc9.dist version.h.dist +tool_version.h.dist Makefile.vc10.dist +config-win32.h diff --git a/src/Makefile.Watcom b/src/Makefile.Watcom index 66c97ef45..f0477fd46 100644 --- a/src/Makefile.Watcom +++ b/src/Makefile.Watcom @@ -78,7 +78,7 @@ ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.5 !ifdef %libssh2_root LIBSSH2_ROOT = $(%libssh2_root) !else -LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.2.8 +LIBSSH2_ROOT = ..$(DS)..$(DS)libssh2-1.3.0 !endif !ifdef %librtmp_root diff --git a/src/Makefile.am b/src/Makefile.am index d697e78ea..a181f06bc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -51,8 +51,8 @@ CFLAGS += @CURL_CFLAG_EXTRAS@ curl_LDADD = $(top_builddir)/lib/libcurl.la @CURL_LIBS@ curl_DEPENDENCIES = $(top_builddir)/lib/libcurl.la -BUILT_SOURCES = hugehelp.c -CLEANFILES = hugehelp.c +BUILT_SOURCES = hugehelp.c config-win32.h +CLEANFILES = hugehelp.c config-win32.h # Use the C locale to ensure that only ASCII characters appear in the # embedded text. NROFF=env LC_ALL=C @NROFF@ @MANOPT@ # figured out by the configure script @@ -68,6 +68,11 @@ MANPAGE=$(top_srcdir)/docs/curl.1 README=$(top_srcdir)/docs/MANUAL MKHELP=$(top_srcdir)/src/mkhelp.pl HUGE=hugehelp.c +CFGWIN32=config-win32.h + +$(CFGWIN32): $(top_srcdir)/lib/config-win32.h + echo "creating $(CFGWIN32)" + @(cp $(top_srcdir)/lib/config-win32.h $(CFGWIN32)) if USE_MANUAL # Here are the stuff to create a built-in manual @@ -97,9 +102,9 @@ $(HUGE): endif # ignore hugehelp.c since it is generated source code and it plays by slightly -# different rules! +# different rules! config-win32.h already checked in lib subdir. checksrc: - @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/src -Whugehelp.c $(curl_SOURCES) + @@PERL@ $(top_srcdir)/lib/checksrc.pl -D$(top_srcdir)/src -Whugehelp.c -Wconfig-win32.h $(curl_SOURCES) if CURLDEBUG # for debug builds, we scan the sources on all regular make invokes diff --git a/src/Makefile.inc b/src/Makefile.inc index 058c6d28d..1660bc403 100644 --- a/src/Makefile.inc +++ b/src/Makefile.inc @@ -14,13 +14,86 @@ CURLX_ONES = $(top_srcdir)/lib/strtoofft.c \ $(top_srcdir)/lib/rawstr.c \ $(top_srcdir)/lib/nonblock.c -CURL_CFILES = main.c hugehelp.c urlglob.c writeout.c writeenv.c \ - getpass.c homedir.c curlutil.c os-specific.c xattr.c +CURL_CFILES = hugehelp.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_skt.c \ + tool_cb_wrt.c \ + tool_cfgable.c \ + tool_convert.c \ + tool_dirhie.c \ + tool_doswin.c \ + tool_easysrc.c \ + tool_formparse.c \ + tool_getparam.c \ + tool_getpass.c \ + tool_help.c \ + tool_helpers.c \ + tool_homedir.c \ + tool_libinfo.c \ + tool_main.c \ + tool_mfiles.c \ + tool_msgs.c \ + tool_operate.c \ + tool_operhlp.c \ + tool_panykey.c \ + tool_paramhlp.c \ + tool_parsecfg.c \ + tool_setopt.c \ + tool_sleep.c \ + tool_urlglob.c \ + tool_util.c \ + tool_vms.c \ + tool_writeenv.c \ + tool_writeout.c \ + tool_xattr.c CURL_HFILES = hugehelp.h setup.h config-win32.h config-mac.h \ - config-riscos.h urlglob.h version.h os-specific.h \ - writeout.h writeenv.h getpass.h homedir.h curlutil.h \ - xattr.h + config-riscos.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_skt.h \ + tool_cb_wrt.h \ + tool_cfgable.h \ + tool_convert.h \ + tool_dirhie.h \ + tool_doswin.h \ + tool_easysrc.h \ + tool_formparse.h \ + tool_getparam.h \ + tool_getpass.h \ + tool_help.h \ + tool_helpers.h \ + tool_homedir.h \ + tool_libinfo.h \ + tool_main.h \ + tool_mfiles.h \ + tool_msgs.h \ + tool_operate.h \ + tool_operhlp.h \ + tool_panykey.h \ + tool_paramhlp.h \ + tool_parsecfg.h \ + tool_sdecls.h \ + tool_setopt.h \ + tool_sleep.h \ + tool_urlglob.h \ + tool_util.h \ + tool_version.h \ + tool_vms.h \ + tool_writeenv.h \ + tool_writeout.h \ + tool_xattr.h curl_SOURCES = $(CURL_CFILES) $(CURLX_ONES) $(CURL_HFILES) diff --git a/src/Makefile.m32 b/src/Makefile.m32 index 3cafae7bb..0822e3a8e 100644 --- a/src/Makefile.m32 +++ b/src/Makefile.m32 @@ -1,7 +1,7 @@ -######################################################################### +########################################################################### # -## Makefile for building curl.exe with MingW32 (GCC-3.2 or later) -## and optionally OpenSSL (0.9.8), libssh2 (1.2), zlib (1.2.5), librtmp (2.3) +## Makefile for building curl.exe with MingW (GCC-3.2 or later) +## and optionally OpenSSL (0.9.8), libssh2 (1.3), zlib (1.2.5), librtmp (2.3) ## ## Usage: mingw32-make -f Makefile.m32 CFG=-feature1[-feature2][-feature3][...] ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-spi-winidn @@ -9,10 +9,8 @@ ## Hint: you can also set environment vars to control the build, f.e.: ## set ZLIB_PATH=c:/zlib-1.2.5 ## set ZLIB=1 -## -## Comments to: Troy Engel <tengel@sonic.net> or -## Joern Hartroth <hartroth@acm.org> -######################################################################### +# +########################################################################### # Edit the path below to point to the base of your Zlib sources. ifndef ZLIB_PATH @@ -22,9 +20,15 @@ endif ifndef OPENSSL_PATH OPENSSL_PATH = ../../openssl-0.9.8r endif +ifndef OPENSSL_LIBPATH +OPENSSL_LIBPATH = $(OPENSSL_PATH)/out +endif +ifndef OPENSSL_LIBS +OPENSSL_LIBS = -leay32 -lssl32 +endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your librtmp package. ifndef LIBRTMP_PATH @@ -45,17 +49,29 @@ ifndef LDAP_SDK LDAP_SDK = c:/novell/ndk/cldapsdk/win32 endif +PROOT = .. + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH -LIBCARES_PATH = ../ares +LIBCARES_PATH = $(PROOT)/ares +endif + +# Edit the var below to set to your architecture or set environment var. +ifndef ARCH +ARCH = w32 endif CC = gcc CFLAGS = -g -O2 -Wall +CFLAGS += -fno-strict-aliasing +ifeq ($(ARCH),w64) +CFLAGS += -D_AMD64_ +endif # comment LDFLAGS below to keep debug info LDFLAGS = -s RC = windres -RCFLAGS = --include-dir=../include -O COFF -i +RCFLAGS = --include-dir=$(PROOT)/include -O COFF -i + RM = del /q /f 2>NUL CP = copy @@ -97,6 +113,9 @@ endif ifeq ($(findstring -sspi,$(CFG)),-sspi) SSPI = 1 endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +SPNEGO = 1 +endif ifeq ($(findstring -ldaps,$(CFG)),-ldaps) LDAPS = 1 endif @@ -105,15 +124,13 @@ IPV6 = 1 endif INCLUDES = -I. -I.. -I../include -I../lib -LINK = $(CC) $(LDFLAGS) -o $@ -curl_PROGRAMS = curl.exe ifdef DYN - curl_DEPENDENCIES = ../lib/libcurldll.a ../lib/libcurl.dll - curl_LDADD = -L../lib -lcurldll + curl_DEPENDENCIES = $(PROOT)/lib/libcurldll.a $(PROOT)/lib/libcurl.dll + curl_LDADD = -L$(PROOT)/lib -lcurldll else - curl_DEPENDENCIES = ../lib/libcurl.a - curl_LDADD = -L../lib -lcurl + curl_DEPENDENCIES = $(PROOT)/lib/libcurl.a + curl_LDADD = -L$(PROOT)/lib -lcurl CFLAGS += -DCURL_STATICLIB endif ifdef ARES @@ -121,7 +138,7 @@ ifdef ARES curl_DEPENDENCIES += $(LIBCARES_PATH)/libcares.a endif CFLAGS += -DUSE_ARES - curl_LDADD += -L$(LIBCARES_PATH) -lcares + curl_LDADD += -L"$(LIBCARES_PATH)" -lcares endif ifdef RTMP CFLAGS += -DUSE_LIBRTMP @@ -129,32 +146,34 @@ ifdef RTMP endif ifdef SSH2 CFLAGS += -DUSE_LIBSSH2 -DHAVE_LIBSSH2_H - curl_LDADD += -L$(LIBSSH2_PATH)/win32 -lssh2 + curl_LDADD += -L"$(LIBSSH2_PATH)/win32" -lssh2 endif ifdef SSL CFLAGS += -DUSE_SSLEAY -DHAVE_OPENSSL_ENGINE_H - curl_LDADD += -L$(OPENSSL_PATH)/out -leay32 -lssl32 + curl_LDADD += -L"$(OPENSSL_LIBPATH)" $(OPENSSL_LIBS) endif ifdef ZLIB INCLUDES += -I"$(ZLIB_PATH)" CFLAGS += -DHAVE_LIBZ -DHAVE_ZLIB_H - curl_LDADD += -L$(ZLIB_PATH) -lz + curl_LDADD += -L"$(ZLIB_PATH)" -lz endif ifdef IDN - INCLUDES += -I"$(LIBIDN_PATH)/include" CFLAGS += -DUSE_LIBIDN - curl_LDADD += -L$(LIBIDN_PATH)/lib -lidn + curl_LDADD += -L"$(LIBIDN_PATH)/lib" -lidn else ifdef WINIDN CFLAGS += -DUSE_WIN32_IDN - DLL_LIBS += -L"$(WINIDN_PATH)" -lnormaliz + curl_LDADD += -L"$(WINIDN_PATH)" -lnormaliz endif endif ifdef SSPI CFLAGS += -DUSE_WINDOWS_SSPI endif +ifdef SPNEGO + CFLAGS += -DHAVE_SPNEGO +endif ifdef IPV6 - CFLAGS += -DENABLE_IPV6 + CFLAGS += -DENABLE_IPV6 -D_WIN32_WINNT=0x0501 endif ifdef LDAPS CFLAGS += -DHAVE_LDAP_SSL @@ -173,48 +192,47 @@ curl_LDADD += -lwldap32 endif endif curl_LDADD += -lws2_32 -COMPILE = $(CC) $(INCLUDES) $(CFLAGS) # Makefile.inc provides the CSOURCES and HHEADERS defines include Makefile.inc +curl_PROGRAMS = curl.exe curl_OBJECTS := $(patsubst %.c,%.o,$(strip $(CURL_CFILES))) -ifdef DYN curlx_OBJECTS := $(patsubst %.c,%.o,$(notdir $(strip $(CURLX_ONES)))) +ifdef DYN curl_OBJECTS += $(curlx_OBJECTS) -vpath %.c ../lib +vpath %.c $(PROOT)/lib endif RESOURCE = curl.res -.SUFFIXES: .rc .res -all: curl.exe +all: $(curl_PROGRAMS) curl.exe: $(RESOURCE) $(curl_OBJECTS) $(curl_DEPENDENCIES) -$(RM) $@ - $(LINK) $< $(curl_OBJECTS) $(curl_LDADD) + $(CC) $(LDFLAGS) -o $@ $< $(curl_OBJECTS) $(curl_LDADD) # We don't have nroff normally under win32 -# hugehelp.c: ../README.curl ../curl.1 mkhelp.pl +# hugehelp.c: $(PROOT)/README.curl $(PROOT)/curl.1 mkhelp.pl # -$(RM) hugehelp.c -# $(NROFF) -man ../curl.1 | $(PERL) mkhelp.pl ../README.curl > hugehelp.c +# $(NROFF) -man $(PROOT)/curl.1 | $(PERL) mkhelp.pl $(PROOT)/README.curl > hugehelp.c hugehelp.c: @echo Creating $@ @$(CP) hugehelp.c.cvs $@ -.c.o: - $(COMPILE) -c $< +%.o: %.c + $(CC) $(INCLUDES) $(CFLAGS) -c $< -.rc.res: +%.res: %.rc $(RC) $(RCFLAGS) $< -o $@ clean: ifeq "$(wildcard hugehelp.c.cvs)" "hugehelp.c.cvs" -$(RM) hugehelp.c endif - -$(RM) $(curl_OBJECTS) $(RESOURCE) + -$(RM) $(curl_OBJECTS) $(curlx_OBJECTS) $(RESOURCE) distclean vclean: clean -$(RM) $(curl_PROGRAMS) diff --git a/src/Makefile.netware b/src/Makefile.netware index 85e0c92ee..8e66f7919 100644 --- a/src/Makefile.netware +++ b/src/Makefile.netware @@ -24,7 +24,7 @@ endif # Edit the path below to point to the base of your LibSSH2 package. ifndef LIBSSH2_PATH -LIBSSH2_PATH = ../../libssh2-1.2.8 +LIBSSH2_PATH = ../../libssh2-1.3.0 endif # Edit the path below to point to the base of your axTLS package. @@ -42,6 +42,11 @@ ifndef LIBRTMP_PATH LIBRTMP_PATH = ../../librtmp-2.3 endif +# Edit the path below to point to the base of your fbopenssl package. +ifndef FBOPENSSL_PATH +FBOPENSSL_PATH = ../../fbopenssl-0.4 +endif + # Edit the path below to point to the base of your c-ares package. ifndef LIBCARES_PATH LIBCARES_PATH = ../ares @@ -96,7 +101,7 @@ else endif PERL = perl # Here you can find a native Win32 binary of the original awk: -# http://www.gknw.net/development/prgtools/awk-20070501.zip +# http://www.gknw.net/development/prgtools/awk-20100523.zip AWK = awk CP = cp -afv MKDIR = mkdir @@ -176,6 +181,43 @@ CURL_LIB = ../lib INCLUDES = -I$(CURL_INC) -I$(CURL_LIB) +ifeq ($(findstring -static,$(CFG)),-static) +LINK_STATIC = 1 +endif +ifeq ($(findstring -ares,$(CFG)),-ares) +WITH_ARES = 1 +endif +ifeq ($(findstring -rtmp,$(CFG)),-rtmp) +WITH_RTMP = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -ssh2,$(CFG)),-ssh2) +WITH_SSH2 = 1 +WITH_SSL = 1 +WITH_ZLIB = 1 +endif +ifeq ($(findstring -axtls,$(CFG)),-axtls) +WITH_AXTLS = 1 +WITH_SSL = +else +ifeq ($(findstring -ssl,$(CFG)),-ssl) +WITH_SSL = 1 +endif +endif +ifeq ($(findstring -zlib,$(CFG)),-zlib) +WITH_ZLIB = 1 +endif +ifeq ($(findstring -idn,$(CFG)),-idn) +WITH_IDN = 1 +endif +ifeq ($(findstring -spnego,$(CFG)),-spnego) +WITH_SPNEGO = 1 +endif +ifeq ($(findstring -ipv6,$(CFG)),-ipv6) +ENABLE_IPV6 = 1 +endif + ifdef LINK_STATIC LDLIBS = $(CURL_LIB)/libcurl.$(LIBEXT) ifdef WITH_ARES @@ -186,7 +228,7 @@ else IMPORTS = @$(CURL_LIB)/libcurl.imp endif ifdef WITH_SSH2 - INCLUDES += -I$(LIBSSH2_PATH)/include + # INCLUDES += -I$(LIBSSH2_PATH)/include ifdef LINK_STATIC LDLIBS += $(LIBSSH2_PATH)/nw/libssh2.$(LIBEXT) else @@ -201,13 +243,17 @@ ifdef LINK_STATIC endif endif ifdef WITH_SSL - INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) + # INCLUDES += -I$(OPENSSL_PATH)/outinc_nw_$(LIBARCH_L) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/ssl.$(LIBEXT) LDLIBS += $(OPENSSL_PATH)/out_nw_$(LIBARCH_L)/crypto.$(LIBEXT) IMPORTS += GetProcessSwitchCount RunningProcess +ifdef WITH_SPNEGO + # INCLUDES += -I$(FBOPENSSL_PATH)/include + LDLIBS += $(FBOPENSSL_PATH)/nw/fbopenssl.$(LIBEXT) +endif else ifdef WITH_AXTLS - INCLUDES += -I$(AXTLS_PATH)/inc + # INCLUDES += -I$(AXTLS_PATH)/inc ifdef LINK_STATIC LDLIBS += $(AXTLS_PATH)/lib/libaxtls.$(LIBEXT) else @@ -491,6 +537,7 @@ endif @echo $(DL)#define USE_MANUAL 1$(DL) >> $@ @echo $(DL)#define HAVE_ARPA_INET_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ASSERT_H 1$(DL) >> $@ + @echo $(DL)#define HAVE_ERRNO_H 1$(DL) >> $@ @echo $(DL)#define HAVE_ERR_H 1$(DL) >> $@ @echo $(DL)#define HAVE_FCNTL_H 1$(DL) >> $@ @echo $(DL)#define HAVE_GETHOSTBYADDR 1$(DL) >> $@ @@ -576,6 +623,9 @@ ifdef WITH_SSL @echo $(DL)#define HAVE_LIBSSL 1$(DL) >> $@ @echo $(DL)#define HAVE_LIBCRYPTO 1$(DL) >> $@ @echo $(DL)#define OPENSSL_NO_KRB5 1$(DL) >> $@ +ifdef WITH_SPNEGO + @echo $(DL)#define HAVE_SPNEGO 1$(DL) >> $@ +endif else ifdef WITH_AXTLS @echo $(DL)#define USE_AXTLS 1$(DL) >> $@ diff --git a/src/Makefile.vc6 b/src/Makefile.vc6 index a25680be2..dbd32f175 100644 --- a/src/Makefile.vc6 +++ b/src/Makefile.vc6 @@ -20,6 +20,11 @@ #
#***************************************************************************
+# All files in the Makefile.vc* series are generated automatically from the
+# one made for MSVC version 6. Alas, if you want to do changes to any of the
+# fiels and send back to the project, edit the version six, make your diff and
+# mail curl-users.
+
#############################################################
#
## Makefile for building curl.exe with MSVC6
@@ -37,7 +42,7 @@ PROGRAM_NAME = curl.exe # Verify that current subdir is curl's 'src'
# -------------------------------------------
-!IF ! EXIST(.\main.c)
+!IF ! EXIST(.\tool_main.c)
! MESSAGE Can not process this makefile from outside of curl's 'src' subdirectory.
! MESSAGE Change to curl's 'src' subdirectory, and try again.
! ERROR See previous message.
@@ -128,33 +133,91 @@ CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include !ENDIF
RELEASE_OBJS= \
- curlutilr.obj \
- getpassr.obj \
- homedirr.obj \
hugehelpr.obj \
- mainr.obj \
nonblockr.obj \
- os-specificr.obj \
rawstrr.obj \
strtoofftr.obj \
- urlglobr.obj \
- writeoutr.obj \
- xattrr.obj \
+ tool_binmoder.obj \
+ tool_bnamer.obj \
+ tool_cb_dbgr.obj \
+ tool_cb_hdrr.obj \
+ tool_cb_prgr.obj \
+ tool_cb_rear.obj \
+ tool_cb_seer.obj \
+ tool_cb_sktr.obj \
+ tool_cb_wrtr.obj \
+ tool_cfgabler.obj \
+ tool_convertr.obj \
+ tool_dirhier.obj \
+ tool_doswinr.obj \
+ tool_easysrcr.obj \
+ tool_formparser.obj \
+ tool_getparamr.obj \
+ tool_getpassr.obj \
+ tool_helpr.obj \
+ tool_helpersr.obj \
+ tool_homedirr.obj \
+ tool_libinfor.obj \
+ tool_mainr.obj \
+ tool_mfilesr.obj \
+ tool_msgsr.obj \
+ tool_operater.obj \
+ tool_operhlpr.obj \
+ tool_panykeyr.obj \
+ tool_paramhlpr.obj \
+ tool_parsecfgr.obj \
+ tool_setoptr.obj \
+ tool_sleepr.obj \
+ tool_urlglobr.obj \
+ tool_utilr.obj \
+ tool_vmsr.obj \
+ tool_writeenvr.obj \
+ tool_writeoutr.obj \
+ tool_xattrr.obj \
curlr.res
DEBUG_OBJS= \
- curlutild.obj \
- getpassd.obj \
- homedird.obj \
hugehelpd.obj \
- maind.obj \
nonblockd.obj \
- os-specificd.obj \
rawstrd.obj \
strtoofftd.obj \
- urlglobd.obj \
- writeoutd.obj \
- xattrd.obj \
+ tool_binmoded.obj \
+ tool_bnamed.obj \
+ tool_cb_dbgd.obj \
+ tool_cb_hdrd.obj \
+ tool_cb_prgd.obj \
+ tool_cb_read.obj \
+ tool_cb_seed.obj \
+ tool_cb_sktd.obj \
+ tool_cb_wrtd.obj \
+ tool_cfgabled.obj \
+ tool_convertd.obj \
+ tool_dirhied.obj \
+ tool_doswind.obj \
+ tool_easysrcd.obj \
+ tool_formparsed.obj \
+ tool_getparamd.obj \
+ tool_getpassd.obj \
+ tool_helpd.obj \
+ tool_helpersd.obj \
+ tool_homedird.obj \
+ tool_libinfod.obj \
+ tool_maind.obj \
+ tool_mfilesd.obj \
+ tool_msgsd.obj \
+ tool_operated.obj \
+ tool_operhlpd.obj \
+ tool_panykeyd.obj \
+ tool_paramhlpd.obj \
+ tool_parsecfgd.obj \
+ tool_setoptd.obj \
+ tool_sleepd.obj \
+ tool_urlglobd.obj \
+ tool_utild.obj \
+ tool_vmsd.obj \
+ tool_writeenvd.obj \
+ tool_writeoutd.obj \
+ tool_xattrd.obj \
curld.res
#################################################
@@ -279,56 +342,172 @@ debug: $(DEBUG_OBJS) ## Release
hugehelpr.obj: hugehelp.c
$(CCR) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
-writeoutr.obj: writeout.c
- $(CCR) $(CFLAGS) /Fo"$@" writeout.c
-urlglobr.obj: urlglob.c
- $(CCR) $(CFLAGS) /Fo"$@" urlglob.c
-getpassr.obj: getpass.c
- $(CCR) $(CFLAGS) /Fo"$@" getpass.c
-homedirr.obj: homedir.c
- $(CCR) $(CFLAGS) /Fo"$@" homedir.c
-curlutilr.obj: curlutil.c
- $(CCR) $(CFLAGS) /Fo"$@" curlutil.c
-os-specificr.obj: os-specific.c
- $(CCR) $(CFLAGS) /Fo"$@" os-specific.c
nonblockr.obj: ../lib/nonblock.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
rawstrr.obj: ../lib/rawstr.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
strtoofftr.obj: ../lib/strtoofft.c
$(CCR) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
-xattrr.obj: xattr.c
- $(CCR) $(CFLAGS) /Fo"$@" xattr.c
-mainr.obj: main.c
- $(CCR) $(CFLAGS) /Fo"$@" main.c
+tool_binmoder.obj: tool_binmode.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamer.obj: tool_bname.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgr.obj: tool_cb_dbg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrr.obj: tool_cb_hdr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgr.obj: tool_cb_prg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_rear.obj: tool_cb_rea.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seer.obj: tool_cb_see.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_sktr.obj: tool_cb_skt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_skt.c
+tool_cb_wrtr.obj: tool_cb_wrt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabler.obj: tool_cfgable.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertr.obj: tool_convert.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhier.obj: tool_dirhie.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswinr.obj: tool_doswin.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcr.obj: tool_easysrc.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparser.obj: tool_formparse.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamr.obj: tool_getparam.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassr.obj: tool_getpass.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpr.obj: tool_help.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersr.obj: tool_helpers.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedirr.obj: tool_homedir.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfor.obj: tool_libinfo.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_mainr.obj: tool_main.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_main.c
+tool_mfilesr.obj: tool_mfiles.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsr.obj: tool_msgs.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operater.obj: tool_operate.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpr.obj: tool_operhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyr.obj: tool_panykey.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpr.obj: tool_paramhlp.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgr.obj: tool_parsecfg.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptr.obj: tool_setopt.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepr.obj: tool_sleep.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobr.obj: tool_urlglob.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utilr.obj: tool_util.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsr.obj: tool_vms.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvr.obj: tool_writeenv.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutr.obj: tool_writeout.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrr.obj: tool_xattr.c
+ $(CCR) $(CFLAGS) /Fo"$@" tool_xattr.c
curlr.res : curl.rc
$(RCR) $(RESFLAGS) /Fo"$@" curl.rc
## Debug
hugehelpd.obj: hugehelp.c
$(CCD) $(CFLAGS) /Zm200 /Fo"$@" hugehelp.c
-writeoutd.obj: writeout.c
- $(CCD) $(CFLAGS) /Fo"$@" writeout.c
-urlglobd.obj: urlglob.c
- $(CCD) $(CFLAGS) /Fo"$@" urlglob.c
-getpassd.obj: getpass.c
- $(CCD) $(CFLAGS) /Fo"$@" getpass.c
-homedird.obj: homedir.c
- $(CCD) $(CFLAGS) /Fo"$@" homedir.c
-curlutild.obj: curlutil.c
- $(CCD) $(CFLAGS) /Fo"$@" curlutil.c
-os-specificd.obj: os-specific.c
- $(CCD) $(CFLAGS) /Fo"$@" os-specific.c
nonblockd.obj: ../lib/nonblock.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/nonblock.c
rawstrd.obj: ../lib/rawstr.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/rawstr.c
strtoofftd.obj: ../lib/strtoofft.c
$(CCD) $(CFLAGS) /Fo"$@" ../lib/strtoofft.c
-xattrd.obj: xattr.c
- $(CCD) $(CFLAGS) /Fo"$@" xattr.c
-maind.obj: main.c
- $(CCD) $(CFLAGS) /Fo"$@" main.c
+tool_binmoded.obj: tool_binmode.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_binmode.c
+tool_bnamed.obj: tool_bname.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_bname.c
+tool_cb_dbgd.obj: tool_cb_dbg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_dbg.c
+tool_cb_hdrd.obj: tool_cb_hdr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_hdr.c
+tool_cb_prgd.obj: tool_cb_prg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_prg.c
+tool_cb_read.obj: tool_cb_rea.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_rea.c
+tool_cb_seed.obj: tool_cb_see.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_see.c
+tool_cb_sktd.obj: tool_cb_skt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_skt.c
+tool_cb_wrtd.obj: tool_cb_wrt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cb_wrt.c
+tool_cfgabled.obj: tool_cfgable.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_cfgable.c
+tool_convertd.obj: tool_convert.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_convert.c
+tool_dirhied.obj: tool_dirhie.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_dirhie.c
+tool_doswind.obj: tool_doswin.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_doswin.c
+tool_easysrcd.obj: tool_easysrc.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_easysrc.c
+tool_formparsed.obj: tool_formparse.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_formparse.c
+tool_getparamd.obj: tool_getparam.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getparam.c
+tool_getpassd.obj: tool_getpass.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_getpass.c
+tool_helpd.obj: tool_help.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_help.c
+tool_helpersd.obj: tool_helpers.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_helpers.c
+tool_homedird.obj: tool_homedir.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_homedir.c
+tool_libinfod.obj: tool_libinfo.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_libinfo.c
+tool_maind.obj: tool_main.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_main.c
+tool_mfilesd.obj: tool_mfiles.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_mfiles.c
+tool_msgsd.obj: tool_msgs.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_msgs.c
+tool_operated.obj: tool_operate.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operate.c
+tool_operhlpd.obj: tool_operhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_operhlp.c
+tool_panykeyd.obj: tool_panykey.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_panykey.c
+tool_paramhlpd.obj: tool_paramhlp.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_paramhlp.c
+tool_parsecfgd.obj: tool_parsecfg.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_parsecfg.c
+tool_setoptd.obj: tool_setopt.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_setopt.c
+tool_sleepd.obj: tool_sleep.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_sleep.c
+tool_urlglobd.obj: tool_urlglob.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_urlglob.c
+tool_utild.obj: tool_util.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_util.c
+tool_vmsd.obj: tool_vms.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_vms.c
+tool_writeenvd.obj: tool_writeenv.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeenv.c
+tool_writeoutd.obj: tool_writeout.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_writeout.c
+tool_xattrd.obj: tool_xattr.c
+ $(CCD) $(CFLAGS) /Fo"$@" tool_xattr.c
curld.res : curl.rc
$(RCD) $(RESFLAGS) /Fo"$@" curl.rc
diff --git a/src/config-amigaos.h b/src/config-amigaos.h index fba875dab..7f8e0a869 100644 --- a/src/config-amigaos.h +++ b/src/config-amigaos.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -30,6 +30,7 @@ #define OS "AmigaOS" #define HAVE_CLOSESOCKET_CAMEL 1 +#define HAVE_ERRNO_H 1 #define HAVE_UNISTD_H 1 #define HAVE_STRDUP 1 #define HAVE_UTIME 1 diff --git a/src/config-mac.h b/src/config-mac.h index f8aeb7a66..19c24c760 100644 --- a/src/config-mac.h +++ b/src/config-mac.h @@ -32,6 +32,7 @@ #define USE_MANUAL 1 #define HAVE_UNISTD_H 1 +#define HAVE_ERRNO_H 1 #define HAVE_FCNTL_H 1 #define HAVE_UTIME_H 1 #define HAVE_SYS_UTIME_H 1 diff --git a/src/config-riscos.h b/src/config-riscos.h index 7816bab13..c9aa7bcc0 100644 --- a/src/config-riscos.h +++ b/src/config-riscos.h @@ -91,6 +91,9 @@ /* Define if you have the <des.h> header file. */ #undef HAVE_DES_H +/* Define if you have the <errno.h> header file. */ +#define HAVE_ERRNO_H + /* Define if you have the <err.h> header file. */ #undef HAVE_ERR_H diff --git a/src/config-win32.h b/src/config-win32.h deleted file mode 100644 index 38a329826..000000000 --- a/src/config-win32.h +++ /dev/null @@ -1,439 +0,0 @@ -#ifndef __SRC_CONFIG_WIN32_H -#define __SRC_CONFIG_WIN32_H -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://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. - * - ***************************************************************************/ - -/* ================================================================ */ -/* src/config-win32.h - Hand crafted config file for windows */ -/* ================================================================ */ - -/* ---------------------------------------------------------------- */ -/* HEADER FILES */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the <fcntl.h> header file. */ -#define HAVE_FCNTL_H 1 - -/* Define if you have the <io.h> header file. */ -#define HAVE_IO_H 1 - -/* Define if you have the <limits.h> header file. */ -#define HAVE_LIMITS_H 1 - -/* Define if you have the <locale.h> header file. */ -#define HAVE_LOCALE_H 1 - -/* Define if you need the malloc.h header file even with stdlib.h */ -#if !defined(__SALFORDC__) && !defined(__POCC__) -#define NEED_MALLOC_H 1 -#endif - -/* Define if you have the <signal.h> header file. */ -#define HAVE_SIGNAL_H 1 - -/* Define if you have the <stdlib.h> header file. */ -#define HAVE_STDLIB_H 1 - -/* Define if you have the <sys/time.h> header file */ -/* #define HAVE_SYS_TIME_H 1 */ - -/* Define if you have the <sys/types.h> header file. */ -#define HAVE_SYS_TYPES_H 1 - -/* Define if you have the <sys/utime.h> header file. */ -#ifndef __BORLANDC__ -#define HAVE_SYS_UTIME_H 1 -#endif - -/* Define if you have the <time.h> header file. */ -#define HAVE_TIME_H 1 - -/* Define if you have the <unistd.h> header file. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \ - defined(__POCC__) -#define HAVE_UNISTD_H 1 -#endif - -/* Define if you have the <windows.h> header file. */ -#define HAVE_WINDOWS_H 1 - -/* Define if you have the <winsock.h> header file. */ -#define HAVE_WINSOCK_H 1 - -/* Define if you have the <winsock2.h> header file. */ -#ifndef __SALFORDC__ -#define HAVE_WINSOCK2_H 1 -#endif - -/* Define if you have the <ws2tcpip.h> header file. */ -#ifndef __SALFORDC__ -#define HAVE_WS2TCPIP_H 1 -#endif - -/* ---------------------------------------------------------------- */ -/* OTHER HEADER INFO */ -/* ---------------------------------------------------------------- */ - -/* Define if sig_atomic_t is an available typedef. */ -#define HAVE_SIG_ATOMIC_T 1 - -/* Define if you have the ANSI C header files. */ -#define STDC_HEADERS 1 - -/* Define if you can safely include both <sys/time.h> and <time.h>. */ -/* #define TIME_WITH_SYS_TIME 1 */ - -/* ---------------------------------------------------------------- */ -/* FUNCTIONS */ -/* ---------------------------------------------------------------- */ - -/* Define if you have the ftruncate function. */ -#define HAVE_FTRUNCATE 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 setlocale function. */ -#define HAVE_SETLOCALE 1 - -/* Define if you have the setmode function. */ -#define HAVE_SETMODE 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 strncasecmp function. */ -/* #define HAVE_STRNCASECMP 1 */ - -/* Define if you have the strnicmp function. */ -#define HAVE_STRNICMP 1 - -/* Define if you have the utime function */ -#ifndef __BORLANDC__ -#define HAVE_UTIME 1 -#endif - -/* 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 recvfrom function. */ -#define HAVE_RECVFROM 1 - -/* Define to the type of arg 1 for recvfrom. */ -#define RECVFROM_TYPE_ARG1 SOCKET - -/* Define to the type pointed by arg 2 for recvfrom. */ -#define RECVFROM_TYPE_ARG2 char - -/* Define to the type of arg 3 for recvfrom. */ -#define RECVFROM_TYPE_ARG3 int - -/* Define to the type of arg 4 for recvfrom. */ -#define RECVFROM_TYPE_ARG4 int - -/* Define to the type pointed by arg 5 for recvfrom. */ -#define RECVFROM_TYPE_ARG5 struct sockaddr - -/* Define to the type pointed by arg 6 for recvfrom. */ -#define RECVFROM_TYPE_ARG6 int - -/* Define to the function return type for recvfrom. */ -#define RECVFROM_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 as the return type of signal handlers (int or void). */ -#define RETSIGTYPE void - -/* Define ssize_t if it is not an available 'typedefed' type */ -#ifndef _SSIZE_T_DEFINED -# if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \ - defined(__POCC__) || \ - 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 */ -/* ---------------------------------------------------------------- */ - -/* The size of `int', as computed by sizeof. */ -#define SIZEOF_INT 4 - -/* The size of `long double', as computed by sizeof. */ -#define SIZEOF_LONG_DOUBLE 16 - -/* The size of `long long', as computed by sizeof. */ -/* #define SIZEOF_LONG_LONG 8 */ - -/* The size of `short', as computed by sizeof. */ -#define SIZEOF_SHORT 2 - -/* ---------------------------------------------------------------- */ -/* STRUCT RELATED */ -/* ---------------------------------------------------------------- */ - -/* Define this if you have struct sockaddr_storage */ -#if !defined(__SALFORDC__) && !defined(__BORLANDC__) -#define HAVE_STRUCT_SOCKADDR_STORAGE 1 -#endif - -/* 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 - -/* ---------------------------------------------------------------- */ -/* Watt-32 tcp/ip SPECIFIC */ -/* ---------------------------------------------------------------- */ - -#ifdef USE_WATT32 - #include <tcp.h> - #undef byte - #undef word - #undef USE_WINSOCK - #undef HAVE_WINSOCK_H - #undef HAVE_WINSOCK2_H - #undef HAVE_WS2TCPIP_H - #define HAVE_GETADDRINFO - #define HAVE_GETNAMEINFO - #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 HAVE_FREEADDRINFO - #define SOCKET int -#endif - - -/* ---------------------------------------------------------------- */ -/* COMPILER SPECIFIC */ -/* ---------------------------------------------------------------- */ - -/* Undef keyword 'const' if it does not work. */ -/* #undef const */ - -/* Windows should not have HAVE_GMTIME_R defined */ -/* #undef HAVE_GMTIME_R */ - -/* Define if the compiler supports C99 variadic macro style. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1400) -#define HAVE_VARIADIC_MACROS_C99 1 -#endif - -/* Define if the compiler supports the 'long long' data type. */ -#if defined(__MINGW32__) || defined(__WATCOMC__) -#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 - -/* VS2005 and later dafault 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 - -/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows - 2000 as a supported build target. VS2008 default installations provide 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 using - Windows SDK versions 6.X and Windows 2000 as a build target are - functional */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_MINIMUM_TARGET 0x0500 -#endif - -/* When no build target is specified VS2008 default build target is Windows - Vista, which leaves out even Winsows XP. If no build target has been given - for VS2008 we will target the minimum Officially supported build target, - which happens to be Windows XP. */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -# define VS2008_DEFAULT_TARGET 0x0501 -#endif - -/* VS2008 default target settings and minimum build target check */ -#if defined(_MSC_VER) && (_MSC_VER >= 1500) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT VS2008_DEFAULT_TARGET -# endif -# ifndef WINVER -# define WINVER VS2008_DEFAULT_TARGET -# endif -# if (_WIN32_WINNT < VS2008_MINIMUM_TARGET) || \ - (WINVER < VS2008_MINIMUM_TARGET) -# error VS2008 does not support Windows build targets prior to Windows 2000 -# endif -#endif - -/* When no build target is specified Pelles C 5.00 and later default build - target is Windows Vista. We override default target to be Windows 2000. */ -#if defined(__POCC__) && (__POCC__ >= 500) -# ifndef _WIN32_WINNT -# define _WIN32_WINNT 0x0500 -# endif -# ifndef WINVER -# define WINVER 0x0500 -# endif -#endif - -/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is - quite convoluted, compiler dependent and even build target dependent. */ -#if defined(HAVE_WS2TCPIP_H) -# if defined(__POCC__) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# elif defined(_MSC_VER) && (_MSC_VER >= 1200) -# define HAVE_FREEADDRINFO 1 -# define HAVE_GETADDRINFO 1 -# define HAVE_GETADDRINFO_THREADSAFE 1 -# define HAVE_GETNAMEINFO 1 -# endif -#endif - -#if defined(__POCC__) -# ifndef _MSC_VER -# error Microsoft extensions /Ze compiler option is required -# endif -# ifndef __POCC__OLDNAMES -# error Compatibility names /Go compiler option is required -# 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(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES) -# define USE_WIN32_LARGE_FILES -#endif - -#if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES) -# define USE_WIN32_LARGE_FILES -#endif - -#if defined(__POCC__) -# undef USE_WIN32_LARGE_FILES -#endif - -#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES) -# define USE_WIN32_SMALL_FILES -#endif - -/* ---------------------------------------------------------------- */ -/* ADDITIONAL DEFINITIONS */ -/* ---------------------------------------------------------------- */ - -/* Define cpu-machine-OS */ -#ifndef OS -#define OS "i386-pc-win32" -#endif - -/* Define to 1 if you want the built-in manual */ -#define USE_MANUAL 1 - -#if defined(__POCC__) -# define ENABLE_IPV6 1 -#endif - -#endif /* __SRC_CONFIG_WIN32_H */ diff --git a/src/curl.rc b/src/curl.rc index 58e439d3b..3db59bd3c 100644 --- a/src/curl.rc +++ b/src/curl.rc @@ -20,7 +20,7 @@ * ***************************************************************************/ #include <winver.h> -#include "version.h" +#include "tool_version.h" LANGUAGE 0x09,0x01 diff --git a/src/hugehelp.c.cvs b/src/hugehelp.c.cvs index ac9f0ff87..1eb2fa537 100644 --- a/src/hugehelp.c.cvs +++ b/src/hugehelp.c.cvs @@ -1,4 +1,5 @@ -#include <stdio.h> +#include "setup.h" +#include "hugehelp.h" void hugehelp(void) { puts ( "This is a silly replacement for the actual file."); diff --git a/src/hugehelp.h b/src/hugehelp.h index b84be17f5..842836dda 100644 --- a/src/hugehelp.h +++ b/src/hugehelp.h @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,8 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" + void hugehelp(void); #endif /* HEADER_CURL_HUGEHELP_H */ diff --git a/src/main.c b/src/main.c deleted file mode 100644 index 463996444..000000000 --- a/src/main.c +++ /dev/null @@ -1,6207 +0,0 @@ -/*************************************************************************** - * _ _ ____ _ - * Project ___| | | | _ \| | - * / __| | | | |_) | | - * | (__| |_| | _ <| |___ - * \___|\___/|_| \_\_____| - * - * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. - * - * This software is licensed as described in the file COPYING, which - * you should have received as part of this distribution. The terms - * are also available at http://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. - * - ***************************************************************************/ -#include "setup.h" - -#include <curl/curl.h> - -/* -** system headers -*/ - -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <stdarg.h> -#include <sys/types.h> -#include <sys/stat.h> -#include <ctype.h> -#include <errno.h> - -#if defined(MSDOS) || defined(WIN32) -# if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) -# include <libgen.h> -# endif -#endif - -#ifdef NETWARE -# ifdef __NOVELL_LIBC__ -# include <screen.h> -# else -# include <nwconio.h> -# define mkdir mkdir_510 -# endif -#endif - -#ifdef HAVE_IO_H -# include <io.h> -#endif - -#ifdef HAVE_UNISTD_H -# include <unistd.h> -#endif - -#ifdef HAVE_FCNTL_H -# include <fcntl.h> -#endif - -#ifdef HAVE_UTIME_H -# include <utime.h> -#elif defined(HAVE_SYS_UTIME_H) -# include <sys/utime.h> -#endif - -#ifdef HAVE_LIMITS_H -# include <limits.h> -#endif - -#ifdef HAVE_SYS_POLL_H -# include <sys/poll.h> -#elif defined(HAVE_POLL_H) -# include <poll.h> -#endif - -#ifdef HAVE_LOCALE_H -# include <locale.h> -#endif - -#ifdef HAVE_NETINET_IN_H -# include <netinet/in.h> -#endif - -#ifdef HAVE_NETINET_TCP_H -# include <netinet/tcp.h> -#endif - -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) -# include <iconv.h> -/* set default codesets for iconv */ -# ifndef CURL_ICONV_CODESET_OF_NETWORK -# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" -# endif -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ - -#ifdef MSDOS -# include <dos.h> -#endif - -#if defined(USE_WIN32_LARGE_FILES) || defined(USE_WIN32_SMALL_FILES) -# include <io.h> -# include <sys/types.h> -# include <sys/stat.h> -#endif - -#ifdef WIN32 -# include <direct.h> -#endif - -/* -** src subdirectory headers -*/ - -#include "urlglob.h" -#include "writeout.h" -#include "getpass.h" -#include "homedir.h" -#include "curlutil.h" -#include "os-specific.h" -#include "version.h" -#include "xattr.h" -#ifdef USE_MANUAL -# include "hugehelp.h" -#endif -#ifdef USE_ENVIRONMENT -# include "writeenv.h" -#endif - -/* -** libcurl subdirectory headers -*/ - -#include "rawstr.h" - -#define ENABLE_CURLX_PRINTF -/* make the curlx header define all printf() functions to use the curlx_* - versions instead */ -#include "curlx.h" - -/* The last #include file should be: */ -#ifdef CURLDEBUG -#ifndef CURLTOOLDEBUG -#define MEMDEBUG_NODEFINES -#endif -/* This is low-level hard-hacking memory leak tracking and similar. Using - the library level code from this client-side is ugly, but we do this - anyway for convenience. */ -#include "memdebug.h" -#endif - -#ifdef __VMS -static int vms_show = 0; -#endif - -#if defined(NETWARE) -#define PRINT_LINES_PAUSE 23 -#endif - -#if defined(__SYMBIAN32__) -#define PRINT_LINES_PAUSE 16 -#define pressanykey() getchar() -#endif - -#define DEFAULT_MAXREDIRS 50L - -#if defined(O_BINARY) && defined(HAVE_SETMODE) -#ifdef __HIGHC__ -#define SET_BINMODE(file) _setmode(file,O_BINARY) -#else -#define SET_BINMODE(file) setmode(fileno(file),O_BINARY) -#endif -#else -#define SET_BINMODE(file) ((void)0) -#endif - -#ifndef O_BINARY -/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in - source code but yet it doesn't ruin anything */ -#define O_BINARY 0 -#endif - -#if defined(MSDOS) || defined(WIN32) - -static const char *msdosify(const char *); -static char *rename_if_dos_device_name(char *); -static char *sanitize_dos_name(char *); - -#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 */ -#endif - -#endif /* MSDOS || WIN32 */ - -#ifdef MSDOS -#define USE_WATT32 -#ifdef DJGPP -/* we want to glob our own argv[] */ -char **__crt0_glob_function (char *arg) -{ - (void)arg; - return (char**)0; -} -#endif /* __DJGPP__ */ -#endif /* MSDOS */ - -#ifndef STDIN_FILENO -#define STDIN_FILENO fileno(stdin) -#endif - -#ifndef STDOUT_FILENO -#define STDOUT_FILENO fileno(stdout) -#endif - -#ifndef STDERR_FILENO -#define STDERR_FILENO fileno(stderr) -#endif - -#define CURLseparator "--_curl_--" - -#define CURL_PROGRESS_STATS 0 /* default progress display */ -#define CURL_PROGRESS_BAR 1 - -typedef enum { - HTTPREQ_UNSPEC, - HTTPREQ_GET, - HTTPREQ_HEAD, - HTTPREQ_POST, - HTTPREQ_SIMPLEPOST, - HTTPREQ_CUSTOM, - HTTPREQ_LAST -} HttpReq; - -/* - * Large file support (>2Gb) using WIN32 functions. - */ - -#ifdef USE_WIN32_LARGE_FILES -# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) -# define fstat(fdes,stp) _fstati64(fdes, stp) -# define stat(fname,stp) _stati64(fname, stp) -# define struct_stat struct _stati64 -# define LSEEK_ERROR (__int64)-1 -#endif - -/* - * Small file support (<2Gb) using WIN32 functions. - */ - -#ifdef USE_WIN32_SMALL_FILES -# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) -# define fstat(fdes,stp) _fstat(fdes, stp) -# define stat(fname,stp) _stat(fname, stp) -# define struct_stat struct _stat -# 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 - -#ifdef WIN32 -# define mkdir(x,y) (mkdir)(x) -# undef PATH_MAX -# define PATH_MAX MAX_PATH -# ifndef __POCC__ -# define F_OK 0 -# endif -#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 -# elif defined(TPF) -# define SIZEOF_OFF_T 8 -# endif -# ifndef SIZEOF_OFF_T -# define SIZEOF_OFF_T 4 -# endif -#endif - -#define CURL_CA_CERT_ERRORMSG1 \ - "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \ - "curl performs SSL certificate verification by default, " \ - "using a \"bundle\"\n" \ - " of Certificate Authority (CA) public keys (CA certs). If the default\n" \ - " bundle file isn't adequate, you can specify an alternate file\n" \ - " using the --cacert option.\n" - -#define CURL_CA_CERT_ERRORMSG2 \ - "If this HTTPS server uses a certificate signed by a CA represented in\n" \ - " the bundle, the certificate verification probably failed due to a\n" \ - " problem with the certificate (it might be expired, or the name might\n" \ - " not match the domain name in the URL).\n" \ - "If you'd like to turn off curl's verification of the certificate, use\n" \ - " the -k (or --insecure) option.\n" - -#ifdef CURL_DOES_CONVERSIONS -#ifdef HAVE_ICONV -iconv_t inbound_cd = (iconv_t)-1; -iconv_t outbound_cd = (iconv_t)-1; - -/* - * convert_to_network() is an internal function to convert - * from the host encoding to ASCII on non-ASCII platforms. - */ -static CURLcode -convert_to_network(char *buffer, size_t length) -{ - CURLcode rc; - - /* translate from the host encoding to the network encoding */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes; - - /* open an iconv conversion descriptor if necessary */ - if(outbound_cd == (iconv_t)-1) { - outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, - CURL_ICONV_CODESET_OF_HOST); - if(outbound_cd == (iconv_t)-1) { - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(outbound_cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((rc == -1) || (in_bytes != 0)) { - return CURLE_CONV_FAILED; - } - - return CURLE_OK; -} - -/* - * convert_from_network() is an internal function - * for performing ASCII conversions on non-ASCII platforms. - */ -static CURLcode -convert_from_network(char *buffer, size_t length) -{ - CURLcode rc; - - /* translate from the network encoding to the host encoding */ - char *input_ptr, *output_ptr; - size_t in_bytes, out_bytes; - - /* open an iconv conversion descriptor if necessary */ - if(inbound_cd == (iconv_t)-1) { - inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, - CURL_ICONV_CODESET_OF_NETWORK); - if(inbound_cd == (iconv_t)-1) { - return CURLE_CONV_FAILED; - } - } - /* call iconv */ - input_ptr = output_ptr = buffer; - in_bytes = out_bytes = length; - rc = iconv(inbound_cd, &input_ptr, &in_bytes, - &output_ptr, &out_bytes); - if((rc == -1) || (in_bytes != 0)) { - return CURLE_CONV_FAILED; - } - - return CURLE_OK; -} -#endif /* HAVE_ICONV */ - -static -char convert_char(curl_infotype infotype, char this_char) -{ -/* determine how this specific character should be displayed */ - switch(infotype) { - case CURLINFO_DATA_IN: - case CURLINFO_DATA_OUT: - case CURLINFO_SSL_DATA_IN: - case CURLINFO_SSL_DATA_OUT: - /* data, treat as ASCII */ - if((this_char >= 0x20) && (this_char < 0x7f)) { - /* printable ASCII hex value: convert to host encoding */ - convert_from_network(&this_char, 1); - } - else { - /* non-printable ASCII, use a replacement character */ - return UNPRINTABLE_CHAR; - } - /* fall through to default */ - default: - /* treat as host encoding */ - if(ISPRINT(this_char) - && (this_char != '\t') - && (this_char != '\r') - && (this_char != '\n')) { - /* printable characters excluding tabs and line end characters */ - return this_char; - } - break; - } - /* non-printable, use a replacement character */ - return UNPRINTABLE_CHAR; -} -#endif /* CURL_DOES_CONVERSIONS */ - -#ifdef WIN32 - -#ifdef __BORLANDC__ -/* 64-bit lseek-like function unavailable */ -# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) -#endif - -#ifdef __POCC__ -# if(__POCC__ < 450) -/* 64-bit lseek-like function unavailable */ -# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence) -# else -# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence) -# endif -#endif - -#ifndef HAVE_FTRUNCATE -#define HAVE_FTRUNCATE 1 -#endif - -/* - * Truncate a file handle at a 64-bit position 'where'. - */ - -static int ftruncate64(int fd, curl_off_t where) -{ - if(_lseeki64(fd, where, SEEK_SET) < 0) - return -1; - - if(!SetEndOfFile((HANDLE)_get_osfhandle(fd))) - return -1; - - return 0; -} -#define ftruncate(fd,where) ftruncate64(fd,where) - -#endif /* WIN32 */ - -typedef enum { - TRACE_NONE, /* no trace/verbose output at all! */ - TRACE_BIN, /* tcpdump inspired look */ - TRACE_ASCII, /* like *BIN but without the hex output */ - TRACE_PLAIN /* -v/--verbose type */ -} trace; - -struct OutStruct { - char *filename; - FILE *stream; - struct Configurable *config; - curl_off_t bytes; /* amount written so far */ - curl_off_t init; /* original size (non-zero when appending) */ -}; - -struct Configurable { - CURL *easy; /* once we have one, we keep it here */ - bool remote_time; - char *random_file; - char *egd_file; - char *useragent; - char *cookie; /* single line with specified cookies */ - char *cookiejar; /* write to this file */ - char *cookiefile; /* read from this file */ - bool cookiesession; /* new session? */ - bool encoding; /* Accept-Encoding please */ - bool tr_encoding; /* Transfer-Encoding please */ - long authtype; /* auth bitmask */ - bool use_resume; - bool resume_from_current; - bool disable_epsv; - bool disable_eprt; - bool ftp_pret; - long proto; - bool proto_present; - long proto_redir; - bool proto_redir_present; - curl_off_t resume_from; - char *postfields; - curl_off_t postfieldsize; - char *referer; - long timeout; - long connecttimeout; - long maxredirs; - curl_off_t max_filesize; - char *headerfile; - char *ftpport; - char *iface; - int localport; - int localportrange; - unsigned short porttouse; - char *range; - long low_speed_limit; - long low_speed_time; - bool showerror; - char *userpwd; - char *tls_username; - char *tls_password; - char *tls_authtype; - char *proxyuserpwd; - char *proxy; - int proxyver; /* set to CURLPROXY_HTTP* define */ - char *noproxy; - char *mail_from; - struct curl_slist *mail_rcpt; - bool proxytunnel; - bool ftp_append; /* APPE on ftp */ - bool mute; /* shutup */ - bool use_ascii; /* select ascii or text transfer */ - bool autoreferer; /* automatically set referer */ - bool failonerror; /* fail on (HTTP) errors */ - bool include_headers; /* send 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 ocations, even when hostname - changed */ - bool netrc_opt; - bool netrc; - char *netrc_file; - bool noprogress; - bool isatty; /* updated internally only if the output is a tty */ - 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 */ - char *cipher_list; - char *cert; - char *cert_type; - char *cacert; - char *capath; - char *crlfile; - char *key; - char *key_type; - char *key_passwd; - char *pubkey; - char *hostpubmd5; - char *engine; - bool list_engines; - bool crlf; - char *customrequest; - char *krblevel; - char *trace_dump; /* file to dump the network trace to, or NULL */ - FILE *trace_stream; - bool trace_fopened; - trace tracetype; - bool tracetime; /* include timestamp? */ - long httpversion; - int progressmode; - 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 create_dirs; - bool ftp_create_dirs; - bool ftp_skip_ip; - bool proxynegotiate; - bool proxyntlm; - bool proxydigest; - bool proxybasic; - bool proxyanyauth; - char *writeout; /* %-styled format string to output */ - bool writeenv; /* write results to environment, if available */ - FILE *errors; /* if stderr redirect is requested */ - bool errors_fopened; - struct curl_slist *quote; - struct curl_slist *postquote; - struct curl_slist *prequote; - long ssl_version; - long ip_version; - curl_TimeCond timecond; - time_t condtime; - struct curl_slist *headers; - struct curl_httppost *httppost; - struct curl_httppost *last_post; - struct curl_slist *telnet_options; - struct curl_slist *resolve; - 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 *socksproxy; /* set to server string */ - int socksver; /* set to CURLPROXY_SOCKS* define */ - char *socks5_gssapi_service; /* set service name for gssapi principal - * default rcmd */ - int socks5_gssapi_nec ; /* The NEC reference server does not protect - * the encryption type exchange */ - - bool tcp_nodelay; - long req_retry; /* number of retries */ - 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 tftp_blksize; /* TFTP BLKSIZE option */ - bool ignorecl; /* --ignore-content-length */ - bool disable_sessionid; - - char *libcurl; /* output libcurl code to this file name */ - bool raw; - bool post301; - bool post302; - 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 */ - struct OutStruct *outs; - bool xattr; /* store metadata in extended attributes */ -}; - -#define WARN_PREFIX "Warning: " -#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX)) -/* produce this text message to the user unless mute was selected */ -static void warnf(struct Configurable *config, const char *fmt, ...) -{ - if(!config->mute) { - va_list ap; - int len; - char *ptr; - char print_buffer[256]; - - va_start(ap, fmt); - len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); - va_end(ap); - - ptr = print_buffer; - while(len > 0) { - fputs(WARN_PREFIX, config->errors); - - if(len > (int)WARN_TEXTWIDTH) { - int cut = WARN_TEXTWIDTH-1; - - while(!ISSPACE(ptr[cut]) && cut) { - cut--; - } - if(0 == cut) - /* not a single cutting position was found, just cut it at the - max text width then! */ - cut = WARN_TEXTWIDTH-1; - - (void)fwrite(ptr, cut + 1, 1, config->errors); - fputs("\n", config->errors); - ptr += cut+1; /* skip the space too */ - len -= cut; - } - else { - fputs(ptr, config->errors); - len = 0; - } - } - } -} - -/* - * This is the main global constructor for the app. Call this before - * _any_ libcurl usage. If this fails, *NO* libcurl functions may be - * used, or havoc may be the result. - */ -static CURLcode main_init(void) -{ -#ifdef DJGPP - /* stop stat() wasting time */ - _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; -#endif - - return curl_global_init(CURL_GLOBAL_DEFAULT); -} - -/* - * This is the main global destructor for the app. Call this after - * _all_ libcurl usage is done. - */ -static void main_free(void) -{ - curl_global_cleanup(); -#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV) - /* close iconv conversion descriptor */ - if(inbound_cd != (iconv_t)-1) - iconv_close(inbound_cd); - if(outbound_cd != (iconv_t)-1) - iconv_close(outbound_cd); -#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */ -} - -static int SetHTTPrequest(struct Configurable *config, - HttpReq req, HttpReq *store) -{ - if((*store == HTTPREQ_UNSPEC) || - (*store == req)) { - *store = req; - return 0; - } - warnf(config, "You can only select one HTTP request!\n"); - return 1; -} - -static void helpf(FILE *errors, const char *fmt, ...) -{ - va_list ap; - if(fmt) { - va_start(ap, fmt); - fputs("curl: ", errors); /* prefix it */ - vfprintf(errors, fmt, ap); - va_end(ap); - } - fprintf(errors, "curl: try 'curl --help' " -#ifdef USE_MANUAL - "or 'curl --manual' " -#endif - "for more information\n"); -} - -/* - * A chain of these nodes contain URL to get and where to put the URL's - * contents. - */ -struct getout { - struct getout *next; /* next one */ - char *url; /* the URL we deal with */ - char *outfile; /* where to store the output */ - char *infile; /* file to upload, if GETOUT_UPLOAD is set */ - int flags; /* options */ -}; -#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */ -#define GETOUT_URL (1<<1) /* set when URL is deemed done */ -#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */ -#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */ -#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */ - -static void help(void) -{ - int i; - /* A few of these source lines are >80 columns wide, but that's only because - breaking the strings narrower makes this chunk look even worse! - - Starting with 7.18.0, this list of command line options is sorted based - on the long option name. It is not done automatically, although a command - line like the following can help out: - - curl --help | cut -c5- | grep "^-" | sort - */ - static const char * const helptext[]={ - "Usage: curl [options...] <url>", - "Options: (H) means HTTP/HTTPS only, (F) means FTP only", - " --anyauth Pick \"any\" authentication method (H)", - " -a/--append Append to target file when uploading (F/SFTP)", - " --basic Use HTTP Basic Authentication (H)", - " --cacert <file> CA certificate to verify peer against (SSL)", - " --capath <directory> CA directory to verify peer against (SSL)", - " -E/--cert <cert[:passwd]> Client certificate file and password (SSL)", - " --cert-type <type> Certificate file type (DER/PEM/ENG) (SSL)", - " --ciphers <list> SSL ciphers to use (SSL)", - " --compressed Request compressed response (using deflate or gzip)", - " -K/--config <file> Specify which config file to read", - " --connect-timeout <seconds> Maximum time allowed for connection", - " -C/--continue-at <offset> Resumed transfer offset", - " -b/--cookie <name=string/file> String or file to read cookies from (H)", - " -c/--cookie-jar <file> Write cookies to this file after operation (H)", - " --create-dirs Create necessary local directory hierarchy", - " --crlf Convert LF to CRLF in upload", - " --crlfile <file> Get a CRL list in PEM format from the given file", - " -d/--data <data> HTTP POST data (H)", - " --data-ascii <data> HTTP POST ASCII data (H)", - " --data-binary <data> HTTP POST binary data (H)", - " --data-urlencode <name=data/name@filename> " - "HTTP POST data url encoded (H)", - " --digest Use HTTP Digest Authentication (H)", - " --disable-eprt Inhibit using EPRT or LPRT (F)", - " --disable-epsv Inhibit using EPSV (F)", - " -D/--dump-header <file> Write the headers to this file", - " --egd-file <file> EGD socket path for random data (SSL)", - " --engine <eng> Crypto engine (SSL). \"--engine list\" for list", -#ifdef USE_ENVIRONMENT - " --environment Write results to environment variables (RISC OS)", -#endif - " -f/--fail Fail silently (no output at all) on HTTP errors (H)", - " -F/--form <name=content> Specify HTTP multipart POST data (H)", - " --form-string <name=string> Specify HTTP multipart POST data (H)", - " --ftp-account <data> Account data string (F)", - " --ftp-alternative-to-user <cmd> " - "String to replace \"USER [name]\" (F)", - " --ftp-create-dirs Create the remote dirs if not present (F)", - " --ftp-method [multicwd/nocwd/singlecwd] Control CWD usage (F)", - " --ftp-pasv Use PASV/EPSV instead of PORT (F)", - " -P/--ftp-port <address> Use PORT with address instead of PASV (F)", - " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n" - " --ftp-pret Send PRET before PASV (for drftpd) (F)", - " --ftp-ssl-ccc Send CCC after authenticating (F)", - " --ftp-ssl-ccc-mode [active/passive] Set CCC mode (F)", - " --ftp-ssl-control Require SSL/TLS for ftp login, " - "clear for transfer (F)", - " -G/--get Send the -d data with a HTTP GET (H)", - " -g/--globoff Disable URL sequences and ranges using {} and []", - " -H/--header <line> Custom header to pass to server (H)", - " -I/--head Show document info only", - " -h/--help This help text", - " --hostpubmd5 <md5> " - "Hex encoded MD5 string of the host public key. (SSH)", - " -0/--http1.0 Use HTTP 1.0 (H)", - " --ignore-content-length Ignore the HTTP Content-Length header", - " -i/--include Include protocol headers in the output (H/F)", - " -k/--insecure Allow connections to SSL sites without certs (H)", - " --interface <interface> Specify network interface/address to use", - " -4/--ipv4 Resolve name to IPv4 address", - " -6/--ipv6 Resolve name to IPv6 address", - " -j/--junk-session-cookies Ignore session cookies read from file (H)", - " --keepalive-time <seconds> Interval between keepalive probes", - " --key <key> Private key file name (SSL/SSH)", - " --key-type <type> Private key file type (DER/PEM/ENG) (SSL)", - " --krb <level> Enable Kerberos with specified security level (F)", - " --libcurl <file> Dump libcurl equivalent code of this command line", - " --limit-rate <rate> Limit transfer speed to this rate", - " -J/--remote-header-name Use the header-provided filename (H)", - " -l/--list-only List only names of an FTP directory (F)", - " --local-port <num>[-num] Force use of these local port numbers", - " -L/--location Follow Location: hints (H)", - " --location-trusted Follow Location: and send auth to other hosts (H)", - " -M/--manual Display the full manual", - " --mail-from <from> Mail from this address", - " --mail-rcpt <to> Mail to this receiver(s)", - " --max-filesize <bytes> Maximum file size to download (H/F)", - " --max-redirs <num> Maximum number of redirects allowed (H)", - " -m/--max-time <seconds> Maximum time allowed for the transfer", - " --negotiate Use HTTP Negotiate Authentication (H)", - " -n/--netrc Must read .netrc for user name and password", - " --netrc-optional Use either .netrc or URL; overrides -n", - " --netrc-file <file> Set up the netrc filename to use", - " -N/--no-buffer Disable buffering of the output stream", - " --no-keepalive Disable keepalive use on the connection", - " --no-sessionid Disable SSL session-ID reusing (SSL)", - " --noproxy Comma-separated list of hosts which do not use proxy", - " --ntlm Use HTTP NTLM authentication (H)", - " -o/--output <file> Write output to <file> instead of stdout", - " --pass <pass> Pass phrase for the private key (SSL/SSH)", - " --post301 " - "Do not switch to GET after following a 301 redirect (H)", - " --post302 " - "Do not switch to GET after following a 302 redirect (H)", - " -#/--progress-bar Display transfer progress as a progress bar", - " --proto <protocols> Enable/disable specified protocols", - " --proto-redir <protocols> " - "Enable/disable specified protocols on redirect", - " -x/--proxy <host[:port]> Use HTTP proxy on given port", - " --proxy-anyauth Pick \"any\" proxy authentication method (H)", - " --proxy-basic Use Basic authentication on the proxy (H)", - " --proxy-digest Use Digest authentication on the proxy (H)", - " --proxy-negotiate Use Negotiate authentication on the proxy (H)", - " --proxy-ntlm Use NTLM authentication on the proxy (H)", - " -U/--proxy-user <user[:password]> Set proxy user and password", - " --proxy1.0 <host[:port]> Use HTTP/1.0 proxy on given port", - " -p/--proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)", - " --pubkey <key> Public key file name (SSH)", - " -Q/--quote <cmd> Send command(s) to server before transfer (F/SFTP)", - " --random-file <file> File for reading random data from (SSL)", - " -r/--range <range> Retrieve only the bytes within a range", - " --raw Pass HTTP \"raw\", without any transfer decoding (H)", - " -e/--referer Referer URL (H)", - " -O/--remote-name Write output to a file named as the remote file", - " --remote-name-all Use the remote file name for all URLs", - " -R/--remote-time Set the remote file's time on the local output", - " -X/--request <command> Specify request command to use", - " --resolve <host:port:address> Force resolve of HOST:PORT to ADDRESS", - " --retry <num> " - "Retry request <num> times if transient problems occur", - " --retry-delay <seconds> " - "When retrying, wait this many seconds between each", - " --retry-max-time <seconds> Retry only within this period", - " -S/--show-error " - "Show error. With -s, make curl show errors when they occur", - " -s/--silent Silent mode. Don't output anything", - " --socks4 <host[:port]> SOCKS4 proxy on given host + port", - " --socks4a <host[:port]> SOCKS4a proxy on given host + port", - " --socks5 <host[:port]> SOCKS5 proxy on given host + port", - " --socks5-hostname <host[:port]> " - "SOCKS5 proxy, pass host name to proxy", -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - " --socks5-gssapi-service <name> SOCKS5 proxy service name for gssapi", - " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server", -#endif - " -Y/--speed-limit " - "Stop transfer if below speed-limit for 'speed-time' secs", - " -y/--speed-time " - "Time needed to trig speed-limit abort. Defaults to 30", - " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)", - " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)", - " -2/--sslv2 Use SSLv2 (SSL)", - " -3/--sslv3 Use SSLv3 (SSL)", - " --stderr <file> Where to redirect stderr. - means stdout", - " --tcp-nodelay Use the TCP_NODELAY option", - " -t/--telnet-option <OPT=val> Set telnet option", - " --tftp-blksize <value> Set TFTP BLKSIZE option (must be >512)", - " -z/--time-cond <time> Transfer based on a time condition", - " -1/--tlsv1 Use TLSv1 (SSL)", - " --trace <file> Write a debug trace to the given file", - " --trace-ascii <file> Like --trace but without the hex output", - " --trace-time Add time stamps to trace/verbose output", - " --tr-encoding Request compressed transfer encoding (H)", - " -T/--upload-file <file> Transfer <file> to remote site", - " --url <URL> Set URL to work with", - " -B/--use-ascii Use ASCII/text transfer", - " -u/--user <user[:password]> Set server user and password", - " --tlsuser <user> Set TLS username", - " --tlspassword <string> Set TLS password", - " --tlsauthtype <string> Set TLS authentication type (default SRP)", - " -A/--user-agent <string> User-Agent to send to server (H)", - " -v/--verbose Make the operation more talkative", - " -V/--version Show version number and quit", - -#ifdef USE_WATT32 - " --wdebug Turn on Watt-32 debugging", -#endif - " -w/--write-out <format> What to output after completion", - " --xattr Store metadata in extended file attributes", - " -q If used as the first parameter disables .curlrc", - NULL - }; - for(i=0; helptext[i]; i++) { - puts(helptext[i]); -#ifdef PRINT_LINES_PAUSE - if(i && ((i % PRINT_LINES_PAUSE) == 0)) - pressanykey(); -#endif - } -} - -struct LongShort { - const char *letter; - const char *lname; - bool extraparam; -}; - -/* global variable to hold info about libcurl */ -static curl_version_info_data *curlinfo; - -static int parseconfig(const char *filename, - struct Configurable *config); -static char *my_get_line(FILE *fp); -static int create_dir_hierarchy(const char *outfile, FILE *errors); - -static void GetStr(char **string, - const char *value) -{ - if(*string) - free(*string); - if(value) - *string = strdup(value); - else - *string = NULL; -} - -static void clean_getout(struct Configurable *config) -{ - struct getout *node=config->url_list; - struct getout *next; - - while(node) { - next = node->next; - if(node->url) - free(node->url); - if(node->outfile) - free(node->outfile); - if(node->infile) - free(node->infile); - free(node); - - node = next; /* GOTO next */ - } -} - -static struct getout *new_getout(struct Configurable *config) -{ - struct getout *node =malloc(sizeof(struct getout)); - struct getout *last= config->url_last; - if(node) { - /* clear the struct */ - memset(node, 0, sizeof(struct getout)); - - /* append this new node last in the list */ - if(last) - last->next = node; - else - config->url_list = node; /* first node */ - - /* move the last pointer */ - config->url_last = node; - - node->flags = config->default_node_flags; - } - return node; -} - -/* Structure for storing the information needed to build a multiple files - * section - */ -struct multi_files { - struct curl_forms form; - struct multi_files *next; -}; - -/* Add a new list entry possibly with a type_name - */ -static struct multi_files * -AddMultiFiles(const char *file_name, - const char *type_name, - const char *show_filename, - struct multi_files **multi_start, - struct multi_files **multi_current) -{ - struct multi_files *multi; - struct multi_files *multi_type = NULL; - struct multi_files *multi_name = NULL; - multi = malloc(sizeof(struct multi_files)); - if(multi) { - memset(multi, 0, sizeof(struct multi_files)); - multi->form.option = CURLFORM_FILE; - multi->form.value = file_name; - } - else - return NULL; - - if(!*multi_start) - *multi_start = multi; - - if(type_name) { - multi_type = malloc(sizeof(struct multi_files)); - if(multi_type) { - memset(multi_type, 0, sizeof(struct multi_files)); - multi_type->form.option = CURLFORM_CONTENTTYPE; - multi_type->form.value = type_name; - multi->next = multi_type; - - multi = multi_type; - } - else { - free(multi); - return NULL; - } - } - if(show_filename) { - multi_name = malloc(sizeof(struct multi_files)); - if(multi_name) { - memset(multi_name, 0, sizeof(struct multi_files)); - multi_name->form.option = CURLFORM_FILENAME; - multi_name->form.value = show_filename; - multi->next = multi_name; - - multi = multi_name; - } - else { - free(multi); - return NULL; - } - } - - if(*multi_current) - (*multi_current)->next = multi; - - *multi_current = multi; - - return *multi_current; -} - -/* Free the items of the list. - */ -static void FreeMultiInfo(struct multi_files *multi_start) -{ - struct multi_files *multi; - while(multi_start) { - multi = multi_start; - multi_start = multi_start->next; - free(multi); - } -} - -/* Print list of OpenSSL engines supported. - */ -static void list_engines(const struct curl_slist *engines) -{ - puts("Build-time engines:"); - if(!engines) { - puts(" <none>"); - return; - } - for(; engines; engines = engines->next) - printf(" %s\n", engines->data); -} - -/*************************************************************************** - * - * formparse() - * - * Reads a 'name=value' parameter and builds the appropriate linked list. - * - * Specify files to upload with 'name=@filename'. Supports specified - * given Content-Type of the files. Such as ';type=<content-type>'. - * - * 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' - * - * 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' - * - * This function uses curl_formadd to fulfill it's job. Is heavily based on - * the old curl_formparse code. - * - ***************************************************************************/ - -#define FORM_FILE_SEPARATOR ',' -#define FORM_TYPE_SEPARATOR ';' - -static int formparse(struct Configurable *config, - const char *input, - struct curl_httppost **httppost, - struct curl_httppost **last_post, - bool literal_value) -{ - /* nextarg MUST be a string in the format 'name=contents' and we'll - build a linked list with the info */ - char name[256]; - char *contents; - char major[128]; - char minor[128]; - char *contp; - const char *type = NULL; - char *sep; - char *sep2; - - if((1 == sscanf(input, "%255[^=]=", name)) && - ((contp = strchr(input, '=')) != NULL)) { - /* the input was using the correct format */ - - /* Allocate the contents */ - contents = strdup(contp+1); - if(!contents) { - fprintf(config->errors, "out of memory\n"); - return 1; - } - contp = contents; - - if('@' == contp[0] && !literal_value) { - struct multi_files *multi_start = NULL, *multi_current = NULL; - /* we use the @-letter to indicate file name(s) */ - contp++; - - multi_start = multi_current=NULL; - - do { - /* since this was a file, it may have a content-type specifier - at the end too, or a filename. Or both. */ - char *ptr; - char *filename=NULL; - - sep=strchr(contp, FORM_TYPE_SEPARATOR); - sep2=strchr(contp, FORM_FILE_SEPARATOR); - - /* pick the closest */ - if(sep2 && (sep2 < sep)) { - sep = sep2; - - /* no type was specified! */ - } - - type = NULL; - - if(sep) { - - /* if we got here on a comma, don't do much */ - if(FORM_FILE_SEPARATOR == *sep) - ptr = NULL; - else - ptr = sep+1; - - *sep=0; /* terminate file name at separator */ - - while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) { - - /* pass all white spaces */ - while(ISSPACE(*ptr)) - ptr++; - - if(checkprefix("type=", ptr)) { - /* set type pointer */ - type = &ptr[5]; - - /* verify that this is a fine type specifier */ - if(2 != sscanf(type, "%127[^/]/%127[^;,\n]", - major, minor)) { - warnf(config, "Illegally formatted content-type field!\n"); - free(contents); - FreeMultiInfo(multi_start); - return 2; /* illegal content-type syntax! */ - } - - /* now point beyond the content-type specifier */ - sep = (char *)type + strlen(major)+strlen(minor)+1; - - /* there's a semicolon following - we check if it is a filename - specified and if not we simply assume that it is text that - the user wants included in the type and include that too up - to the next zero or semicolon. */ - if((*sep==';') && !checkprefix(";filename=", sep)) { - sep2 = strchr(sep+1, ';'); - if(sep2) - sep = sep2; - else - sep = sep+strlen(sep); /* point to end of string */ - } - - if(*sep) { - *sep=0; /* zero terminate type string */ - - ptr=sep+1; - } - else - ptr = NULL; /* end */ - } - else if(checkprefix("filename=", ptr)) { - filename = &ptr[9]; - ptr=strchr(filename, FORM_TYPE_SEPARATOR); - if(!ptr) { - ptr=strchr(filename, FORM_FILE_SEPARATOR); - } - if(ptr) { - *ptr=0; /* zero terminate */ - ptr++; - } - } - else - /* confusion, bail out of loop */ - break; - } - /* find the following comma */ - if(ptr) - sep=strchr(ptr, FORM_FILE_SEPARATOR); - else - sep=NULL; - } - else { - sep=strchr(contp, FORM_FILE_SEPARATOR); - } - if(sep) { - /* the next file name starts here */ - *sep =0; - sep++; - } - /* if type == NULL curl_formadd takes care of the problem */ - - if(!AddMultiFiles(contp, type, filename, &multi_start, - &multi_current)) { - warnf(config, "Error building form post!\n"); - free(contents); - FreeMultiInfo(multi_start); - return 3; - } - contp = sep; /* move the contents pointer to after the separator */ - - } while(sep && *sep); /* loop if there's another file name */ - - /* now we add the multiple files section */ - if(multi_start) { - struct curl_forms *forms = NULL; - struct multi_files *ptr = multi_start; - unsigned int i, count = 0; - while(ptr) { - ptr = ptr->next; - ++count; - } - forms = malloc((count+1)*sizeof(struct curl_forms)); - if(!forms) { - fprintf(config->errors, "Error building form post!\n"); - free(contents); - FreeMultiInfo(multi_start); - return 4; - } - for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) { - forms[i].option = ptr->form.option; - forms[i].value = ptr->form.value; - } - forms[count].option = CURLFORM_END; - FreeMultiInfo(multi_start); - if(curl_formadd(httppost, last_post, - CURLFORM_COPYNAME, name, - CURLFORM_ARRAY, forms, CURLFORM_END) != 0) { - warnf(config, "curl_formadd failed!\n"); - free(forms); - free(contents); - return 5; - } - free(forms); - } - } - else { - struct curl_forms info[4]; - int i = 0; - char *ct = literal_value? NULL: strstr(contp, ";type="); - - info[i].option = CURLFORM_COPYNAME; - info[i].value = name; - i++; - - if(ct) { - info[i].option = CURLFORM_CONTENTTYPE; - info[i].value = &ct[6]; - i++; - ct[0]=0; /* zero terminate here */ - } - - if(contp[0]=='<' && !literal_value) { - info[i].option = CURLFORM_FILECONTENT; - info[i].value = contp+1; - i++; - info[i].option = CURLFORM_END; - - if(curl_formadd(httppost, last_post, - CURLFORM_ARRAY, info, CURLFORM_END ) != 0) { - warnf(config, "curl_formadd failed, possibly the file %s is bad!\n", - contp+1); - free(contents); - return 6; - } - } - else { -#ifdef CURL_DOES_CONVERSIONS - convert_to_network(contp, strlen(contp)); -#endif - info[i].option = CURLFORM_COPYCONTENTS; - info[i].value = contp; - i++; - info[i].option = CURLFORM_END; - if(curl_formadd(httppost, last_post, - CURLFORM_ARRAY, info, CURLFORM_END) != 0) { - warnf(config, "curl_formadd failed!\n"); - free(contents); - return 7; - } - } - } - - } - else { - warnf(config, "Illegally formatted input field!\n"); - return 1; - } - free(contents); - return 0; -} - - -typedef enum { - PARAM_OK, - PARAM_OPTION_AMBIGUOUS, - PARAM_OPTION_UNKNOWN, - PARAM_REQUIRES_PARAMETER, - PARAM_BAD_USE, - PARAM_HELP_REQUESTED, - PARAM_GOT_EXTRA_PARAMETER, - PARAM_BAD_NUMERIC, - PARAM_LIBCURL_DOESNT_SUPPORT, - PARAM_NO_MEM, - PARAM_LAST -} ParameterError; - -static 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_LIBCURL_DOESNT_SUPPORT: - return "the installed libcurl version doesn't support this"; - case PARAM_NO_MEM: - return "out of memory"; - default: - return "unknown error"; - } -} - -static ParameterError file2string(char **bufp, FILE *file) -{ - char buffer[256]; - char *ptr; - char *string = NULL; - size_t stringlen = 0; - size_t buflen; - - if(file) { - while(fgets(buffer, sizeof(buffer), file)) { - if((ptr = strchr(buffer, '\r')) != NULL) - *ptr = '\0'; - if((ptr = strchr(buffer, '\n')) != NULL) - *ptr = '\0'; - buflen = strlen(buffer); - if((ptr = realloc(string, stringlen+buflen+1)) == NULL) { - if(string) - free(string); - return PARAM_NO_MEM; - } - string = ptr; - strcpy(string+stringlen, buffer); - stringlen += buflen; - } - } - *bufp = string; - return PARAM_OK; -} - -static ParameterError file2memory(char **bufp, size_t *size, FILE *file) -{ - char *newbuf; - char *buffer = NULL; - size_t alloc = 512; - size_t nused = 0; - size_t nread; - - if(file) { - do { - if(!buffer || (alloc == nused)) { - /* size_t overflow detection for huge files */ - if(alloc+1 > ((size_t)-1)/2) { - if(buffer) - free(buffer); - return PARAM_NO_MEM; - } - alloc *= 2; - /* allocate an extra char, reserved space, for null termination */ - if((newbuf = realloc(buffer, alloc+1)) == NULL) { - if(buffer) - free(buffer); - return PARAM_NO_MEM; - } - buffer = newbuf; - } - nread = fread(buffer+nused, 1, alloc-nused, file); - nused += nread; - } while(nread); - /* null terminate the buffer in case it's used as a string later */ - buffer[nused] = '\0'; - /* free trailing slack space, if possible */ - if(alloc != nused) { - if((newbuf = realloc(buffer, nused+1)) != NULL) - buffer = newbuf; - } - /* discard buffer if nothing was read */ - if(!nused) { - free(buffer); - buffer = NULL; /* no string */ - } - } - *size = nused; - *bufp = buffer; - return PARAM_OK; -} - -static void cleanarg(char *str) -{ -#ifdef HAVE_WRITABLE_ARGV - /* 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 - (void)str; -#endif -} - -/* - * Parse the string and write the integer in the given address. Return - * non-zero on failure, zero on success. - * - * The string must start with a digit to be valid. - * - * Since this function gets called with the 'nextarg' pointer from within the - * getparameter a lot, we must check it for NULL before accessing the str - * data. - */ - -static int str2num(long *val, const char *str) -{ - if(str && ISDIGIT(*str)) { - char *endptr; - long num = strtol(str, &endptr, 10); - if((endptr != str) && (endptr == str + strlen(str))) { - *val = num; - return 0; /* Ok */ - } - } - return 1; /* badness */ -} - -/* - * Parse the string and modify the long in the given address. Return - * non-zero on failure, zero on success. - * - * The string is a list of protocols - * - * Since this function gets called with the 'nextarg' pointer from within the - * getparameter a lot, we must check it for NULL before accessing the str - * data. - */ - -static long proto2num(struct Configurable *config, long *val, const char *str) -{ - char *buffer; - const char *sep = ","; - char *token; - - static struct sprotos { - const char *name; - long bit; - } const protos[] = { - { "all", CURLPROTO_ALL }, - { "http", CURLPROTO_HTTP }, - { "https", CURLPROTO_HTTPS }, - { "ftp", CURLPROTO_FTP }, - { "ftps", CURLPROTO_FTPS }, - { "scp", CURLPROTO_SCP }, - { "sftp", CURLPROTO_SFTP }, - { "telnet", CURLPROTO_TELNET }, - { "ldap", CURLPROTO_LDAP }, - { "ldaps", CURLPROTO_LDAPS }, - { "dict", CURLPROTO_DICT }, - { "file", CURLPROTO_FILE }, - { "tftp", CURLPROTO_TFTP }, - { "imap", CURLPROTO_IMAP }, - { "imaps", CURLPROTO_IMAPS }, - { "pop3", CURLPROTO_POP3 }, - { "pop3s", CURLPROTO_POP3S }, - { "smtp", CURLPROTO_SMTP }, - { "smtps", CURLPROTO_SMTPS }, - { "rtsp", CURLPROTO_RTSP }, - { "gopher", CURLPROTO_GOPHER }, - { NULL, 0 } - }; - - if(!str) - return 1; - - buffer = strdup(str); /* because strtok corrupts it */ - - for(token = strtok(buffer, sep); - token; - token = strtok(NULL, sep)) { - enum e_action { allow, deny, set } action = allow; - - struct sprotos const *pp; - - /* Process token modifiers */ - while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ - switch (*token++) { - case '=': - action = set; - break; - case '-': - action = deny; - break; - case '+': - action = allow; - break; - default: /* Includes case of terminating NULL */ - free(buffer); - return 1; - } - } - - for(pp=protos; pp->name; pp++) { - if(curlx_raw_equal(token, pp->name)) { - switch (action) { - case deny: - *val &= ~(pp->bit); - break; - case allow: - *val |= pp->bit; - break; - case set: - *val = pp->bit; - break; - } - break; - } - } - - if(!(pp->name)) { /* unknown protocol */ - /* If they have specified only this protocol, we say treat it as - if no protocols are allowed */ - if(action == set) - *val = 0; - warnf(config, "unrecognized protocol '%s'\n", token); - } - } - free(buffer); - return 0; -} - -/** - * Parses the given string looking for an offset (which may be - * a larger-than-integer value). - * - * @param val the offset to populate - * @param str the buffer containing the offset - * @return zero if successful, non-zero if failure. - */ -static int str2offset(curl_off_t *val, const char *str) -{ -#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) - *val = curlx_strtoofft(str, NULL, 0); - if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE)) - return 1; -#else - *val = strtol(str, NULL, 0); - if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE) - return 1; -#endif - return 0; -} - -static void checkpasswd(const char *kind, /* for what purpose */ - char **userpwd) /* pointer to allocated string */ -{ - char *ptr; - if(!*userpwd) - return; - - ptr = strchr(*userpwd, ':'); - if(!ptr) { - /* no password present, prompt for one */ - char passwd[256]=""; - char prompt[256]; - size_t passwdlen; - size_t userlen = strlen(*userpwd); - char *passptr; - - /* build a nice-looking prompt */ - curlx_msnprintf(prompt, sizeof(prompt), - "Enter %s password for user '%s':", - kind, *userpwd); - - /* get password */ - getpass_r(prompt, passwd, sizeof(passwd)); - passwdlen = strlen(passwd); - - /* extend the allocated memory area to fit the password too */ - passptr = realloc(*userpwd, - passwdlen + 1 + /* an extra for the colon */ - userlen + 1); /* an extra for the zero */ - - if(passptr) { - /* append the password separated with a colon */ - passptr[userlen]=':'; - memcpy(&passptr[userlen+1], passwd, passwdlen+1); - *userpwd = passptr; - } - } -} - -static ParameterError add2list(struct curl_slist **list, - const char *ptr) -{ - struct curl_slist *newlist = curl_slist_append(*list, ptr); - if(newlist) - *list = newlist; - else - return PARAM_NO_MEM; - - return PARAM_OK; -} - -static int ftpfilemethod(struct Configurable *config, const char *str) -{ - if(curlx_raw_equal("singlecwd", str)) - return CURLFTPMETHOD_SINGLECWD; - if(curlx_raw_equal("nocwd", str)) - return CURLFTPMETHOD_NOCWD; - if(curlx_raw_equal("multicwd", str)) - return CURLFTPMETHOD_MULTICWD; - warnf(config, "unrecognized ftp file method '%s', using default\n", str); - return CURLFTPMETHOD_MULTICWD; -} - -static int ftpcccmethod(struct Configurable *config, const char *str) -{ - if(curlx_raw_equal("passive", str)) - return CURLFTPSSL_CCC_PASSIVE; - if(curlx_raw_equal("active", str)) - return CURLFTPSSL_CCC_ACTIVE; - warnf(config, "unrecognized ftp CCC method '%s', using default\n", str); - return CURLFTPSSL_CCC_PASSIVE; -} - - -static int sockoptcallback(void *clientp, curl_socket_t curlfd, - curlsocktype purpose) -{ - struct Configurable *config = (struct Configurable *)clientp; - int onoff = 1; /* this callback is only used if we ask for keepalives on the - connection */ -#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL) - int keepidle = (int)config->alivetime; -#endif - - switch(purpose) { - case CURLSOCKTYPE_IPCXN: - if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff, - sizeof(onoff)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(clientp, "Could not set SO_KEEPALIVE!\n"); - return 0; - } - else { - if(config->alivetime) { -#ifdef TCP_KEEPIDLE - if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, - sizeof(keepidle)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(clientp, "Could not set TCP_KEEPIDLE!\n"); - return 0; - } -#endif -#ifdef TCP_KEEPINTVL - if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle, - sizeof(keepidle)) < 0) { - /* don't abort operation, just issue a warning */ - SET_SOCKERRNO(0); - warnf(clientp, "Could not set TCP_KEEPINTVL!\n"); - return 0; - } -#endif -#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL) - warnf(clientp, "Keep-alive functionality somewhat crippled due to " - "missing support in your operating system!\n"); -#endif - } - } - break; - default: - break; - } - - return 0; -} - - -static ParameterError getparameter(char *flag, /* f or -long-flag */ - char *nextarg, /* NULL if unset */ - bool *usedarg, /* set to TRUE if the arg - has been used */ - struct Configurable *config) -{ - char letter; - char subletter=0; /* subletters can only occur on long options */ - int rc; /* generic return code variable */ - const char *parse=NULL; - unsigned int j; - time_t now; - int hit=-1; - bool longopt=FALSE; - bool singleopt=FALSE; /* when true means '-o foo' used '-ofoo' */ - ParameterError err; - bool toggle=TRUE; /* how to switch boolean options, on or off. Controlled - by using --OPTION or --no-OPTION */ - - /* single-letter, - long-name, - boolean whether it takes an additional argument - */ - static const struct LongShort aliases[]= { - /* all these ones, starting with "*" or "$" as a short-option have *no* - short option to mention. */ - {"*", "url", TRUE}, - {"*a", "random-file", TRUE}, - {"*b", "egd-file", TRUE}, - {"*c", "connect-timeout", TRUE}, - {"*d", "ciphers", TRUE}, - {"*e", "disable-epsv", FALSE}, - {"*E", "epsv", FALSE}, /* made like this to make --no-epsv and --epsv to - work although --disable-epsv is the documented - option */ -#ifdef USE_ENVIRONMENT - {"*f", "environment", FALSE}, -#endif - {"*g", "trace", TRUE}, - {"*h", "trace-ascii", TRUE}, - {"*i", "limit-rate", TRUE}, - {"*j", "compressed", FALSE}, - {"*J", "tr-encoding", FALSE}, - {"*k", "digest", FALSE}, - {"*l", "negotiate", FALSE}, - {"*m", "ntlm", FALSE}, - {"*n", "basic", FALSE}, - {"*o", "anyauth", FALSE}, -#ifdef USE_WATT32 - {"*p", "wdebug", FALSE}, -#endif - {"*q", "ftp-create-dirs", FALSE}, - {"*r", "create-dirs", FALSE}, - {"*s", "max-redirs", TRUE}, - {"*t", "proxy-ntlm", FALSE}, - {"*u", "crlf", FALSE}, - {"*v", "stderr", TRUE}, - {"*w", "interface", TRUE}, - {"*x", "krb" , TRUE}, - {"*x", "krb4" , TRUE}, /* this is the previous name */ - {"*y", "max-filesize", TRUE}, - {"*z", "disable-eprt", FALSE}, - {"*Z", "eprt", FALSE}, /* made like this to make --no-eprt and --eprt to - work although --disable-eprt is the documented - option */ - {"$a", "ftp-ssl", FALSE}, /* deprecated name since 7.20.0 */ - {"$a", "ssl", FALSE}, /* new option name in 7.20.0, previously this - was ftp-ssl */ - {"$b", "ftp-pasv", FALSE}, - {"$c", "socks5", TRUE}, - {"$c", "socks", TRUE}, /* this is how the option once was documented - but we prefer the --socks5 version for - explicit version */ - {"$d", "tcp-nodelay",FALSE}, - {"$e", "proxy-digest", FALSE}, - {"$f", "proxy-basic", FALSE}, - {"$g", "retry", TRUE}, - {"$h", "retry-delay", TRUE}, - {"$i", "retry-max-time", TRUE}, - {"$k", "proxy-negotiate", FALSE}, - {"$m", "ftp-account", TRUE}, - {"$n", "proxy-anyauth", FALSE}, - {"$o", "trace-time", FALSE}, - {"$p", "ignore-content-length", FALSE}, - {"$q", "ftp-skip-pasv-ip", FALSE}, - {"$r", "ftp-method", TRUE}, - {"$s", "local-port", TRUE}, - {"$t", "socks4", TRUE}, - {"$T", "socks4a", TRUE}, - {"$u", "ftp-alternative-to-user", TRUE}, - {"$v", "ftp-ssl-reqd", FALSE}, /* deprecated name since 7.20.0 */ - {"$v", "ssl-reqd", FALSE}, /* new option name in 7.20.0, previously this - was ftp-ssl-reqd */ - {"$w", "sessionid", FALSE}, /* listed as --no-sessionid in the help */ - {"$x", "ftp-ssl-control", FALSE}, - {"$y", "ftp-ssl-ccc", FALSE}, - {"$j", "ftp-ssl-ccc-mode", TRUE}, - {"$z", "libcurl", TRUE}, - {"$#", "raw", FALSE}, - {"$0", "post301", FALSE}, - {"$1", "keepalive", FALSE}, /* listed as --no-keepalive in the help */ - {"$2", "socks5-hostname", TRUE}, - {"$3", "keepalive-time", TRUE}, - {"$4", "post302", FALSE}, - {"$5", "noproxy", TRUE}, - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - {"$6", "socks5-gssapi-service", TRUE}, - {"$7", "socks5-gssapi-nec", FALSE}, -#endif - {"$8", "proxy1.0", TRUE}, - {"$9", "tftp-blksize", TRUE}, - {"$A", "mail-from", TRUE}, - {"$B", "mail-rcpt", TRUE}, - {"$C", "ftp-pret", FALSE}, - {"$D", "proto", TRUE}, - {"$E", "proto-redir", TRUE}, - {"$F", "resolve", TRUE}, - {"0", "http1.0", FALSE}, - {"1", "tlsv1", FALSE}, - {"2", "sslv2", FALSE}, - {"3", "sslv3", FALSE}, - {"4", "ipv4", FALSE}, - {"6", "ipv6", FALSE}, - {"a", "append", FALSE}, - {"A", "user-agent", TRUE}, - {"b", "cookie", TRUE}, - {"B", "use-ascii", FALSE}, - {"c", "cookie-jar", TRUE}, - {"C", "continue-at", TRUE}, - {"d", "data", TRUE}, - {"da", "data-ascii", TRUE}, - {"db", "data-binary", TRUE}, - {"de", "data-urlencode", TRUE}, - {"D", "dump-header", TRUE}, - {"e", "referer", TRUE}, - {"E", "cert", TRUE}, - {"Ea", "cacert", TRUE}, - {"Eb","cert-type", TRUE}, - {"Ec","key", TRUE}, - {"Ed","key-type", TRUE}, - {"Ee","pass", TRUE}, - {"Ef","engine", TRUE}, - {"Eg","capath ", TRUE}, - {"Eh","pubkey", TRUE}, - {"Ei", "hostpubmd5", TRUE}, - {"Ej","crlfile", TRUE}, - {"Ek","tlsuser", TRUE}, - {"El","tlspassword", TRUE}, - {"Em","tlsauthtype", TRUE}, - {"f", "fail", FALSE}, - {"F", "form", TRUE}, - {"Fs","form-string", TRUE}, - {"g", "globoff", FALSE}, - {"G", "get", FALSE}, - {"h", "help", FALSE}, - {"H", "header", TRUE}, - {"i", "include", FALSE}, - {"I", "head", FALSE}, - {"j", "junk-session-cookies", FALSE}, - {"J", "remote-header-name", FALSE}, - {"k", "insecure", FALSE}, - {"K", "config", TRUE}, - {"l", "list-only", FALSE}, - {"L", "location", FALSE}, - {"Lt", "location-trusted", FALSE}, - {"m", "max-time", TRUE}, - {"M", "manual", FALSE}, - {"n", "netrc", FALSE}, - {"no", "netrc-optional", FALSE}, - {"ne", "netrc-file", TRUE}, - {"N", "buffer", FALSE}, /* listed as --no-buffer in the help */ - {"o", "output", TRUE}, - {"O", "remote-name", FALSE}, - {"Oa", "remote-name-all", FALSE}, - {"p", "proxytunnel", FALSE}, - {"P", "ftpport", TRUE}, /* older version */ - {"P", "ftp-port", TRUE}, - {"q", "disable", FALSE}, - {"Q", "quote", TRUE}, - {"r", "range", TRUE}, - {"R", "remote-time", FALSE}, - {"s", "silent", FALSE}, - {"S", "show-error", FALSE}, - {"t", "telnet-options", TRUE}, /* this is documented as telnet-option */ - {"T", "upload-file", TRUE}, - {"u", "user", TRUE}, - {"U", "proxy-user", TRUE}, - {"v", "verbose", FALSE}, - {"V", "version", FALSE}, - {"w", "write-out", TRUE}, - {"x", "proxy", TRUE}, - {"X", "request", TRUE}, - {"X", "http-request", TRUE}, /* OBSOLETE VERSION */ - {"Y", "speed-limit", TRUE}, - {"y", "speed-time", TRUE}, - {"z", "time-cond", TRUE}, - {"#", "progress-bar",FALSE}, - {"~", "xattr",FALSE}, - }; - - if(('-' != flag[0]) || - (('-' == flag[0]) && ('-' == flag[1]))) { - /* this should be a long name */ - char *word=('-' == flag[0])?flag+2:flag; - size_t fnam=strlen(word); - int numhits=0; - - if(!strncmp(word, "no-", 3)) { - /* disable this option but ignore the "no-" part when looking for it */ - word += 3; - toggle = FALSE; - } - - for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) { - if(curlx_strnequal(aliases[j].lname, word, fnam)) { - longopt = TRUE; - numhits++; - if(curlx_raw_equal(aliases[j].lname, word)) { - parse = aliases[j].letter; - hit = j; - numhits = 1; /* a single unique hit */ - break; - } - parse = aliases[j].letter; - hit = j; - } - } - if(numhits>1) { - /* this is at least the second match! */ - return PARAM_OPTION_AMBIGUOUS; - } - if(hit < 0) { - return PARAM_OPTION_UNKNOWN; - } - } - else { - flag++; /* prefixed with one dash, pass it */ - hit=-1; - parse = flag; - } - - do { - /* we can loop here if we have multiple single-letters */ - - if(!longopt) { - if(NULL != parse) { - letter = (char)*parse; - } - else { - letter = '\0'; - } - subletter='\0'; - } - else { - letter = parse[0]; - subletter = parse[1]; - } - *usedarg = FALSE; /* default is that we don't use the arg */ - - if(hit < 0) { - for(j=0; j< sizeof(aliases)/sizeof(aliases[0]); j++) { - if(letter == aliases[j].letter[0]) { - hit = j; - break; - } - } - if(hit < 0) { - return PARAM_OPTION_UNKNOWN; - } - } - - if(aliases[hit].extraparam) { - /* 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) - return PARAM_REQUIRES_PARAMETER; - else - *usedarg = TRUE; /* mark it as used */ - } - - switch(letter) { - case '*': /* options without a short option */ - switch(subletter) { - case 'a': /* random-file */ - GetStr(&config->random_file, nextarg); - break; - case 'b': /* egd-file */ - GetStr(&config->egd_file, nextarg); - break; - case 'c': /* connect-timeout */ - if(str2num(&config->connecttimeout, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case 'd': /* ciphers */ - GetStr(&config->cipher_list, nextarg); - break; - case 'e': /* --disable-epsv */ - config->disable_epsv = toggle; - break; - case 'E': /* --epsv */ - config->disable_epsv = (bool)(!toggle); - break; -#ifdef USE_ENVIRONMENT - case 'f': - config->writeenv = toggle; - break; -#endif - case 'g': /* --trace */ - GetStr(&config->trace_dump, nextarg); - if(config->tracetype && (config->tracetype != TRACE_BIN)) - warnf(config, "--trace overrides an earlier trace/verbose option\n"); - config->tracetype = TRACE_BIN; - break; - case 'h': /* --trace-ascii */ - GetStr(&config->trace_dump, nextarg); - if(config->tracetype && (config->tracetype != TRACE_ASCII)) - warnf(config, - "--trace-ascii overrides an earlier trace/verbose option\n"); - config->tracetype = TRACE_ASCII; - break; - case 'i': /* --limit-rate */ - { - /* We support G, M, K too */ - char *unit; - curl_off_t value = curlx_strtoofft(nextarg, &unit, 0); - - if(!*unit) - unit=(char *)"b"; - else if(strlen(unit) > 1) - unit=(char *)"w"; /* unsupported */ - - switch(*unit) { - case 'G': - case 'g': - value *= 1024*1024*1024; - break; - case 'M': - case 'm': - value *= 1024*1024; - break; - case 'K': - case 'k': - value *= 1024; - break; - case 'b': - case 'B': - /* for plain bytes, leave as-is */ - break; - default: - warnf(config, "unsupported rate unit. Use G, M, K or B!\n"); - return PARAM_BAD_USE; - } - config->recvpersecond = value; - config->sendpersecond = value; - } - break; - - case 'j': /* --compressed */ - if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->encoding = toggle; - break; - - case 'J': /* --tr-encoding */ - config->tr_encoding = toggle; - break; - - case 'k': /* --digest */ - if(toggle) - config->authtype |= CURLAUTH_DIGEST; - else - config->authtype &= ~CURLAUTH_DIGEST; - break; - - case 'l': /* --negotiate */ - if(toggle) { - if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) - config->authtype |= CURLAUTH_GSSNEGOTIATE; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - } - else - config->authtype &= ~CURLAUTH_GSSNEGOTIATE; - break; - - case 'm': /* --ntlm */ - if(toggle) { - if(curlinfo->features & CURL_VERSION_NTLM) - config->authtype |= CURLAUTH_NTLM; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - } - else - config->authtype &= ~CURLAUTH_NTLM; - break; - - case 'n': /* --basic for completeness */ - if(toggle) - config->authtype |= CURLAUTH_BASIC; - else - config->authtype &= ~CURLAUTH_BASIC; - break; - - case 'o': /* --anyauth, let libcurl pick it */ - if(toggle) - config->authtype = CURLAUTH_ANY; - /* --no-anyauth simply doesn't touch it */ - break; - -#ifdef USE_WATT32 - case 'p': /* --wdebug */ - dbug_init(); - break; -#endif - case 'q': /* --ftp-create-dirs */ - config->ftp_create_dirs = toggle; - break; - - case 'r': /* --create-dirs */ - config->create_dirs = TRUE; - break; - - case 's': /* --max-redirs */ - /* specified max no of redirects (http(s)) */ - if(str2num(&config->maxredirs, nextarg)) - return PARAM_BAD_NUMERIC; - break; - - case 't': /* --proxy-ntlm */ - if(curlinfo->features & CURL_VERSION_NTLM) - config->proxyntlm = toggle; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - - case 'u': /* --crlf */ - /* LF -> CRLF conversion? */ - config->crlf = TRUE; - break; - - case 'v': /* --stderr */ - if(strcmp(nextarg, "-")) { - FILE *newfile = fopen(nextarg, "wt"); - if(!newfile) - warnf(config, "Failed to open %s!\n", nextarg); - else { - if(config->errors_fopened) - fclose(config->errors); - config->errors = newfile; - config->errors_fopened = TRUE; - } - } - else - config->errors = stdout; - break; - case 'w': /* --interface */ - /* interface */ - GetStr(&config->iface, nextarg); - break; - case 'x': /* --krb */ - /* kerberos level string */ - if(curlinfo->features & (CURL_VERSION_KERBEROS4 | - CURL_VERSION_GSSNEGOTIATE)) - GetStr(&config->krblevel, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'y': /* --max-filesize */ - if(str2offset(&config->max_filesize, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case 'z': /* --disable-eprt */ - config->disable_eprt = toggle; - break; - case 'Z': /* --eprt */ - config->disable_eprt = (bool)(!toggle); - break; - - default: /* the URL! */ - { - struct getout *url; - if(config->url_get || ((config->url_get = config->url_list) != NULL)) { - /* 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! */ - url=new_getout(config); - - if(url) { - /* fill in the URL */ - GetStr(&url->url, nextarg); - url->flags |= GETOUT_URL; - } - } - } - break; - case '$': /* more options without a short option */ - switch(subletter) { - case 'a': /* --ftp-ssl */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl = toggle; - break; - case 'b': /* --ftp-pasv */ - if(config->ftpport) - free(config->ftpport); - config->ftpport = NULL; - break; - case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves - the name locally and passes on the resolved address */ - GetStr(&config->socksproxy, nextarg); - config->socksver = CURLPROXY_SOCKS5; - break; - case 't': /* --socks4 specifies a socks4 proxy to use */ - GetStr(&config->socksproxy, nextarg); - config->socksver = CURLPROXY_SOCKS4; - break; - case 'T': /* --socks4a specifies a socks4a proxy to use */ - GetStr(&config->socksproxy, nextarg); - config->socksver = CURLPROXY_SOCKS4A; - break; - case '2': /* --socks5-hostname specifies a socks5 proxy and enables name - resolving with the proxy */ - GetStr(&config->socksproxy, nextarg); - config->socksver = CURLPROXY_SOCKS5_HOSTNAME; - break; - case 'd': /* --tcp-nodelay option */ - config->tcp_nodelay = toggle; - break; - case 'e': /* --proxy-digest */ - config->proxydigest = toggle; - break; - case 'f': /* --proxy-basic */ - config->proxybasic = toggle; - break; - case 'g': /* --retry */ - if(str2num(&config->req_retry, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case 'h': /* --retry-delay */ - if(str2num(&config->retry_delay, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case 'i': /* --retry-max-time */ - if(str2num(&config->retry_maxtime, nextarg)) - return PARAM_BAD_NUMERIC; - break; - - case 'k': /* --proxy-negotiate */ - if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) - config->proxynegotiate = toggle; - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'm': /* --ftp-account */ - GetStr(&config->ftp_account, nextarg); - break; - case 'n': /* --proxy-anyauth */ - config->proxyanyauth = toggle; - break; - case 'o': /* --trace-time */ - config->tracetime = toggle; - break; - case 'p': /* --ignore-content-length */ - config->ignorecl = toggle; - break; - case 'q': /* --ftp-skip-pasv-ip */ - config->ftp_skip_ip = toggle; - break; - case 'r': /* --ftp-method (undocumented at this point) */ - config->ftp_filemethod = ftpfilemethod(config, nextarg); - break; - case 's': /* --local-port */ - rc = sscanf(nextarg, "%d - %d", - &config->localport, - &config->localportrange); - if(!rc) - return PARAM_BAD_USE; - else if(rc == 1) - config->localportrange = 1; /* default number of ports to try */ - else { - config->localportrange -= config->localport; - if(config->localportrange < 1) { - warnf(config, "bad range input\n"); - return PARAM_BAD_USE; - } - } - break; - case 'u': /* --ftp-alternative-to-user */ - GetStr(&config->ftp_alternative_to_user, nextarg); - break; - case 'v': /* --ftp-ssl-reqd */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl_reqd = toggle; - break; - case 'w': /* --no-sessionid */ - config->disable_sessionid = (bool)(!toggle); - break; - case 'x': /* --ftp-ssl-control */ - if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) - return PARAM_LIBCURL_DOESNT_SUPPORT; - config->ftp_ssl_control = toggle; - break; - case 'y': /* --ftp-ssl-ccc */ - config->ftp_ssl_ccc = toggle; - if(!config->ftp_ssl_ccc_mode) - config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; - break; - case 'j': /* --ftp-ssl-ccc-mode */ - config->ftp_ssl_ccc = TRUE; - config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); - break; - case 'z': /* --libcurl */ - GetStr(&config->libcurl, nextarg); - break; - case '#': /* --raw */ - config->raw = toggle; - break; - case '0': /* --post301 */ - config->post301 = toggle; - break; - case '1': /* --no-keepalive */ - config->nokeepalive = (bool)(!toggle); - break; - case '3': /* --keepalive-time */ - if(str2num(&config->alivetime, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case '4': /* --post302 */ - config->post302 = toggle; - break; - case '5': /* --noproxy */ - /* This specifies the noproxy list */ - GetStr(&config->noproxy, nextarg); - break; -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - case '6': /* --socks5-gssapi-service */ - GetStr(&config->socks5_gssapi_service, nextarg); - break; - case '7': /* --socks5-gssapi-nec*/ - config->socks5_gssapi_nec = TRUE; - break; -#endif - case '8': /* --proxy1.0 */ - /* http 1.0 proxy */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_HTTP_1_0; - break; - case '9': /* --tftp-blksize */ - str2num(&config->tftp_blksize, nextarg); - break; - case 'A': /* --mail-from */ - GetStr(&config->mail_from, nextarg); - break; - case 'B': /* --mail-rcpt */ - /* append receiver to a list */ - err = add2list(&config->mail_rcpt, nextarg); - if(err) - return err; - break; - case 'C': /* --ftp-pret */ - config->ftp_pret = toggle; - break; - case 'D': /* --proto */ - config->proto_present = TRUE; - if(proto2num(config, &config->proto, nextarg)) - return PARAM_BAD_USE; - break; - case 'E': /* --proto-redir */ - config->proto_redir_present = TRUE; - if(proto2num(config, &config->proto_redir, nextarg)) - return PARAM_BAD_USE; - break; - case 'F': /* --resolve */ - err = add2list(&config->resolve, nextarg); - if(err) - return err; - break; - } - break; - case '#': /* --progress-bar */ - if(toggle) - config->progressmode = CURL_PROGRESS_BAR; - else - config->progressmode = CURL_PROGRESS_STATS; - break; - case '~': /* --xattr */ - config->xattr = toggle; - break; - case '0': - /* HTTP version 1.0 */ - config->httpversion = CURL_HTTP_VERSION_1_0; - break; - case '1': - /* TLS version 1 */ - config->ssl_version = CURL_SSLVERSION_TLSv1; - break; - case '2': - /* SSL version 2 */ - config->ssl_version = CURL_SSLVERSION_SSLv2; - break; - case '3': - /* SSL version 3 */ - config->ssl_version = CURL_SSLVERSION_SSLv3; - break; - case '4': - /* IPv4 */ - config->ip_version = 4; - break; - case '6': - /* IPv6 */ - config->ip_version = 6; - break; - case 'a': - /* This makes the FTP sessions use APPE instead of STOR */ - config->ftp_append = toggle; - break; - case 'A': - /* This specifies the User-Agent name */ - GetStr(&config->useragent, nextarg); - break; - case 'b': /* cookie string coming up: */ - if(nextarg[0] == '@') { - nextarg++; - } - else if(strchr(nextarg, '=')) { - /* A cookie string must have a =-letter */ - GetStr(&config->cookie, nextarg); - break; - } - /* We have a cookie file to read from! */ - GetStr(&config->cookiefile, nextarg); - break; - case 'B': - /* use ASCII/text when transferring */ - config->use_ascii = toggle; - break; - case 'c': - /* get the file name to dump all cookies in */ - GetStr(&config->cookiejar, nextarg); - break; - case 'C': - /* This makes us continue an ftp transfer at given position */ - if(!curlx_strequal(nextarg, "-")) { - if(str2offset(&config->resume_from, nextarg)) - return PARAM_BAD_NUMERIC; - config->resume_from_current = FALSE; - } - else { - config->resume_from_current = TRUE; - config->resume_from = 0; - } - config->use_resume=TRUE; - break; - case 'd': - /* postfield data */ - { - char *postdata=NULL; - FILE *file; - - if(subletter == 'e') { /* --data-urlencode*/ - /* [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. - */ - const char *p = strchr(nextarg, '='); - size_t size = 0; - size_t nlen; - char is_file; - 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) { - /* a '@' letter, it means that a file name or - (stdin) follows */ - - if(curlx_strequal("-", p)) { - file = stdin; - SET_BINMODE(stdin); - } - else { - file = fopen(p, "rb"); - if(!file) - warnf(config, - "Couldn't read data from file \"%s\", this makes " - "an empty POST.\n", nextarg); - } - - err = file2memory(&postdata, &size, file); - - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - } - else { - GetStr(&postdata, p); - 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(""); - } - else { - char *enc = curl_easy_escape(config->easy, postdata, (int)size); - free(postdata); /* no matter if it worked or not */ - if(enc) { - /* now make a string with the name from above and append the - encoded string */ - size_t outlen = nlen + strlen(enc) + 2; - char *n = malloc(outlen); - if(!n) { - curl_free(enc); - return PARAM_NO_MEM; - } - if(nlen > 0) /* only append '=' if we have a name */ - snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); - else - strcpy(n, enc); - curl_free(enc); - postdata = n; - } - else - return PARAM_NO_MEM; - } - } - else if('@' == *nextarg) { - size_t size = 0; - /* the data begins with a '@' letter, it means that a file name - or - (stdin) follows */ - nextarg++; /* pass the @ */ - - if(curlx_strequal("-", nextarg)) { - file = stdin; - if(subletter == 'b') /* forced data-binary */ - SET_BINMODE(stdin); - } - else { - file = fopen(nextarg, "rb"); - if(!file) - warnf(config, "Couldn't read data from file \"%s\", this makes " - "an empty POST.\n", nextarg); - } - - if(subletter == 'b') { - /* forced binary */ - err = file2memory(&postdata, &size, file); - config->postfieldsize = (curl_off_t)size; - } - else - err = file2string(&postdata, file); - - 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(""); - } - } - else { - GetStr(&postdata, nextarg); - } - -#ifdef CURL_DOES_CONVERSIONS - if(subletter != 'b') { /* NOT forced binary, convert to ASCII */ - convert_to_network(postdata, strlen(postdata)); - } -#endif - - if(config->postfields) { - /* we already have a string, we append this one - with a separating &-letter */ - char *oldpost=config->postfields; - size_t newlen = strlen(oldpost) + strlen(postdata) + 2; - config->postfields=malloc(newlen); - if(!config->postfields) { - free(postdata); - return PARAM_NO_MEM; - } - /* use ASCII value 0x26 for '&' to accommodate non-ASCII platforms */ - snprintf(config->postfields, newlen, "%s\x26%s", oldpost, postdata); - free(oldpost); - free(postdata); - } - else - config->postfields=postdata; - } - /* - We can't set the request type here, as this data might be used in - a simple GET if -G is used. Already or soon. - - if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) - return PARAM_BAD_USE; - */ - break; - case 'D': - /* dump-header to given file name */ - GetStr(&config->headerfile, nextarg); - break; - case 'e': - { - char *ptr = strstr(nextarg, ";auto"); - if(ptr) { - /* Automatic referer requested, this may be combined with a - set initial one */ - config->autoreferer = TRUE; - *ptr = 0; /* zero terminate here */ - } - else - config->autoreferer = FALSE; - GetStr(&config->referer, nextarg); - } - break; - case 'E': - switch(subletter) { - case 'a': /* CA info PEM file */ - /* CA info PEM file */ - GetStr(&config->cacert, nextarg); - break; - case 'b': /* cert file type */ - GetStr(&config->cert_type, nextarg); - break; - case 'c': /* private key file */ - GetStr(&config->key, nextarg); - break; - case 'd': /* private key file type */ - GetStr(&config->key_type, nextarg); - break; - case 'e': /* private key passphrase */ - GetStr(&config->key_passwd, nextarg); - cleanarg(nextarg); - break; - case 'f': /* crypto engine */ - GetStr(&config->engine, nextarg); - if(config->engine && curlx_raw_equal(config->engine,"list")) - config->list_engines = TRUE; - break; - case 'g': /* CA info PEM file */ - /* CA cert directory */ - GetStr(&config->capath, nextarg); - break; - case 'h': /* --pubkey public key file */ - GetStr(&config->pubkey, nextarg); - break; - case 'i': /* --hostpubmd5 md5 of the host public key */ - GetStr(&config->hostpubmd5, nextarg); - if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) - return PARAM_BAD_USE; - break; - case 'j': /* CRL info PEM file */ - /* CRL file */ - GetStr(&config->crlfile, nextarg); - break; - case 'k': /* TLS username */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->tls_username, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'l': /* TLS password */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) - GetStr(&config->tls_password, nextarg); - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - case 'm': /* TLS authentication type */ - if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { - GetStr(&config->tls_authtype, nextarg); - if(!strequal(config->tls_authtype, "SRP")) - return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ - } - else - return PARAM_LIBCURL_DOESNT_SUPPORT; - break; - default: /* certificate file */ - { - char *ptr = strchr(nextarg, ':'); - /* 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(ptr && - (ptr == &nextarg[1]) && - (nextarg[2] == '\\' || nextarg[2] == '/') && - (ISALPHA(nextarg[0])) ) - /* colon in the second column, followed by a backslash, and the - first character is an alphabetic letter: - - this is a drive letter colon */ - ptr = strchr(&nextarg[3], ':'); /* find the next one instead */ -#endif - if(ptr) { - /* we have a password too */ - *ptr=0; - ptr++; - GetStr(&config->key_passwd, ptr); - } - GetStr(&config->cert, nextarg); - cleanarg(nextarg); - } - } - break; - case 'f': - /* fail hard on errors */ - config->failonerror = toggle; - break; - case 'F': - /* "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->httppost, - &config->last_post, - (bool) (subletter=='s'))) /* 's' means literal string */ - return PARAM_BAD_USE; - if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq)) - return PARAM_BAD_USE; - break; - - case 'g': /* g disables URLglobbing */ - config->globoff = toggle; - break; - - case 'G': /* HTTP GET */ - config->use_httpget = TRUE; - break; - - case 'h': /* h for help */ - if(toggle) { - help(); - return PARAM_HELP_REQUESTED; - } - /* we now actually support --no-help too! */ - break; - case 'H': - /* A custom header to append to a list */ - err = add2list(&config->headers, nextarg); - if(err) - return err; - break; - case 'i': - config->include_headers = toggle; /* include the headers as well in the - general output stream */ - break; - case 'j': - config->cookiesession = toggle; - break; - case 'I': - /* - * no_body will imply include_headers later on - */ - config->no_body = toggle; - if(SetHTTPrequest(config, - (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, - &config->httpreq)) - return PARAM_BAD_USE; - break; - case 'J': /* --remote-header-name */ - if(config->include_headers) { - warnf(config, - "--include and --remote-header-name cannot be combined.\n"); - return PARAM_BAD_USE; - } - config->content_disposition = toggle; - break; - case 'k': /* allow insecure SSL connects */ - config->insecure_ok = toggle; - break; - case 'K': /* parse config file */ - if(parseconfig(nextarg, config)) - warnf(config, "error trying read config from the '%s' file\n", - nextarg); - break; - case 'l': - config->dirlistonly = toggle; /* only list the names of the FTP dir */ - break; - case 'L': - config->followlocation = toggle; /* Follow Location: HTTP headers */ - switch (subletter) { - case 't': - /* Continue to send authentication (user+password) when following - * locations, even when hostname changed */ - config->unrestricted_auth = toggle; - break; - } - break; - case 'm': - /* specified max time */ - if(str2num(&config->timeout, nextarg)) - return PARAM_BAD_NUMERIC; - break; - case 'M': /* M for manual, huge help */ - if(toggle) { /* --no-manual shows no manual... */ -#ifdef USE_MANUAL - hugehelp(); - return PARAM_HELP_REQUESTED; -#else - warnf(config, - "built-in manual was disabled at build-time!\n"); - return PARAM_OPTION_UNKNOWN; -#endif - } - break; - case 'n': - switch(subletter) { - case 'o': /* CA info PEM file */ - /* use .netrc or URL */ - config->netrc_opt = toggle; - break; - case 'e': /* netrc-file */ - GetStr(&config->netrc_file, nextarg); - break; - default: - /* pick info from .netrc, if this is used for http, curl will - automatically enfore user+password with the request */ - config->netrc = toggle; - break; - } - break; - case 'N': - /* disable the output I/O buffering. note that the option is called - --buffer but is mostly used in the negative form: --no-buffer */ - if(longopt) - config->nobuffer = (bool)(!toggle); - else - config->nobuffer = toggle; - break; - case 'O': /* --remote-name */ - if(subletter == 'a') { /* --remote-name-all */ - config->default_node_flags = toggle?GETOUT_USEREMOTE:0; - break; - } - /* fall-through! */ - case 'o': /* --output */ - /* output file */ - { - struct getout *url; - if(config->url_out || ((config->url_out = config->url_list) != NULL)) { - /* 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 - /* there was no free node, create one! */ - url=new_getout(config); - - if(url) { - /* fill in the outfile */ - if('o' == letter) { - GetStr(&url->outfile, nextarg); - 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 'P': - /* This makes the FTP sessions use PORT instead of PASV */ - /* use <eth0> or <192.168.10.10> style addresses. Anything except - this will make us try to get the "default" address. - NOTE: this is a changed behaviour since the released 4.1! - */ - GetStr(&config->ftpport, nextarg); - break; - case 'p': - /* proxy tunnel for non-http protocols */ - config->proxytunnel = toggle; - break; - - case 'q': /* if used first, already taken care of, we do it like - this so we don't cause an error! */ - break; - case 'Q': - /* 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; - } - if(err) - return err; - break; - case 'r': - /* 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]; - curl_off_t off; - warnf(config, - "A specified range MUST include at least one dash (-). " - "Appending one for you!\n"); - off = curlx_strtoofft(nextarg, NULL, 10); - snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); - GetStr(&config->range, buffer); - } - { - /* byte range requested */ - char* tmp_range; - tmp_range=nextarg; - while(*tmp_range != '\0') { - if(!ISDIGIT(*tmp_range)&&*tmp_range!='-'&&*tmp_range!=',') { - warnf(config,"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.\n"); - break; - } - tmp_range++; - } - /* byte range requested */ - GetStr(&config->range, nextarg); - } - break; - case 'R': - /* use remote file's time */ - config->remote_time = toggle; - break; - case 's': - /* don't show progress meter, don't show errors : */ - if(toggle) - config->mute = config->noprogress = TRUE; - else - config->mute = config->noprogress = FALSE; - config->showerror = (bool)(!toggle); /* toggle off */ - break; - case 'S': - /* show errors */ - config->showerror = toggle; /* toggle on if used with -s */ - break; - case 't': - /* Telnet options */ - err = add2list(&config->telnet_options, nextarg); - if(err) - return err; - break; - case 'T': - /* we are uploading */ - { - struct getout *url; - if(config->url_out || ((config->url_out = config->url_list) != NULL)) { - /* 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_UPLOAD)) - 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 - /* there was no free node, create one! */ - url=new_getout(config); - - if(url) { - url->flags |= GETOUT_UPLOAD; /* mark -T used */ - if(!*nextarg) - url->flags |= GETOUT_NOUPLOAD; - else { - /* "-" equals stdin, but keep the string around for now */ - GetStr(&url->infile, nextarg); - } - } - } - break; - case 'u': - /* user:password */ - GetStr(&config->userpwd, nextarg); - cleanarg(nextarg); - checkpasswd("host", &config->userpwd); - break; - case 'U': - /* Proxy user:password */ - GetStr(&config->proxyuserpwd, nextarg); - cleanarg(nextarg); - checkpasswd("proxy", &config->proxyuserpwd); - break; - case 'v': - if(toggle) { - /* the '%' thing here will cause the trace get sent to stderr */ - GetStr(&config->trace_dump, (char *)"%"); - if(config->tracetype && (config->tracetype != TRACE_PLAIN)) - warnf(config, - "-v/--verbose overrides an earlier trace/verbose option\n"); - config->tracetype = TRACE_PLAIN; - } - else - /* verbose is disabled here */ - config->tracetype = TRACE_NONE; - break; - case 'V': - { - const char * const *proto; - - if(!toggle) - /* --no-version yields no output! */ - break; - - printf(CURL_ID "%s\n", curl_version()); - if(curlinfo->protocols) { - printf("Protocols: "); - for(proto=curlinfo->protocols; *proto; ++proto) { - printf("%s ", *proto); - } - puts(""); /* newline */ - } - if(curlinfo->features) { - unsigned int i; - struct feat { - const char *name; - int bitmask; - }; - static const struct feat feats[] = { - {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, - {"Debug", CURL_VERSION_DEBUG}, - {"TrackMemory", CURL_VERSION_CURLDEBUG}, - {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, - {"IDN", CURL_VERSION_IDN}, - {"IPv6", CURL_VERSION_IPV6}, - {"Largefile", CURL_VERSION_LARGEFILE}, - {"NTLM", CURL_VERSION_NTLM}, - {"SPNEGO", CURL_VERSION_SPNEGO}, - {"SSL", CURL_VERSION_SSL}, - {"SSPI", CURL_VERSION_SSPI}, - {"krb4", CURL_VERSION_KERBEROS4}, - {"libz", CURL_VERSION_LIBZ}, - {"CharConv", CURL_VERSION_CONV}, - {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP} - }; - printf("Features: "); - for(i=0; i<sizeof(feats)/sizeof(feats[0]); i++) { - if(curlinfo->features & feats[i].bitmask) - printf("%s ", feats[i].name); - } - puts(""); /* newline */ - } - } - return PARAM_HELP_REQUESTED; - case 'w': - /* 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(curlx_strequal("-", nextarg)) { - fname = "<stdin>"; - file = stdin; - } - else { - fname = nextarg; - file = fopen(nextarg, "r"); - } - err = file2string(&config->writeout, file); - if(file && (file != stdin)) - fclose(file); - if(err) - return err; - if(!config->writeout) - warnf(config, "Failed to read %s", fname); - } - else - GetStr(&config->writeout, nextarg); - break; - case 'x': - /* proxy */ - GetStr(&config->proxy, nextarg); - config->proxyver = CURLPROXY_HTTP; - break; - case 'X': - /* set custom request */ - GetStr(&config->customrequest, nextarg); - break; - case 'y': - /* low speed time */ - if(str2num(&config->low_speed_time, nextarg)) - return PARAM_BAD_NUMERIC; - if(!config->low_speed_limit) - config->low_speed_limit = 1; - break; - case 'Y': - /* low speed limit */ - if(str2num(&config->low_speed_limit, nextarg)) - return PARAM_BAD_NUMERIC; - if(!config->low_speed_time) - config->low_speed_time=30; - break; - case 'z': /* time condition coming up */ - switch(*nextarg) { - case '+': - nextarg++; - 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_getdate(nextarg, &now); - if(-1 == (int)config->condtime) { - /* now let's see if it is a file name to get the time from instead! */ - struct_stat statbuf; - if(-1 == stat(nextarg, &statbuf)) { - /* failed, remove time condition */ - config->timecond = CURL_TIMECOND_NONE; - warnf(config, - "Illegal date format for -z/--timecond (and not " - "a file name). Disabling time condition. " - "See curl_getdate(3) for valid date syntax.\n"); - } - else { - /* pull the time out from the file */ - config->condtime = statbuf.st_mtime; - } - } - break; - default: /* unknown flag */ - return PARAM_OPTION_UNKNOWN; - } - hit = -1; - - } while(!longopt && !singleopt && *++parse && !*usedarg); - - return PARAM_OK; -} - -/* - * Copies the string from line to the buffer at param, unquoting - * backslash-quoted characters and NUL-terminating the output string. - * Stops at the first non-backslash-quoted double quote character or the - * end of the input string. param must be at least as long as the input - * string. Returns the pointer after the last handled input character. - */ -static const char *unslashquote(const char *line, char *param) -{ - while(*line && (*line != '\"')) { - if(*line == '\\') { - char out; - line++; - - /* default is to output the letter after the backslash */ - switch(out = *line) { - case '\0': - continue; /* this'll break out of the loop */ - case 't': - out='\t'; - break; - case 'n': - out='\n'; - break; - case 'r': - out='\r'; - break; - case 'v': - out='\v'; - break; - } - *param++=out; - line++; - } - else - *param++=*line++; - } - *param=0; /* always zero terminate */ - return line; -} - -/* return 0 on everything-is-fine, and non-zero otherwise */ -static int parseconfig(const char *filename, - struct Configurable *config) -{ - int res; - FILE *file; - char filebuffer[512]; - bool usedarg; - char *home; - int rc = 0; - - if(!filename || !*filename) { - /* NULL or no file name attempts to load .curlrc from the homedir! */ - -#define CURLRC DOT_CHAR "curlrc" - -#ifndef __AMIGA__ - filename = CURLRC; /* sensible default */ - home = homedir(); /* portable homedir finder */ - if(home) { - if(strlen(home)<(sizeof(filebuffer)-strlen(CURLRC))) { - snprintf(filebuffer, sizeof(filebuffer), - "%s%s%s", home, DIR_CHAR, CURLRC); - -#ifdef WIN32 - /* Check if the file exists - if not, try CURLRC in the same - * directory as our executable - */ - file = fopen(filebuffer, "r"); - if(file != NULL) { - fclose(file); - filename = filebuffer; - } - else { - /* Get the filename of our executable. GetModuleFileName is - * already declared via inclusions done in setup header file. - * We assume that we are using the ASCII version here. - */ - int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer)); - if(n > 0 && n < (int)sizeof(filebuffer)) { - /* We got a valid filename - get the directory part */ - char *lastdirchar = strrchr(filebuffer, '\\'); - if(lastdirchar) { - size_t remaining; - *lastdirchar = 0; - /* If we have enough space, build the RC filename */ - remaining = sizeof(filebuffer) - strlen(filebuffer); - if(strlen(CURLRC) < remaining - 1) { - snprintf(lastdirchar, remaining, - "%s%s", DIR_CHAR, CURLRC); - /* Don't bother checking if it exists - we do - * that later - */ - filename = filebuffer; - } - } - } - } -#else /* WIN32 */ - filename = filebuffer; -#endif /* WIN32 */ - } - free(home); /* we've used it, now free it */ - } - -# else /* __AMIGA__ */ - /* On AmigaOS all the config files are into env: - */ - filename = "ENV:" CURLRC; - -#endif - } - - if(strcmp(filename,"-")) - file = fopen(filename, "r"); - else - file = stdin; - - if(file) { - char *line; - char *aline; - char *option; - char *param; - int lineno=0; - bool alloced_param; - -#define ISSEP(x) (((x)=='=') || ((x) == ':')) - - while(NULL != (aline = my_get_line(file))) { - lineno++; - line = aline; - alloced_param=FALSE; - - /* line with # in the first non-blank column is a comment! */ - while(*line && ISSPACE(*line)) - line++; - - switch(*line) { - case '#': - case '/': - case '\r': - case '\n': - case '*': - case '\0': - free(aline); - continue; - } - - /* the option keywords starts here */ - option = line; - while(*line && !ISSPACE(*line) && !ISSEP(*line)) - line++; - /* ... and has ended here */ - - if(*line) - *line++=0; /* zero terminate, we have a local copy of the data */ - -#ifdef DEBUG_CONFIG - fprintf(stderr, "GOT: %s\n", option); -#endif - - /* pass spaces and separator(s) */ - while(*line && (ISSPACE(*line) || ISSEP(*line))) - line++; - - /* the parameter starts here (unless quoted) */ - if(*line == '\"') { - /* quoted parameter, do the quote dance */ - line++; - param=malloc(strlen(line)+1); /* parameter */ - if(!param) { - /* out of memory */ - free(aline); - rc = 1; - break; - } - alloced_param=TRUE; - (void)unslashquote(line, param); - } - else { - param=line; /* parameter starts here */ - while(*line && !ISSPACE(*line)) - line++; - *line=0; /* zero terminate */ - } - - if(param && !*param) { - /* do this so getparameter can check for required parameters. - Otherwise it always thinks there's a parameter. */ - if(alloced_param) - free(param); - param = NULL; - } - -#ifdef DEBUG_CONFIG - fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); -#endif - res = getparameter(option, param, &usedarg, config); - - if(param && *param && !usedarg) - /* we passed in a parameter that wasn't used! */ - res = PARAM_GOT_EXTRA_PARAMETER; - - if(res != PARAM_OK) { - /* the help request isn't really an error */ - if(!strcmp(filename, "-")) { - filename=(char *)"<stdin>"; - } - if(PARAM_HELP_REQUESTED != res) { - const char *reason = param2text(res); - warnf(config, "%s:%d: warning: '%s' %s\n", - filename, lineno, option, reason); - } - } - - if(alloced_param) { - free(param); - param = NULL; - } - - free(aline); - } - if(file != stdin) - fclose(file); - } - else - rc = 1; /* couldn't open the file */ - return rc; -} - -static void go_sleep(long ms) -{ -#ifdef HAVE_POLL_FINE - /* portable subsecond "sleep" */ - poll((void *)0, 0, (int)ms); -#else - /* systems without poll() need other solutions */ - -#ifdef WIN32 - /* Windows offers a millisecond sleep */ - Sleep(ms); -#elif defined(MSDOS) - delay(ms); -#else - /* Other systems must use select() for this */ - struct timeval timeout; - - timeout.tv_sec = ms/1000; - ms = ms%1000; - timeout.tv_usec = ms * 1000; - - select(0, NULL, NULL, NULL, &timeout); -#endif - -#endif -} - -static size_t my_fwrite(void *buffer, size_t sz, size_t nmemb, void *stream) -{ - size_t rc; - struct OutStruct *out=(struct OutStruct *)stream; - struct Configurable *config = out->config; - - /* - * Once that libcurl has called back my_fwrite() the returned value - * is checked against the amount that was intended to be written, if - * it does not match then it fails with CURLE_WRITE_ERROR. So at this - * point returning a value different from sz*nmemb indicates failure. - */ - const size_t err_rc = (sz * nmemb) ? 0 : 1; - - if(!out->stream) { - out->bytes = 0; /* nothing written yet */ - if(!out->filename) { - warnf(config, "Remote filename has no length!\n"); - return err_rc; /* Failure */ - } - - if(config->content_disposition) { - /* don't overwrite existing files */ - FILE* f = fopen(out->filename, "r"); - if(f) { - fclose(f); - warnf(config, "Refusing to overwrite %s: %s\n", out->filename, - strerror(EEXIST)); - return err_rc; /* Failure */ - } - } - - /* open file for writing */ - out->stream=fopen(out->filename, "wb"); - if(!out->stream) { - warnf(config, "Failed to create the file %s: %s\n", out->filename, - strerror(errno)); - return err_rc; /* failure */ - } - } - - rc = fwrite(buffer, sz, nmemb, out->stream); - - if((sz * nmemb) == rc) - /* we added this amount of data to the output */ - out->bytes += (sz * nmemb); - - if(config->readbusy) { - config->readbusy = FALSE; - curl_easy_pause(config->easy, CURLPAUSE_CONT); - } - - if(config->nobuffer) { - /* disable output buffering */ - int res = fflush(out->stream); - if(res) { - /* return a value that isn't the same as sz * nmemb */ - return err_rc; /* failure */ - } - } - - return rc; -} - -struct InStruct { - int fd; - struct Configurable *config; -}; - -#define MAX_SEEK 2147483647 - -/* - * my_seek() is the CURLOPT_SEEKFUNCTION we use - */ -static int my_seek(void *stream, curl_off_t offset, int whence) -{ - struct InStruct *in=(struct InStruct *)stream; - -#if(CURL_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 > MAX_SEEK) { - /* 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 1; - - if(LSEEK_ERROR == lseek(in->fd, 0, SEEK_SET)) - /* couldn't rewind to beginning */ - return 1; - - while(left) { - long step = (left>MAX_SEEK ? MAX_SEEK : (long)left); - if(LSEEK_ERROR == lseek(in->fd, step, SEEK_CUR)) - /* couldn't seek forwards the desired amount */ - return 1; - left -= step; - } - return 0; - } -#endif - if(LSEEK_ERROR == lseek(in->fd, 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 0; -} - -static size_t my_fread(void *buffer, size_t sz, size_t nmemb, void *userp) -{ - ssize_t rc; - struct InStruct *in=(struct InStruct *)userp; - - rc = read(in->fd, buffer, sz*nmemb); - if(rc < 0) { - if(errno == EAGAIN) { - errno = 0; - in->config->readbusy = TRUE; - return CURL_READFUNC_PAUSE; - } - /* since size_t is unsigned we can't return negative values fine */ - rc = 0; - } - in->config->readbusy = FALSE; - return (size_t)rc; -} - -struct ProgressData { - int calls; - curl_off_t prev; - int width; - FILE *out; /* where to write everything to */ - curl_off_t initial_size; -}; - -static int myprogress (void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow) -{ - /* The original progress-bar source code was written for curl by Lars Aas, - and this new edition inherits some of his concepts. */ - - char line[256]; - char outline[256]; - char format[40]; - double frac; - double percent; - int barwidth; - int num; - int i; - - struct ProgressData *bar = (struct ProgressData *)clientp; - curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal + - bar->initial_size; /* expected transfer size */ - curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow + - bar->initial_size; /* we've come this far */ - - if(point > total) - /* we have got more than the expected total! */ - total = point; - - bar->calls++; /* simply count invokes */ - - if(total < 1) { - curl_off_t prevblock = bar->prev / 1024; - curl_off_t thisblock = point / 1024; - while(thisblock > prevblock) { - fprintf( bar->out, "#" ); - prevblock++; - } - } - else { - frac = (double)point / (double)total; - percent = frac * 100.0f; - barwidth = bar->width - 7; - num = (int) (((double)barwidth) * frac); - for(i = 0; i < num; i++) - line[i] = '#'; - line[i] = '\0'; - snprintf( format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth ); - snprintf( outline, sizeof(outline), format, line, percent ); - fprintf( bar->out, "\r%s", outline ); - } - fflush(bar->out); - bar->prev = point; - - return 0; -} - -static -void progressbarinit(struct ProgressData *bar, - struct Configurable *config) -{ -#ifdef __EMX__ - /* 20000318 mgs */ - int scr_size [2]; -#endif - char *colp; - - memset(bar, 0, sizeof(struct ProgressData)); - - /* pass this through to progress function so - * it can display progress towards total file - * not just the part that's left. (21-may-03, dbyron) */ - if(config->use_resume) - bar->initial_size = config->resume_from; - -/* TODO: get terminal width through ansi escapes or something similar. - try to update width when xterm is resized... - 19990617 larsa */ -#ifndef __EMX__ - /* 20000318 mgs - * OS/2 users most likely won't have this env var set, and besides that - * we're using our own way to determine screen width */ - colp = curlx_getenv("COLUMNS"); - if(colp != NULL) { - char *endptr; - long num = strtol(colp, &endptr, 10); - if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0)) - bar->width = (int)num; - else - bar->width = 79; - curl_free(colp); - } - else - bar->width = 79; -#else - /* 20000318 mgs - * We use this emx library call to get the screen width, and subtract - * one from what we got in order to avoid a problem with the cursor - * advancing to the next line if we print a string that is as long as - * the screen is wide. */ - - _scrsize(scr_size); - bar->width = scr_size[0] - 1; -#endif - - bar->out = config->errors; -} - - -static -void dump(const char *timebuf, 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, %zd bytes (0x%zx)\n", timebuf, 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; - } -#ifdef CURL_DOES_CONVERSIONS - /* repeat the 0D0A check above but use the host encoding for CRLF */ - if((tracetype == TRACE_ASCII) && - (i+c+1 < size) && ptr[i+c]=='\r' && ptr[i+c+1]=='\n') { - i+=(c+2-width); - break; - } - /* convert to host encoding and print this character */ - fprintf(stream, "%c", convert_char(infotype, ptr[i+c])); -#else - (void)infotype; - fprintf(stream, "%c", - (ptr[i+c]>=0x20) && (ptr[i+c]<0x80)?ptr[i+c]:UNPRINTABLE_CHAR); -#endif /* CURL_DOES_CONVERSIONS */ - /* 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); -} - -static -int my_trace(CURL *handle, curl_infotype type, - unsigned char *data, size_t size, - void *userp) -{ - struct Configurable *config = (struct Configurable *)userp; - FILE *output=config->errors; - const char *text; - struct timeval tv; - struct tm *now; - char timebuf[20]; - time_t secs; - static time_t epoch_offset; - static int known_offset; - - (void)handle; /* prevent compiler warning */ - - if(config->tracetime) { - tv = cutil_tvnow(); - 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 don't care */ - snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ", - now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); - } - else - timebuf[0]=0; - - if(!config->trace_stream) { - /* open for append */ - if(curlx_strequal("-", config->trace_dump)) - config->trace_stream = stdout; - else if(curlx_strequal("%", config->trace_dump)) - /* Ok, this is somewhat hackish but we do it undocumented for now */ - config->trace_stream = config->errors; /* aka stderr */ - else { - config->trace_stream = fopen(config->trace_dump, "w"); - 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) { - /* - * This is the trace look that is similar to what libcurl makes on its - * own. - */ - static const char * const s_infotype[] = { - "*", "<", ">", "{", "}", "{", "}" - }; - size_t i; - size_t st=0; - static bool newl = FALSE; - static bool traced_data = FALSE; - - switch(type) { - case CURLINFO_HEADER_OUT: - for(i=0; i<size-1; i++) { - if(data[i] == '\n') { /* LF */ - if(!newl) { - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - } - (void)fwrite(data+st, i-st+1, 1, output); - st = i+1; - newl = FALSE; - } - } - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - (void)fwrite(data+st, i-st+1, 1, output); - newl = (bool)(size && (data[size-1] != '\n')); - traced_data = FALSE; - break; - case CURLINFO_TEXT: - case CURLINFO_HEADER_IN: - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - (void)fwrite(data, size, 1, output); - newl = (bool)(size && (data[size-1] != '\n')); - 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 != stderr) && (output != stdout))) { - if(!newl) - fprintf(output, "%s%s ", timebuf, s_infotype[type]); - fprintf(output, "[data not shown]\n"); - newl = FALSE; - traced_data = TRUE; - } - } - break; - default: /* nada */ - newl = FALSE; - traced_data = FALSE; - break; - } - - return 0; - } - -#ifdef CURL_DOES_CONVERSIONS - /* Special processing is needed for CURLINFO_HEADER_OUT blocks - * if they contain both headers and data (separated by CRLFCRLF). - * We dump the header text and then switch type to CURLINFO_DATA_OUT. - */ - if((type == CURLINFO_HEADER_OUT) && (size > 4)) { - size_t i; - for(i = 0; i < size - 4; i++) { - if(memcmp(&data[i], "\r\n\r\n", 4) == 0) { - /* dump everything through the CRLFCRLF as a sent header */ - text = "=> Send header"; - dump(timebuf, text, output, data, i+4, config->tracetype, type); - data += i + 3; - size -= i + 4; - type = CURLINFO_DATA_OUT; - data += 1; - break; - } - } - } -#endif /* CURL_DOES_CONVERSIONS */ - - switch (type) { - case CURLINFO_TEXT: - fprintf(output, "%s== Info: %s", timebuf, data); - 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, text, output, data, size, config->tracetype, type); - return 0; -} - -static void free_config_fields(struct Configurable *config) -{ - if(config->random_file) - free(config->random_file); - if(config->egd_file) - free(config->egd_file); - if(config->trace_dump) - free(config->trace_dump); - if(config->cipher_list) - free(config->cipher_list); - if(config->userpwd) - free(config->userpwd); - if(config->postfields) - free(config->postfields); - if(config->proxy) - free(config->proxy); - if(config->proxyuserpwd) - free(config->proxyuserpwd); - if(config->noproxy) - free(config->noproxy); - if(config->cookie) - free(config->cookie); - if(config->cookiefile) - free(config->cookiefile); - if(config->krblevel) - free(config->krblevel); - if(config->headerfile) - free(config->headerfile); - if(config->ftpport) - free(config->ftpport); - if(config->range) - free(config->range); - if(config->customrequest) - free(config->customrequest); - if(config->writeout) - free(config->writeout); - if(config->httppost) - curl_formfree(config->httppost); - if(config->netrc_file) - free(config->netrc_file); - if(config->cert) - free(config->cert); - if(config->cacert) - free(config->cacert); - if(config->cert_type) - free(config->cert_type); - if(config->capath) - free(config->capath); - if(config->crlfile) - free(config->crlfile); - if(config->cookiejar) - free(config->cookiejar); - if(config->ftp_account) - free(config->ftp_account); - if(config->ftp_alternative_to_user) - free(config->ftp_alternative_to_user); - if(config->iface) - free(config->iface); - if(config->socksproxy) - free(config->socksproxy); - if(config->libcurl) - free(config->libcurl); - if(config->key_passwd) - free(config->key_passwd); - if(config->key) - free(config->key); - if(config->key_type) - free(config->key_type); - if(config->pubkey) - free(config->pubkey); - if(config->referer) - free(config->referer); - if(config->hostpubmd5) - free(config->hostpubmd5); - if(config->mail_from) - free(config->mail_from); -#ifdef USE_TLS_SRP - if(config->tls_authtype) - free(config->tls_authtype); - if(config->tls_username) - free(config->tls_username); - if(config->tls_password) - free(config->tls_password); -#endif -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - if(config->socks5_gssapi_service) - free(config->socks5_gssapi_service); -#endif - - curl_slist_free_all(config->quote); /* checks for config->quote == NULL */ - curl_slist_free_all(config->prequote); - curl_slist_free_all(config->postquote); - curl_slist_free_all(config->headers); - curl_slist_free_all(config->telnet_options); - curl_slist_free_all(config->mail_rcpt); - curl_slist_free_all(config->resolve); - - if(config->easy) - curl_easy_cleanup(config->easy); -} - -#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% - */ -static void FindWin32CACert(struct Configurable *config, - const char *bundle_file) -{ - /* only check for cert file if "we" support SSL */ - if(curlinfo->features & CURL_VERSION_SSL) { - DWORD buflen; - char *ptr = NULL; - char *retval = malloc(sizeof (TCHAR) * (MAX_PATH + 1)); - if(!retval) - return; - retval[0] = '\0'; - buflen = SearchPathA(NULL, bundle_file, NULL, MAX_PATH+2, retval, &ptr); - if(buflen > 0) { - GetStr(&config->cacert, retval); - } - free(retval); - } -} - -#endif - -#define RETRY_SLEEP_DEFAULT 1000 /* ms */ -#define RETRY_SLEEP_MAX 600000 /* ms == 10 minutes */ - -static bool -output_expected(const char* url, const char* uploadfile) -{ - if(!uploadfile) - return TRUE; /* download */ - if(checkprefix("http://", url) || checkprefix("https://", url)) - return TRUE; /* HTTP(S) upload */ - - return FALSE; /* non-HTTP upload, probably no output should be expected */ -} - -#define my_setopt(x,y,z) _my_setopt(x, FALSE, config, #y, y, z) -#define my_setopt_str(x,y,z) _my_setopt(x, TRUE, config, #y, y, z) - -static struct curl_slist *easycode; -static struct curl_slist *easycode_remarks; - -static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config, - const char *name, CURLoption tag, ...); - -static CURLcode _my_setopt(CURL *curl, bool str, struct Configurable *config, - const char *name, CURLoption tag, ...) -{ - va_list arg; - CURLcode ret; - char *bufp; - char value[256]; - bool remark=FALSE; - bool skip=FALSE; - - va_start(arg, tag); - - if(tag < CURLOPTTYPE_OBJECTPOINT) { - long lval = va_arg(arg, long); - snprintf(value, sizeof(value), "%ldL", lval); - ret = curl_easy_setopt(curl, tag, lval); - if(!lval) - skip = TRUE; - } - else if(tag < CURLOPTTYPE_OFF_T) { - void *pval = va_arg(arg, void *); - unsigned char *ptr = (unsigned char *)pval; - - /* function pointers are never printable */ - if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { - if(pval) { - strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */ - remark = TRUE; - } - else - skip = TRUE; - } - - else if(pval && str) - snprintf(value, sizeof(value), "\"%s\"", (char *)ptr); - else if(pval) { - strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */ - remark = TRUE; - } - else - skip = TRUE; - - ret = curl_easy_setopt(curl, tag, pval); - - } - else { - curl_off_t oval = va_arg(arg, curl_off_t); - snprintf(value, sizeof(value), - "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); - ret = curl_easy_setopt(curl, tag, oval); - - if(!oval) - skip = TRUE; - } - - if(config->libcurl && !skip) { - /* we only use this for real if --libcurl was used */ - - if(remark) - bufp = curlx_maprintf("%s set to a %s", name, value); - else - bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value); - - if(!bufp) - ret = CURLE_OUT_OF_MEMORY; - else { - struct curl_slist *list = - curl_slist_append(remark?easycode_remarks:easycode, bufp); - - if(remark) - easycode_remarks = list; - else - easycode = list; - } - if(bufp) - curl_free(bufp); - } - va_end(arg); - - return ret; -} - -static const char * const srchead[]={ - "/********* Sample code generated by the curl command line tool **********", - " * All curl_easy_setopt() options are documented at:", - " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html", - " ************************************************************************/", - "#include <curl/curl.h>", - "", - "int main(int argc, char *argv[])", - "{", - " CURLcode ret;", - NULL -}; - -static void dumpeasycode(struct Configurable *config) -{ - struct curl_slist *ptr; - char *o = config->libcurl; - - if(o) { - FILE *out; - bool fopened = FALSE; - if(strcmp(o, "-")) { - out = fopen(o, "wt"); - fopened = TRUE; - } - else - out= stdout; - if(!out) - warnf(config, "Failed to open %s to write libcurl code!\n", o); - else { - int i; - const char *c; - - for(i=0; ((c = srchead[i]) != '\0'); i++) - fprintf(out, "%s\n", c); - - ptr = easycode; - while(ptr) { - fprintf(out, " %s\n", ptr->data); - ptr = ptr->next; - } - - ptr = easycode_remarks; - if(ptr) { - fprintf(out, - "\n /* Here is a list of options the curl code" - " used that cannot get generated\n" - " as source easily. You may select to either" - " not use them or implement\n them yourself.\n" - "\n"); - while(ptr) { - fprintf(out, " %s\n", ptr->data); - ptr = ptr->next; - } - fprintf(out, "\n */\n"); - } - - fprintf(out, - " return (int)ret;\n" - "}\n" - "/**** End of sample code ****/\n"); - if(fopened) - fclose(out); - } - } - curl_slist_free_all(easycode); -} - -static bool stdin_upload(const char *uploadfile) -{ - return (bool)(curlx_strequal(uploadfile, "-") || - curlx_strequal(uploadfile, ".")); -} - -/* Adds the file name to the URL if it doesn't already have one. - * url will be freed before return if the returned pointer is different - */ -static char *add_file_name_to_url(CURL *curl, char *url, const char *filename) -{ - /* If no file name part is given in the URL, we add this file name */ - char *ptr=strstr(url, "://"); - if(ptr) - ptr+=3; - else - ptr=url; - ptr = strrchr(ptr, '/'); - if(!ptr || !strlen(++ptr)) { - /* The URL has no file name part, add the local file name. In order - to be able to do so, we have to create a new URL in another - buffer.*/ - - /* We only want the part of the local path that is on the right - side of the rightmost slash and backslash. */ - const char *filep = strrchr(filename, '/'); - char *file2 = strrchr(filep?filep:filename, '\\'); - char *encfile; - - if(file2) - filep = file2+1; - else if(filep) - filep++; - else - filep = filename; - - /* URL encode the file name */ - encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); - if(encfile) { - char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3); - if(!urlbuffer) { - free(url); - return NULL; - } - if(ptr) - /* there is a trailing slash on the URL */ - sprintf(urlbuffer, "%s%s", url, encfile); - else - /* there is no trailing slash on the URL */ - sprintf(urlbuffer, "%s/%s", url, encfile); - - curl_free(encfile); - - free(url); - url = urlbuffer; /* use our new URL instead! */ - } - } - return url; -} - -/* Extracts the name portion of the URL. - * Returns a heap-allocated string, or NULL if no name part - */ -static char *get_url_file_name(const char *url) -{ - char *fn = NULL; - - /* Find and get the remote file name */ - const char * pc =strstr(url, "://"); - if(pc) - pc+=3; - else - pc=url; - pc = strrchr(pc, '/'); - - if(pc) { - /* duplicate the string beyond the slash */ - pc++; - fn = *pc ? strdup(pc): NULL; - } - return fn; -} - -static char* -parse_filename(char *ptr, size_t len) -{ - char* copy; - char* p; - char* q; - char quote = 0; - - /* simple implementation of strndup() */ - copy = malloc(len+1); - if(!copy) - return NULL; - strncpy(copy, ptr, len); - copy[len] = 0; - - p = copy; - if(*p == '\'' || *p == '"') { - /* store the starting quote */ - quote = *p; - p++; - } - - /* if the filename contains a path, only use filename portion */ - q = strrchr(copy, '/'); - if(q) { - p=q+1; - if(!*p) { - free(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) { - free(copy); - return NULL; - } - } - - if(quote) { - /* if the file name started with a quote, then scan for the end quote and - stop there */ - q = strrchr(p, quote); - if(q) - *q = 0; - } - else - q = NULL; /* no start quote, so no end has been found */ - - if(!q) { - /* 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); - - return copy; -} - -static size_t -header_callback(void *ptr, size_t size, size_t nmemb, void *stream) -{ - struct OutStruct* outs = (struct OutStruct*)stream; - const char* str = (char*)ptr; - const size_t cb = size*nmemb; - const char* end = (char*)ptr + cb; - size_t len; - - if(cb > 20 && checkprefix("Content-disposition:", str)) { - char *p = (char*)str + 20; - - /* look for the 'filename=' parameter - (encoded filenames (*=) are not supported) */ - for(;;) { - char *filename; - char *semi; - - while(*p && (p < end) && !ISALPHA(*p)) - p++; - if(p > end-9) - break; - - if(memcmp(p, "filename=", 9)) { - /* no match, find next parameter */ - while((p < end) && (*p != ';')) - p++; - continue; - } - p+=9; - semi = strchr(p, ';'); - - /* this expression below typecasts 'cb' only to avoid - warning: signed and unsigned type in conditional expression - */ - len = semi ? (semi - p) : (ssize_t)cb - (p - str); - filename = parse_filename(p, len); - if(filename) { - outs->filename = filename; - break; - } - } - } - - return cb; -} - -static int -operate(struct Configurable *config, int argc, argv_item_t argv[]) -{ - char errorbuffer[CURL_ERROR_SIZE]; - char useragent[256]; /* buah, we don't want a larger default user agent */ - struct ProgressData progressbar; - struct getout *urlnode; - struct getout *nextnode; - - struct OutStruct outs; - struct OutStruct heads; - struct InStruct input; - - URLGlob *urls=NULL; - URLGlob *inglob=NULL; - int urlnum; - int infilenum; - char *uploadfile=NULL; /* a single file, never a glob */ - - curl_off_t uploadfilesize; /* -1 means unknown */ - bool stillflags=TRUE; - - bool allocuseragent=FALSE; - - char *httpgetfields=NULL; - - CURL *curl; - int res = 0; - int i; - long retry_sleep_default; - long retry_sleep; - - char *env; - - memset(&heads, 0, sizeof(struct OutStruct)); - -#ifdef CURLDEBUG - /* this sends all memory debug messages to a logfile named memdump */ - env = curlx_getenv("CURL_MEMDEBUG"); - if(env) { - /* use the value as file name */ - char *s = strdup(env); - curl_free(env); - curl_memdebug(s); - free(s); - /* this weird strdup() and stuff here is to make the curl_free() get - called before the memdebug() as otherwise the memdebug tracing will - with tracing a free() without an alloc! */ - } - env = curlx_getenv("CURL_MEMLIMIT"); - if(env) { - char *endptr; - long num = strtol(env, &endptr, 10); - if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) - curl_memlimit(num); - curl_free(env); - } -#endif - - /* Initialize curl library - do not call any libcurl functions before. - Note that the CURLDEBUG magic above is an exception, but then that's not - part of the official public API. - */ - if(main_init() != CURLE_OK) { - helpf(config->errors, "error initializing curl library\n"); - return CURLE_FAILED_INIT; - } - - /* - * Get a curl handle to use for all forthcoming curl transfers. Cleanup - * when all transfers are done. - */ - curl = curl_easy_init(); - if(!curl) { - clean_getout(config); - return CURLE_FAILED_INIT; - } - config->easy = curl; - - memset(&outs,0,sizeof(outs)); - - config->outs = &outs; - - /* we get libcurl info right away */ - curlinfo = curl_version_info(CURLVERSION_NOW); - - errorbuffer[0]=0; /* prevent junk from being output */ - - /* setup proper locale from environment */ -#ifdef HAVE_SETLOCALE - setlocale(LC_ALL, ""); -#endif - - /* inits */ - config->postfieldsize = -1; - config->showerror=TRUE; - config->use_httpget=FALSE; - config->create_dirs=FALSE; - config->maxredirs = DEFAULT_MAXREDIRS; - config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */ - config->proto_present = FALSE; - config->proto_redir = - CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ - config->proto_redir_present = FALSE; - - if(argc>1 && - (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) && - strchr(argv[1], 'q')) { - /* - * The first flag, that is not a verbose name, but a shortname - * and it includes the 'q' flag! - */ - ; - } - else { - parseconfig(NULL, config); /* ignore possible failure */ - } - - if((argc < 2) && !config->url_list) { - helpf(config->errors, NULL); - return CURLE_FAILED_INIT; - } - - /* Parse options */ - for(i = 1; i < argc; i++) { - if(stillflags && - ('-' == argv[i][0])) { - char *nextarg; - bool passarg; - char *origopt=argv[i]; - - char *flag = argv[i]; - - if(curlx_strequal("--", argv[i])) - /* this indicates the end of the flags and thus enables the - following (URL) argument to start with -. */ - stillflags=FALSE; - else { - nextarg= (i < argc - 1)? argv[i+1]: NULL; - - res = getparameter(flag, nextarg, &passarg, config); - if(res) { - int retval = CURLE_OK; - if(res != PARAM_HELP_REQUESTED) { - const char *reason = param2text(res); - helpf(config->errors, "option %s: %s\n", origopt, reason); - retval = CURLE_FAILED_INIT; - } - clean_getout(config); - return retval; - } - - if(passarg) /* we're supposed to skip this */ - i++; - } - } - else { - bool used; - /* just add the URL please */ - res = getparameter((char *)"--url", argv[i], &used, config); - if(res) - return res; - } - } - - retry_sleep_default = config->retry_delay? - config->retry_delay*1000:RETRY_SLEEP_DEFAULT; /* ms */ - retry_sleep = retry_sleep_default; - - if((!config->url_list || !config->url_list->url) && !config->list_engines) { - clean_getout(config); - helpf(config->errors, "no URL specified!\n"); - return CURLE_FAILED_INIT; - } - if(NULL == config->useragent) { - /* set non-zero default values: */ - snprintf(useragent, sizeof(useragent), - CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version()); - config->useragent= useragent; - } - else - allocuseragent = TRUE; - - /* On WIN32 we can't set the path to curl-ca-bundle.crt - * at compile time. So we look here for the file in two ways: - * 1: look at the environment variable CURL_CA_BUNDLE for a path - * 2: if #1 isn't found, use the windows API function SearchPath() - * to find it along the app's path (includes app's dir and CWD) - * - * We support the environment variable thing for non-Windows platforms - * too. Just for the sake of it. - */ - if(!config->cacert && - !config->capath && - !config->insecure_ok) { - env = curlx_getenv("CURL_CA_BUNDLE"); - if(env) - GetStr(&config->cacert, env); - else { - env = curlx_getenv("SSL_CERT_DIR"); - if(env) - GetStr(&config->capath, env); - else { - env = curlx_getenv("SSL_CERT_FILE"); - if(env) - GetStr(&config->cacert, env); - } - } - - if(env) - curl_free(env); -#ifdef WIN32 - else - FindWin32CACert(config, "curl-ca-bundle.crt"); -#endif - } - - if(config->postfields) { - if(config->use_httpget) { - /* Use the postfields data for a http get */ - httpgetfields = strdup(config->postfields); - free(config->postfields); - config->postfields = NULL; - if(SetHTTPrequest(config, - (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), - &config->httpreq)) { - free(httpgetfields); - return PARAM_BAD_USE; - } - } - else { - if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) - return PARAM_BAD_USE; - } - } - - /* This is the first entry added to easycode and it initializes the slist */ - easycode = curl_slist_append(easycode, "CURL *hnd = curl_easy_init();"); - if(!easycode) { - clean_getout(config); - res = CURLE_OUT_OF_MEMORY; - goto quit_curl; - } - - if(config->list_engines) { - struct curl_slist *engines = NULL; - - curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); - list_engines(engines); - curl_slist_free_all(engines); - res = CURLE_OK; - goto quit_curl; - } - - /* After this point, we should call curl_easy_cleanup() if we decide to bail - * out from this function! */ - - urlnode = config->url_list; - - if(config->headerfile) { - /* open file for output: */ - if(strcmp(config->headerfile,"-")) { - heads.filename = config->headerfile; - } - else - heads.stream=stdout; - heads.config = config; - } - - /* loop through the list of given URLs */ - while(urlnode) { - int up; /* upload file counter within a single upload glob */ - char *dourl; - char *url; - char *infiles; /* might be a glob pattern */ - char *outfiles=NULL; - - /* get the full URL (it might be NULL) */ - dourl=urlnode->url; - - url = dourl; - - if(NULL == url) { - /* This node had no URL, skip it and continue to the next */ - if(urlnode->outfile) - free(urlnode->outfile); - - /* move on to the next URL */ - nextnode=urlnode->next; - free(urlnode); /* free the node */ - urlnode = nextnode; - continue; /* next please */ - } - - /* default output stream is stdout */ - outs.stream = stdout; - outs.config = config; - outs.bytes = 0; /* nothing written yet */ - - /* save outfile pattern before expansion */ - if(urlnode->outfile) { - outfiles = strdup(urlnode->outfile); - if(!outfiles) { - clean_getout(config); - break; - } - } - - infiles = urlnode->infile; - - if(!config->globoff && infiles) { - /* Unless explicitly shut off */ - res = glob_url(&inglob, infiles, &infilenum, - config->showerror?config->errors:NULL); - if(res != CURLE_OK) { - clean_getout(config); - if(outfiles) - free(outfiles); - break; - } - } - - /* Here's the loop for uploading multiple files within the same - single globbed string. If no upload, we enter the loop once anyway. */ - for(up = 0; - (!up && !infiles) || - ((uploadfile = inglob? - glob_next_url(inglob): - (!up?strdup(infiles):NULL)) != NULL); - up++) { - int separator = 0; - long retry_numretries; - uploadfilesize=-1; - - if(!config->globoff) { - /* Unless explicitly shut off, we expand '{...}' and '[...]' - expressions and return total number of URLs in pattern set */ - res = glob_url(&urls, dourl, &urlnum, - config->showerror?config->errors:NULL); - if(res != CURLE_OK) { - break; - } - } - else - urlnum = 1; /* without globbing, this is a single URL */ - - /* if multiple files extracted to stdout, insert separators! */ - separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1); - - /* Here's looping around each globbed URL */ - for(i = 0; - ((url = urls?glob_next_url(urls):(i?NULL:strdup(url))) != NULL); - i++) { - /* NOTE: In the condition expression in the for() statement above, the - 'url' variable is only ever strdup()ed if(i == 0) and thus never - when this loops later on. Further down in this function we call - free(url) and then the code loops. Static code parsers may thus get - tricked into believing that we have a potential access-after-free - here. I can however not spot any such case. */ - - int infd = STDIN_FILENO; - bool infdopen; - char *outfile; - struct timeval retrystart; - outfile = outfiles?strdup(outfiles):NULL; - - if((urlnode->flags&GETOUT_USEREMOTE) || - (outfile && !curlx_strequal("-", outfile)) ) { - - /* - * We have specified a file name to store the result in, or we have - * decided we want to use the remote file name. - */ - - if(!outfile) { - /* extract the file name from the URL */ - outfile = get_url_file_name(url); - if((!outfile || !*outfile) && !config->content_disposition) { - helpf(config->errors, "Remote file name has no length!\n"); - res = CURLE_WRITE_ERROR; - free(url); - break; - } -#if defined(MSDOS) || defined(WIN32) - /* For DOS and WIN32, we do some major replacing of - bad characters in the file name before using it */ - outfile = sanitize_dos_name(outfile); - if(!outfile) { - res = CURLE_OUT_OF_MEMORY; - break; - } -#endif /* MSDOS || WIN32 */ - } - else if(urls) { - /* fill '#1' ... '#9' terms from URL pattern */ - char *storefile = outfile; - outfile = glob_match_url(storefile, urls); - free(storefile); - if(!outfile) { - /* bad globbing */ - warnf(config, "bad output glob!\n"); - free(url); - res = CURLE_FAILED_INIT; - break; - } - } - - /* Create the directory hierarchy, if not pre-existent to a multiple - file output call */ - - if(config->create_dirs && - (-1 == create_dir_hierarchy(outfile, config->errors))) { - free(url); - res = CURLE_WRITE_ERROR; - break; - } - - if(config->resume_from_current) { - /* We're told to continue from where we are now. Get the - size of the file as it is now and open it for append instead */ - - struct_stat fileinfo; - - /* VMS -- Danger, the filesize is only valid for stream files */ - if(0 == stat(outfile, &fileinfo)) - /* set offset to current file size: */ - config->resume_from = fileinfo.st_size; - else - /* let offset be 0 */ - config->resume_from = 0; - } - - outs.filename = outfile; - - if(config->resume_from) { - outs.init = config->resume_from; - /* open file for output: */ - outs.stream=(FILE *) fopen(outfile, config->resume_from?"ab":"wb"); - if(!outs.stream) { - helpf(config->errors, "Can't open '%s'!\n", outfile); - free(url); - res = CURLE_WRITE_ERROR; - break; - } - } - else { - outs.stream = NULL; /* open when needed */ - outs.bytes = 0; /* reset byte counter */ - } - } - infdopen=FALSE; - if(uploadfile && !stdin_upload(uploadfile)) { - /* - * We have specified a file to upload and it isn't "-". - */ - struct_stat fileinfo; - - url = add_file_name_to_url(curl, url, uploadfile); - if(!url) { - helpf(config->errors, "out of memory\n"); - res = CURLE_OUT_OF_MEMORY; - break; - } - /* VMS Note: - * - * Reading binary from files can be a problem... Only FIXED, VAR - * etc WITHOUT implied CC will work Others need a \n appended to a - * line - * - * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a - * fixed file with implied CC needs to have a byte added for every - * record processed, this can by derived from Filesize & recordsize - * for VARiable record files the records need to be counted! for - * every record add 1 for linefeed and subtract 2 for the record - * header for VARIABLE header files only the bare record data needs - * to be considered with one appended if implied CC - */ - - infd= open(uploadfile, O_RDONLY | O_BINARY); - if((infd == -1) || fstat(infd, &fileinfo)) { - helpf(config->errors, "Can't open '%s'!\n", uploadfile); - if(infd != -1) - close(infd); - - /* Free the list of remaining URLs and globbed upload files - * to force curl to exit immediately - */ - if(urls) { - glob_cleanup(urls); - urls = NULL; - } - if(inglob) { - glob_cleanup(inglob); - inglob = NULL; - } - - res = CURLE_READ_ERROR; - goto quit_urls; - } - infdopen=TRUE; - - /* we ignore file size for char/block devices, sockets, etc. */ - if(S_ISREG(fileinfo.st_mode)) - uploadfilesize=fileinfo.st_size; - - } - else if(uploadfile && stdin_upload(uploadfile)) { - /* count to see if there are more than one auth bit set - in the authtype field */ - int authbits = 0; - int bitcheck = 0; - while(bitcheck < 32) { - if(config->authtype & (1 << bitcheck++)) { - authbits++; - if(authbits > 1) { - /* more than one, we're done! */ - break; - } - } - } - - /* - * If the user has also selected --anyauth or --proxy-anyauth - * we should warn him/her. - */ - if(config->proxyanyauth || (authbits>1)) { - warnf(config, - "Using --anyauth or --proxy-anyauth with upload from stdin" - " involves a big risk of it not working. Use a temporary" - " file or a fixed auth type instead!\n"); - } - - SET_BINMODE(stdin); - infd = STDIN_FILENO; - if(curlx_strequal(uploadfile, ".")) { - if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0) - warnf(config, - "fcntl failed on fd=%d: %s\n", infd, strerror(errno)); - } - } - - if(uploadfile && config->resume_from_current) - config->resume_from = -1; /* -1 will then force get-it-yourself */ - - if(output_expected(url, uploadfile) - && outs.stream && isatty(fileno(outs.stream))) - /* we send the output to a tty, therefore we switch off the progress - meter */ - config->noprogress = config->isatty = TRUE; - - if(urlnum > 1 && !(config->mute)) { - fprintf(config->errors, "\n[%d/%d]: %s --> %s\n", - i+1, urlnum, url, outfile ? outfile : "<stdout>"); - if(separator) - printf("%s%s\n", CURLseparator, url); - } - if(httpgetfields) { - char *urlbuffer; - /* Find out whether the url contains a file name */ - const char *pc =strstr(url, "://"); - char sep='?'; - if(pc) - pc+=3; - else - pc=url; - - pc = strrchr(pc, '/'); /* check for a slash */ - - if(pc) { - /* there is a slash present in the URL */ - - if(strchr(pc, '?')) - /* Ouch, there's already a question mark in the URL string, we - then append the data with an ampersand separator instead! */ - sep='&'; - } - /* - * Then append ? followed by the get fields to the url. - */ - urlbuffer = malloc(strlen(url) + strlen(httpgetfields) + 3); - if(!urlbuffer) { - helpf(config->errors, "out of memory\n"); - - /* Free the list of remaining URLs and globbed upload files - * to force curl to exit immediately - */ - if(urls) { - glob_cleanup(urls); - urls = NULL; - } - if(inglob) { - glob_cleanup(inglob); - inglob = NULL; - } - - res = CURLE_OUT_OF_MEMORY; - goto quit_urls; - } - if(pc) - sprintf(urlbuffer, "%s%c%s", url, sep, httpgetfields); - else - /* Append / before the ? to create a well-formed url - if the url contains a hostname only - */ - sprintf(urlbuffer, "%s/?%s", url, httpgetfields); - - free(url); /* free previous URL */ - url = urlbuffer; /* use our new URL instead! */ - } - - if(!config->errors) - config->errors = stderr; - - if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) { - /* We get the output to stdout and we have not got the ASCII/text - flag, then set stdout to be binary */ - SET_BINMODE(stdout); - } - - if(1 == config->tcp_nodelay) - my_setopt(curl, CURLOPT_TCP_NODELAY, 1); - - /* where to store */ - my_setopt(curl, CURLOPT_WRITEDATA, &outs); - /* what call to write */ - my_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite); - - /* for uploads */ - input.fd = infd; - input.config = config; - my_setopt(curl, CURLOPT_READDATA, &input); - /* what call to read */ - if((outfile && !curlx_strequal("-", outfile)) || - !checkprefix("telnet:", url)) - my_setopt(curl, CURLOPT_READFUNCTION, my_fread); - - /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what - CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ - my_setopt(curl, CURLOPT_SEEKDATA, &input); - my_setopt(curl, CURLOPT_SEEKFUNCTION, my_seek); - - if(config->recvpersecond) - /* tell libcurl to use a smaller sized buffer as it allows us to - make better sleeps! 7.9.9 stuff! */ - my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond); - - /* size of uploaded file: */ - if(uploadfilesize != -1) - my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); - my_setopt_str(curl, CURLOPT_URL, url); /* what to fetch */ - my_setopt_str(curl, CURLOPT_PROXY, config->proxy); /* proxy to use */ - if(config->proxy) - my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver); - my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress); - if(config->no_body) { - my_setopt(curl, CURLOPT_NOBODY, 1); - my_setopt(curl, CURLOPT_HEADER, 1); - } - else - my_setopt(curl, CURLOPT_HEADER, config->include_headers); - - my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror); - my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE); - my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly); - my_setopt(curl, CURLOPT_APPEND, config->ftp_append); - - if(config->netrc_opt) - my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); - else if(config->netrc || config->netrc_file) - my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED); - else - my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED); - - if(config->netrc_file) - my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file); - - my_setopt(curl, CURLOPT_FOLLOWLOCATION, config->followlocation); - my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, config->unrestricted_auth); - my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii); - my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); - my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); - my_setopt(curl, CURLOPT_NOPROXY, config->noproxy); - my_setopt_str(curl, CURLOPT_RANGE, config->range); - my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); - my_setopt(curl, CURLOPT_TIMEOUT, config->timeout); - - switch(config->httpreq) { - case HTTPREQ_SIMPLEPOST: - my_setopt_str(curl, CURLOPT_POSTFIELDS, config->postfields); - my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, config->postfieldsize); - break; - case HTTPREQ_POST: - my_setopt(curl, CURLOPT_HTTPPOST, config->httppost); - break; - default: - break; - } - my_setopt_str(curl, CURLOPT_REFERER, config->referer); - my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer); - my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); - my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); - my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, - config->low_speed_limit); - my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); - my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, - config->sendpersecond); - my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, - config->recvpersecond); - my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, - config->use_resume?config->resume_from:0); - my_setopt_str(curl, CURLOPT_COOKIE, config->cookie); - my_setopt(curl, CURLOPT_HTTPHEADER, config->headers); - my_setopt(curl, CURLOPT_SSLCERT, config->cert); - my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); - my_setopt(curl, CURLOPT_SSLKEY, config->key); - my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); - my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); - - /* SSH private key uses the same command-line option as SSL private - key */ - my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); - my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); - - /* SSH host key md5 checking allows us to fail if we are - * not talking to who we think we should - */ - my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, - config->hostpubmd5); - - /* default to strict verifyhost */ - /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2); */ - if(config->cacert || config->capath) { - if(config->cacert) - my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); - - if(config->capath) - my_setopt_str(curl, CURLOPT_CAPATH, config->capath); - my_setopt(curl, CURLOPT_SSL_VERIFYPEER, TRUE); - } - if(config->crlfile) - my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); - if(config->insecure_ok) { - /* new stuff needed for libcurl 7.10 */ - my_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE); - my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1); - } - else { - char *home = homedir(); - char *file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR); - if(home) - free(home); - - if(file) { - my_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file); - curl_free(file); - } - else { - /* Free the list of remaining URLs and globbed upload files - * to force curl to exit immediately - */ - if(urls) { - glob_cleanup(urls); - urls = NULL; - } - if(inglob) { - glob_cleanup(inglob); - inglob = NULL; - } - - res = CURLE_OUT_OF_MEMORY; - goto quit_urls; - } - } - - if(config->no_body || config->remote_time) { - /* no body or use remote time */ - my_setopt(curl, CURLOPT_FILETIME, TRUE); - } - - my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); - my_setopt(curl, CURLOPT_CRLF, config->crlf); - my_setopt(curl, CURLOPT_QUOTE, config->quote); - my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote); - my_setopt(curl, CURLOPT_PREQUOTE, config->prequote); - my_setopt(curl, CURLOPT_HEADERDATA, - config->headerfile?&heads:NULL); - my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile); - /* cookie jar was added in 7.9 */ - if(config->cookiejar) - my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); - /* cookie session added in 7.9.7 */ - my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession); - - my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version); - my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond); - my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime); - my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); - my_setopt(curl, CURLOPT_STDERR, config->errors); - - /* three new ones in libcurl 7.3: */ - my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel); - my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); - my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); - - progressbarinit(&progressbar, config); - if((config->progressmode == CURL_PROGRESS_BAR) && - !config->noprogress && !config->mute) { - /* we want the alternative style, then we have to implement it - ourselves! */ - my_setopt(curl, CURLOPT_PROGRESSFUNCTION, myprogress); - my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar); - } - - /* new in libcurl 7.6.2: */ - my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); - - /* new in libcurl 7.7: */ - my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file); - my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file); - my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout); - - if(config->cipher_list) - my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); - - if(config->httpversion) - my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion); - - /* new in libcurl 7.9.2: */ - if(config->disable_epsv) - /* disable it */ - my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE); - - /* new in libcurl 7.10.5 */ - if(config->disable_eprt) - /* disable it */ - my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE); - - /* new in libcurl 7.10.6 (default is Basic) */ - if(config->authtype) - my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype); - - if(config->tracetype != TRACE_NONE) { - my_setopt(curl, CURLOPT_DEBUGFUNCTION, my_trace); - my_setopt(curl, CURLOPT_DEBUGDATA, config); - my_setopt(curl, CURLOPT_VERBOSE, TRUE); - } - - res = CURLE_OK; - - /* new in curl ?? */ - if(config->engine) { - res = my_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); - my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1); - } - - if(res != CURLE_OK) - goto show_error; - - if(config->encoding) - my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); - - if(config->tr_encoding) - my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1); - - /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */ - my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, - config->ftp_create_dirs); - if(config->proxyanyauth) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); - else if(config->proxynegotiate) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); - else if(config->proxyntlm) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); - else if(config->proxydigest) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); - else if(config->proxybasic) - my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); - - /* new in curl 7.10.8 */ - if(config->max_filesize) - my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, - config->max_filesize); - - if(4 == config->ip_version) - my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); - else if(6 == config->ip_version) - my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); - else - my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); - - /* new in curl 7.15.5 */ - if(config->ftp_ssl_reqd) - my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); - - /* new in curl 7.11.0 */ - else if(config->ftp_ssl) - my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); - - /* new in curl 7.16.0 */ - else if(config->ftp_ssl_control) - my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); - - /* new in curl 7.16.1 */ - if(config->ftp_ssl_ccc) - my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); - - /* new in curl 7.11.1, modified in 7.15.2 */ - if(config->socksproxy) { - my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy); - my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver); - } - -#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) - /* new in curl 7.19.4 */ - if(config->socks5_gssapi_service) - my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, - config->socks5_gssapi_service); - - /* new in curl 7.19.4 */ - if(config->socks5_gssapi_nec) - my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, - config->socks5_gssapi_nec); -#endif - /* curl 7.13.0 */ - my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); - - my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl); - - /* curl 7.14.2 */ - my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip); - - /* curl 7.15.1 */ - my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod); - - /* curl 7.15.2 */ - if(config->localport) { - my_setopt(curl, CURLOPT_LOCALPORT, config->localport); - my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, - config->localportrange); - } - - /* curl 7.15.5 */ - my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, - config->ftp_alternative_to_user); - - /* curl 7.16.0 */ - if(config->disable_sessionid) - my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, - !config->disable_sessionid); - - /* curl 7.16.2 */ - if(config->raw) { - my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE); - my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE); - } - - /* curl 7.17.1 */ - if(!config->nokeepalive) { - my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, sockoptcallback); - my_setopt(curl, CURLOPT_SOCKOPTDATA, config); - } - - /* curl 7.19.1 (the 301 version existed in 7.18.2) */ - my_setopt(curl, CURLOPT_POSTREDIR, config->post301 | - (config->post302 ? CURL_REDIR_POST_302 : FALSE)); - - /* curl 7.20.0 */ - if(config->tftp_blksize) - my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); - - if(config->mail_from) - my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); - - if(config->mail_rcpt) - my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); - - /* curl 7.20.x */ - if(config->ftp_pret) - my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE); - - if(config->proto_present) - my_setopt(curl, CURLOPT_PROTOCOLS, config->proto); - if(config->proto_redir_present) - my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); - - if((urlnode->flags & GETOUT_USEREMOTE) - && config->content_disposition) { - my_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); - my_setopt(curl, CURLOPT_HEADERDATA, &outs); - } - - if(config->resolve) - /* new in 7.21.3 */ - my_setopt(curl, CURLOPT_RESOLVE, config->resolve); - - /* TODO: new in ### */ - curl_easy_setopt(curl, CURLOPT_TLSAUTH_USERNAME, config->tls_username); - curl_easy_setopt(curl, CURLOPT_TLSAUTH_PASSWORD, config->tls_password); - - retry_numretries = config->req_retry; - - retrystart = cutil_tvnow(); - - for(;;) { - res = curl_easy_perform(curl); - if(!curl_slist_append(easycode, "ret = curl_easy_perform(hnd);")) { - res = CURLE_OUT_OF_MEMORY; - break; - } - - if(config->content_disposition && outs.stream && !config->mute && - outs.filename) - printf("curl: Saved to filename '%s'\n", outs.filename); - - /* if retry-max-time is non-zero, make sure we haven't exceeded the - time */ - if(retry_numretries && - (!config->retry_maxtime || - (cutil_tvdiff(cutil_tvnow(), retrystart)< - config->retry_maxtime*1000)) ) { - enum { - RETRY_NO, - RETRY_TIMEOUT, - RETRY_HTTP, - RETRY_FTP, - RETRY_LAST /* not used */ - } retry = RETRY_NO; - long response; - if(CURLE_OPERATION_TIMEDOUT == res) - /* retry timeout always */ - retry = RETRY_TIMEOUT; - else if((CURLE_OK == res) || - (config->failonerror && - (CURLE_HTTP_RETURNED_ERROR == res))) { - /* If it returned OK. _or_ failonerror was enabled and it - returned due to such an error, check for HTTP transient - errors to retry on. */ - char *this_url=NULL; - curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &this_url); - if(this_url && - checkprefix("http", this_url)) { - /* This was HTTP(S) */ - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); - - switch(response) { - case 500: /* Internal Server Error */ - case 502: /* Bad Gateway */ - case 503: /* Service Unavailable */ - case 504: /* Gateway Timeout */ - retry = RETRY_HTTP; - /* - * At this point, we have already written data to the output - * file (or terminal). If we write to a file, we must rewind - * or close/re-open the file so that the next attempt starts - * over from the beginning. - * - * TODO: similar action for the upload case. We might need - * to start over reading from a previous point if we have - * uploaded something when this was returned. - */ - break; - } - } - } /* if CURLE_OK */ - else if(res) { - curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); - - if(response/100 == 4) - /* - * This is typically when the FTP server only allows a certain - * amount of users and we are not one of them. All 4xx codes - * are transient. - */ - retry = RETRY_FTP; - } - - if(retry) { - static const char * const m[]={ - NULL, "timeout", "HTTP error", "FTP error" - }; - warnf(config, "Transient problem: %s " - "Will retry in %ld seconds. " - "%ld retries left.\n", - m[retry], retry_sleep/1000, retry_numretries); - - go_sleep(retry_sleep); - retry_numretries--; - if(!config->retry_delay) { - retry_sleep *= 2; - if(retry_sleep > RETRY_SLEEP_MAX) - retry_sleep = RETRY_SLEEP_MAX; - } - if(outs.bytes && outs.filename) { - /* We have written data to a output file, we truncate file - */ - if(!config->mute) - fprintf(config->errors, "Throwing away %" - CURL_FORMAT_CURL_OFF_T " bytes\n", - outs.bytes); - fflush(outs.stream); - /* truncate file at the position where we started appending */ -#ifdef HAVE_FTRUNCATE - if(ftruncate( fileno(outs.stream), outs.init)) { - /* when truncate fails, we can't just append as then we'll - create something strange, bail out */ - if(!config->mute) - fprintf(config->errors, - "failed to truncate, exiting\n"); - break; - } - /* now seek to the end of the file, the position where we - just truncated the file in a large file-safe way */ - fseek(outs.stream, 0, SEEK_END); -#else - /* ftruncate is not available, so just reposition the file - to the location we would have truncated it. This won't - work properly with large files on 32-bit systems, but - most of those will have ftruncate. */ - fseek(outs.stream, (long)outs.init, SEEK_SET); -#endif - outs.bytes = 0; /* clear for next round */ - } - continue; - } - } /* if retry_numretries */ - - /* In all ordinary cases, just break out of loop here */ - retry_sleep = retry_sleep_default; - break; - - } - - if((config->progressmode == CURL_PROGRESS_BAR) && - progressbar.calls) - /* if the custom progress bar has been displayed, we output a - newline here */ - fputs("\n", progressbar.out); - - if(config->writeout) - ourWriteOut(curl, config->writeout); -#ifdef USE_ENVIRONMENT - if(config->writeenv) - ourWriteEnv(curl); -#endif - - show_error: - -#ifdef __VMS - if(is_vms_shell()) { - /* VMS DCL shell behavior */ - if(!config->showerror) { - vms_show = VMSSTS_HIDE; - } - } - else -#endif - { - if((res!=CURLE_OK) && config->showerror) { - fprintf(config->errors, "curl: (%d) %s\n", res, - errorbuffer[0]? errorbuffer: - curl_easy_strerror((CURLcode)res)); - if(CURLE_SSL_CACERT == res) { - fprintf(config->errors, "%s%s", - CURL_CA_CERT_ERRORMSG1, - CURL_CA_CERT_ERRORMSG2 ); - } - } - } - if(outfile && !curlx_strequal(outfile, "-") && outs.stream) { - int rc; - - if(config->xattr) { - rc = fwrite_xattr(curl, fileno(outs.stream) ); - if(rc) - warnf(config, "Error setting extended attributes: %s\n", - strerror(errno) ); - } - - rc = fclose(outs.stream); - if(!res && rc) { - /* something went wrong in the writing process */ - res = CURLE_WRITE_ERROR; - fprintf(config->errors, "(%d) Failed writing body\n", res); - } - } - -#ifdef HAVE_UTIME - /* Important that we set the time _after_ the file has been - closed, as is done above here */ - if(config->remote_time && outs.filename) { - /* ask libcurl if we got a time. Pretty please */ - long filetime; - curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); - if(filetime >= 0) { - struct utimbuf times; - times.actime = (time_t)filetime; - times.modtime = (time_t)filetime; - utime(outs.filename, ×); /* set the time we got */ - } - } -#endif -#ifdef __AMIGA__ - /* Set the url as comment for the file. (up to 80 chars are allowed) - */ - if(strlen(url) > 78) - url[79] = '\0'; - - SetComment( outs.filename, url); -#endif - - quit_urls: - if(url) - free(url); - - if(outfile) - free(outfile); - - if(infdopen) - close(infd); - - } /* loop to the next URL */ - - if(urls) { - /* cleanup memory used for URL globbing patterns */ - glob_cleanup(urls); - urls = NULL; - } - - if(uploadfile) - free(uploadfile); - - } /* loop to the next globbed upload file */ - - if(inglob) { - glob_cleanup(inglob); - inglob = NULL; - } - - if(outfiles) - free(outfiles); - - /* empty this urlnode struct */ - if(urlnode->url) - free(urlnode->url); - if(urlnode->outfile) - free(urlnode->outfile); - if(urlnode->infile) - free(urlnode->infile); - - /* move on to the next URL */ - nextnode=urlnode->next; - free(urlnode); /* free the node */ - urlnode = nextnode; - - } /* while-loop through all URLs */ - - quit_curl: - if(httpgetfields) - free(httpgetfields); - - if(config->engine) - free(config->engine); - - /* cleanup the curl handle! */ - curl_easy_cleanup(curl); - config->easy = NULL; /* cleanup now */ - if(easycode) - curl_slist_append(easycode, "curl_easy_cleanup(hnd);"); - - if(heads.stream && (heads.stream != stdout)) - fclose(heads.stream); - - if(allocuseragent) - free(config->useragent); - - if(config->trace_fopened && config->trace_stream) - fclose(config->trace_stream); - - /* Dump the libcurl code if previously enabled. - NOTE: that this function relies on config->errors amongst other things - so not everything can be closed and cleaned before this is called */ - dumpeasycode(config); - - if(config->errors_fopened) - fclose(config->errors); - - main_free(); /* cleanup */ - - return res; -} - -/* Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are - open before starting to run. Otherwise, the first three network - sockets opened by curl could be used for input sources, downloaded data - or error logs as they will effectively be stdin, stdout and/or stderr. -*/ -static void checkfds(void) -{ -#ifdef HAVE_PIPE - int fd[2] = { STDIN_FILENO, STDIN_FILENO }; - while(fd[0] == STDIN_FILENO || - fd[0] == STDOUT_FILENO || - fd[0] == STDERR_FILENO || - fd[1] == STDIN_FILENO || - fd[1] == STDOUT_FILENO || - fd[1] == STDERR_FILENO) - if(pipe(fd) < 0) - return; /* Out of handles. This isn't really a big problem now, but - will be when we try to create a socket later. */ - close(fd[0]); - close(fd[1]); -#endif -} - - - -int main(int argc, char *argv[]) -{ - int res; - struct Configurable config; - - memset(&config, 0, sizeof(struct Configurable)); - - config.errors = stderr; /* default errors to stderr */ - - checkfds(); - - res = operate(&config, argc, argv); -#ifdef __SYMBIAN32__ - if(config.showerror) - pressanykey(); -#endif - free_config_fields(&config); - -#ifdef __NOVELL_LIBC__ - if(getenv("_IN_NETWARE_BASH_") == NULL) - pressanykey(); -#endif -#ifdef __VMS - vms_special_exit(res, vms_show); -#else - return res; -#endif -} - -/* - * Reads a line from the given file, ensuring is NUL terminated. - * The pointer must be freed by the caller. - * NULL is returned on an out of memory condition. - */ -static char *my_get_line(FILE *fp) -{ - char buf[4096]; - char *nl = NULL; - char *retval = NULL; - - do { - if(NULL == fgets(buf, sizeof(buf), fp)) - break; - if(NULL == retval) { - retval = strdup(buf); - if(!retval) - return NULL; - } - else { - char *ptr; - ptr = realloc(retval, strlen(retval) + strlen(buf) + 1); - if(NULL == ptr) { - free(retval); - return NULL; - } - retval = ptr; - strcat(retval, buf); - } - } - while(NULL == (nl = strchr(retval, '\n'))); - - if(NULL != nl) - *nl = '\0'; - - return retval; -} - -static void show_dir_errno(FILE *errors, const char *name) -{ - switch (ERRNO) { -#ifdef EACCES - case EACCES: - fprintf(errors,"You don't have permission to create %s.\n", name); - break; -#endif -#ifdef ENAMETOOLONG - case ENAMETOOLONG: - fprintf(errors,"The directory name %s is too long.\n", name); - break; -#endif -#ifdef EROFS - case EROFS: - fprintf(errors,"%s resides on a read-only file system.\n", name); - break; -#endif -#ifdef ENOSPC - case ENOSPC: - fprintf(errors,"No space left on the file system that will " - "contain the directory %s.\n", name); - break; -#endif -#ifdef EDQUOT - case EDQUOT: - fprintf(errors,"Cannot create directory %s because you " - "exceeded your quota.\n", name); - break; -#endif - default : - fprintf(errors,"Error creating directory %s.\n", name); - break; - } -} - -/* Create the needed directory hierarchy recursively in order to save - multi-GETs in file output, ie: - curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" - should create all the dir* automagically -*/ -static int create_dir_hierarchy(const char *outfile, FILE *errors) -{ - char *tempdir; - char *tempdir2; - char *outdup; - char *dirbuildup; - int result=0; - - outdup = strdup(outfile); - if(!outdup) - return -1; - - dirbuildup = malloc(sizeof(char) * strlen(outfile)); - if(!dirbuildup) { - free(outdup); - return -1; - } - dirbuildup[0] = '\0'; - - tempdir = strtok(outdup, DIR_CHAR); - - while(tempdir != NULL) { - tempdir2 = strtok(NULL, DIR_CHAR); - /* since strtok returns a token for the last word even - if not ending with DIR_CHAR, we need to prune it */ - if(tempdir2 != NULL) { - size_t dlen = strlen(dirbuildup); - if(dlen) - sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir); - else { - if(0 != strncmp(outdup, DIR_CHAR, 1)) - strcpy(dirbuildup, tempdir); - else - sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir); - } - if(access(dirbuildup, F_OK) == -1) { - result = mkdir(dirbuildup,(mode_t)0000750); - if(-1 == result) { - show_dir_errno(errors, dirbuildup); - break; /* get out of loop */ - } - } - } - tempdir = tempdir2; - } - free(dirbuildup); - free(outdup); - - return result; /* 0 is fine, -1 is badness */ -} - -#if defined(MSDOS) || defined(WIN32) - -#ifndef HAVE_BASENAME -/* basename() returns a pointer to the last component of a pathname. - * Ripped from lib/formdata.c. - */ -static char *Curl_basename(char *path) -{ - /* Ignore all the details above for now and make a quick and simple - implementaion 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 /* HAVE_BASENAME */ - -/* The following functions are taken with modification from the DJGPP - * port of tar 1.12. They use algorithms originally from DJTAR. */ - -static const char * -msdosify (const char *file_name) -{ - static 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; - - /* 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++ = *s++; - } - - for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { - if(memchr (illegal_aliens, *s, len)) { - /* 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. */ - if(*s == '.') { - if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) { - /* Copy "./" and "../" verbatim. */ - *d++ = *s++; - if(*s == '.') - *d++ = *s++; - *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'; - *d = 'x'; - } - else { - /* libg++ etc. */ - memcpy (d, "plus", 4); - d += 3; - } - s++; - idx++; - } - else - *d = '_'; - } - else - *d = *s; - if(*s == '/') { - idx = 0; - dot_idx = -1; - } - else - idx++; - } - - *d = '\0'; - return dos_name; -} - -static char * -rename_if_dos_device_name (char *file_name) -{ - /* 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 *base; - struct_stat st_buf; - char fname[PATH_MAX]; - - strncpy(fname, file_name, PATH_MAX-1); - fname[PATH_MAX-1] = 0; - base = basename(fname); - if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { - size_t blen = strlen (base); - - if(strlen(fname) >= PATH_MAX-1) { - /* Make room for the '_' */ - blen--; - base[blen] = 0; - } - /* Prepend a '_'. */ - memmove (base + 1, base, blen + 1); - base[0] = '_'; - strcpy (file_name, fname); - } - return file_name; -} - -/* Replace bad characters in the file name before using it. - * fn will always be freed before return - * The returned pointer must be freed by the caller if not NULL - */ -static char *sanitize_dos_name(char *fn) -{ - char tmpfn[PATH_MAX]; - if(strlen(fn) >= PATH_MAX) - fn[PATH_MAX-1]=0; /* truncate it */ - strcpy(tmpfn, msdosify(fn)); - free(fn); - return strdup(rename_if_dos_device_name(tmpfn)); -} -#endif /* MSDOS || WIN32 */ diff --git a/src/mkhelp.pl b/src/mkhelp.pl index 4d44a9e0f..ff4604155 100644 --- a/src/mkhelp.pl +++ b/src/mkhelp.pl @@ -133,16 +133,14 @@ print <<HEAD * NEVER EVER edit this manually, fix the mkhelp.pl script instead! * Generation time: $now */ -#include "setup.h" #ifdef USE_MANUAL #include "hugehelp.h" -#include <stdio.h> HEAD ; if($c) { print <<HEAD -#include <stdlib.h> #include <zlib.h> +#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 shrunk from $gzip @@ -167,6 +165,17 @@ HEAD print <<EOF #define BUF_SIZE 0x10000 +static voidpf zalloc_func(voidpf opaque, unsigned int items, unsigned int size) +{ + (void) opaque; + /* not a typo, keep it calloc() */ + return (voidpf) calloc(items, size); +} +static void zfree_func(voidpf opaque, voidpf ptr) +{ + (void) opaque; + free(ptr); +} /* Decompress and send to stdout a gzip-compressed buffer */ void hugehelp(void) { @@ -179,11 +188,11 @@ void hugehelp(void) return; headerlen = 10; + memset(&z, 0, sizeof(z_stream)); + z.zalloc = (alloc_func)zalloc_func; + z.zfree = (free_func)zfree_func; z.avail_in = (unsigned int)(sizeof(hugehelpgz) - headerlen); z.next_in = (unsigned char *)hugehelpgz + headerlen; - z.zalloc = (alloc_func)Z_NULL; - z.zfree = (free_func)Z_NULL; - z.opaque = 0; if (inflateInit2(&z, -MAX_WBITS) != Z_OK) return; diff --git a/src/setup.h b/src/setup.h index b510fd9b5..414aac73b 100644 --- a/src/setup.h +++ b/src/setup.h @@ -135,6 +135,11 @@ # endif #endif +#ifdef USE_LWIPSOCK +# include <lwip/sockets.h> +# include <lwip/netdb.h> +#endif + #ifdef TPF # include <sys/socket.h> /* change which select is used for the curl command line tool */ @@ -144,11 +149,52 @@ #endif #include <stdio.h> +#ifdef HAVE_ASSERT_H +#include <assert.h> +#endif + #ifdef __TANDEM #include <floss.h> #endif +/* + * Large file (>2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_LARGE_FILES +# include <io.h> +# include <sys/types.h> +# include <sys/stat.h> +# define lseek(fdes,offset,whence) _lseeki64(fdes, offset, whence) +# define fstat(fdes,stp) _fstati64(fdes, stp) +# define stat(fname,stp) _stati64(fname, stp) +# define struct_stat struct _stati64 +# define LSEEK_ERROR (__int64)-1 +#endif + +/* + * Small file (<2Gb) support using WIN32 functions. + */ + +#ifdef USE_WIN32_SMALL_FILES +# include <io.h> +# include <sys/types.h> +# include <sys/stat.h> +# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence) +# define fstat(fdes,stp) _fstat(fdes, stp) +# define stat(fname,stp) _stat(fname, stp) +# define struct_stat struct _stat +# 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 OS #define OS "unknown" @@ -221,4 +267,28 @@ int fileno( FILE *stream); #include "setup_once.h" #endif +/* + * Definition of our NOP statement Object-like macro + */ + +#ifndef Curl_nop_stmt +# define Curl_nop_stmt do { } WHILE_FALSE +#endif + +/* + * Ensure that Winsock and lwIP TCP/IP stacks are not mixed. + */ + +#if defined(__LWIP_OPT_H__) +# if defined(SOCKET) || \ + defined(USE_WINSOCK) || \ + defined(HAVE_ERRNO_H) || \ + defined(HAVE_WINSOCK_H) || \ + defined(HAVE_WINSOCK2_H) || \ + defined(HAVE_WS2TCPIP_H) +# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!" +# endif +#endif + #endif /* HEADER_CURL_SRC_SETUP_H */ + diff --git a/src/tool_binmode.c b/src/tool_binmode.c new file mode 100644 index 000000000..34422fdef --- /dev/null +++ b/src/tool_binmode.c @@ -0,0 +1,52 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef HAVE_SETMODE + +#ifdef HAVE_IO_H +# include <io.h> +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#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 + 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 000000000..abd22e44d --- /dev/null +++ b/src/tool_binmode.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_TOOL_BINMODE_H +#define HEADER_CURL_TOOL_BINMODE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "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 000000000..2ac6e483b --- /dev/null +++ b/src/tool_bname.c @@ -0,0 +1,50 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "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 000000000..ed7ba0632 --- /dev/null +++ b/src/tool_bname.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_TOOL_BNAME_H +#define HEADER_CURL_TOOL_BNAME_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "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 000000000..7ac9a7339 --- /dev/null +++ b/src/tool_cb_dbg.c @@ -0,0 +1,275 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.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 *text, + FILE *stream, const unsigned char *ptr, size_t size, + trace tracetype, curl_infotype infotype); + +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ + +int tool_debug_cb(CURL *handle, curl_infotype type, + unsigned char *data, size_t size, + void *userdata) +{ + struct Configurable *config = userdata; + FILE *output = config->errors; + const char *text; + struct timeval tv; + struct tm *now; + char timebuf[20]; + time_t secs; + static time_t epoch_offset; + static int known_offset; + + (void)handle; /* not used */ + + if(config->tracetime) { + tv = tvnow(); + 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 don't care */ + snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d.%06ld ", + now->tm_hour, now->tm_min, now->tm_sec, (long)tv.tv_usec); + } + else + timebuf[0] = 0; + + if(!config->trace_stream) { + /* open for append */ + if(curlx_strequal("-", config->trace_dump)) + config->trace_stream = stdout; + else if(curlx_strequal("%", config->trace_dump)) + /* Ok, this is somewhat hackish but we do it undocumented for now */ + config->trace_stream = config->errors; /* aka stderr */ + else { + config->trace_stream = fopen(config->trace_dump, "w"); + 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) { + /* + * This is the trace look that is similar to what libcurl makes on its + * own. + */ + static const char * const s_infotype[] = { + "*", "<", ">", "{", "}", "{", "}" + }; + size_t i; + size_t st = 0; + static bool newl = FALSE; + static bool traced_data = FALSE; + + switch(type) { + case CURLINFO_HEADER_OUT: + for(i = 0; i < size - 1; i++) { + if(data[i] == '\n') { /* LF */ + if(!newl) { + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + } + (void)fwrite(data + st, i - st + 1, 1, output); + st = i + 1; + newl = FALSE; + } + } + if(!newl) + fprintf(output, "%s%s ", timebuf, s_infotype[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) + fprintf(output, "%s%s ", timebuf, s_infotype[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 != stderr) && (output != stdout))) { + if(!newl) + fprintf(output, "%s%s ", timebuf, s_infotype[type]); + fprintf(output, "[data not shown]\n"); + newl = FALSE; + traced_data = TRUE; + } + } + break; + default: /* nada */ + newl = FALSE; + traced_data = FALSE; + break; + } + + return 0; + } + +#ifdef CURL_DOES_CONVERSIONS + /* Special processing is needed for CURLINFO_HEADER_OUT blocks + * if they contain both headers and data (separated by CRLFCRLF). + * We dump the header text and then switch type to CURLINFO_DATA_OUT. + */ + if((type == CURLINFO_HEADER_OUT) && (size > 4)) { + size_t i; + for(i = 0; i < size - 4; i++) { + if(memcmp(&data[i], "\r\n\r\n", 4) == 0) { + /* dump everything through the CRLFCRLF as a sent header */ + text = "=> Send header"; + dump(timebuf, text, output, data, i + 4, config->tracetype, type); + data += i + 3; + size -= i + 4; + type = CURLINFO_DATA_OUT; + data += 1; + break; + } + } + } +#endif /* CURL_DOES_CONVERSIONS */ + + switch (type) { + case CURLINFO_TEXT: + fprintf(output, "%s== Info: %s", timebuf, data); + 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, text, output, data, size, config->tracetype, type); + return 0; +} + +static void dump(const char *timebuf, 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, %zd bytes (0x%zx)\n", timebuf, 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; + } +#ifdef CURL_DOES_CONVERSIONS + /* repeat the 0D0A check above but use the host encoding for CRLF */ + if((tracetype == TRACE_ASCII) && + (i+c+1 < size) && (ptr[i+c] == '\r') && (ptr[i+c+1] == '\n')) { + i += (c+2-width); + break; + } + /* convert to host encoding and print this character */ + fprintf(stream, "%c", convert_char(infotype, ptr[i+c])); +#else + (void)infotype; + fprintf(stream, "%c", ((ptr[i+c] >= 0x20) && (ptr[i+c] < 0x80)) ? + ptr[i+c] : UNPRINTABLE_CHAR); +#endif /* CURL_DOES_CONVERSIONS */ + /* 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 000000000..6d4446da1 --- /dev/null +++ b/src/tool_cb_dbg.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_TOOL_CB_DBG_H +#define HEADER_CURL_TOOL_CB_DBG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* +** callback for CURLOPT_DEBUGFUNCTION +*/ + +int tool_debug_cb(CURL *handle, curl_infotype type, + unsigned 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 000000000..06ced4541 --- /dev/null +++ b/src/tool_cb_hdr.c @@ -0,0 +1,207 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_hdr.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static char *parse_filename(const char *ptr, size_t len); + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(void *ptr, size_t size, size_t nmemb, void *userdata) +{ + struct OutStruct *outs = userdata; + const char *str = ptr; + const size_t cb = size * nmemb; + const char *end = (char*)ptr + cb; + + /* + * Once that libcurl has called back tool_header_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + size_t failure = (size * nmemb) ? 0 : 1; + + if(!outs->config) + return failure; + +#ifdef DEBUGBUILD + if((size * nmemb > (size_t)CURL_MAX_WRITE_SIZE) || + (size * nmemb > (size_t)CURL_MAX_HTTP_HEADER)) { + warnf(outs->config, "Header data exceeds single call write limit!\n"); + return failure; + } +#endif + + if(!outs->filename && (cb > 20) && + checkprefix("Content-disposition:", str)) { + const char *p = str + 20; + + /* look for the 'filename=' parameter + (encoded filenames (*=) are not supported) */ + for(;;) { + char *filename; + size_t len; + + while(*p && (p < end) && !ISALPHA(*p)) + p++; + if(p > end - 9) + break; + + if(memcmp(p, "filename=", 9)) { + /* no match, find next parameter */ + while((p < end) && (*p != ';')) + p++; + continue; + } + 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) { + outs->filename = filename; + outs->alloc_filename = TRUE; + outs->s_isreg = TRUE; + outs->fopened = FALSE; + outs->stream = NULL; + break; + } + else + return failure; + } + } + + 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 = ';'; + + /* if the filename contains a path, only use filename portion */ + q = strrchr(copy, '/'); + 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; + } + } + + /* scan for the end letter and stop there */ + q = p; + while(*q) { + if(q[1] && (q[0] == '\\')) + q++; + else if(q[0] == stop) + break; + q++; + } + *q = '\0'; + + /* 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); + + /* in case we built debug enabled, we allow an evironment 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 */ + snprintf(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; +} + diff --git a/src/tool_cb_hdr.h b/src/tool_cb_hdr.h new file mode 100644 index 000000000..8808a4ae1 --- /dev/null +++ b/src/tool_cb_hdr.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TOOL_CB_HDR_H +#define HEADER_CURL_TOOL_CB_HDR_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* +** callback for CURLOPT_HEADERFUNCTION +*/ + +size_t tool_header_cb(void *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 000000000..e141f1e65 --- /dev/null +++ b/src/tool_cb_prg.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_prg.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_PROGRESSFUNCTION +*/ + +int tool_progress_cb(void *clientp, + double dltotal, double dlnow, + double ultotal, double ulnow) +{ + /* The original progress-bar source code was written for curl by Lars Aas, + and this new edition inherits some of his concepts. */ + + char line[256]; + char outline[256]; + char format[40]; + double frac; + double percent; + int barwidth; + int num; + int i; + + struct ProgressData *bar = (struct ProgressData *)clientp; + + /* expected transfer size */ + curl_off_t total = (curl_off_t)dltotal + (curl_off_t)ultotal + + bar->initial_size; + + /* we've come this far */ + curl_off_t point = (curl_off_t)dlnow + (curl_off_t)ulnow + + bar->initial_size; + + if(point > total) + /* we have got more than the expected total! */ + total = point; + + /* simply count invokes */ + bar->calls++; + + if(total < 1) { + curl_off_t prevblock = bar->prev / 1024; + curl_off_t thisblock = point / 1024; + while(thisblock > prevblock) { + fprintf(bar->out, "#"); + prevblock++; + } + } + else { + frac = (double)point / (double)total; + percent = frac * 100.0f; + barwidth = bar->width - 7; + num = (int) (((double)barwidth) * frac); + for(i = 0; i < num; i++) + line[i] = '#'; + line[i] = '\0'; + snprintf(format, sizeof(format), "%%-%ds %%5.1f%%%%", barwidth); + snprintf(outline, sizeof(outline), format, line, percent); + fprintf(bar->out, "\r%s", outline); + } + fflush(bar->out); + bar->prev = point; + + return 0; +} + +void progressbarinit(struct ProgressData *bar, + struct Configurable *config) +{ +#ifdef __EMX__ + /* 20000318 mgs */ + int scr_size[2]; +#endif + char *colp; + + memset(bar, 0, sizeof(struct ProgressData)); + + /* pass this through to progress function so + * it can display progress towards total file + * not just the part that's left. (21-may-03, dbyron) */ + if(config->use_resume) + bar->initial_size = config->resume_from; + +/* TODO: get terminal width through ansi escapes or something similar. + try to update width when xterm is resized... - 19990617 larsa */ +#ifndef __EMX__ + /* 20000318 mgs + * OS/2 users most likely won't have this env var set, and besides that + * we're using our own way to determine screen width */ + colp = curlx_getenv("COLUMNS"); + if(colp) { + char *endptr; + long num = strtol(colp, &endptr, 10); + if((endptr != colp) && (endptr == colp + strlen(colp)) && (num > 0)) + bar->width = (int)num; + else + bar->width = 79; + curl_free(colp); + } + else + bar->width = 79; +#else + /* 20000318 mgs + * We use this emx library call to get the screen width, and subtract + * one from what we got in order to avoid a problem with the cursor + * advancing to the next line if we print a string that is as long as + * the screen is wide. */ + + _scrsize(scr_size); + bar->width = scr_size[0] - 1; +#endif + + bar->out = config->errors; +} + diff --git a/src/tool_cb_prg.h b/src/tool_cb_prg.h new file mode 100644 index 000000000..f64335a3b --- /dev/null +++ b/src/tool_cb_prg.h @@ -0,0 +1,49 @@ +#ifndef HEADER_CURL_TOOL_CB_PRG_H +#define HEADER_CURL_TOOL_CB_PRG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#define CURL_PROGRESS_STATS 0 /* default progress display */ +#define CURL_PROGRESS_BAR 1 + +struct ProgressData { + int calls; + curl_off_t prev; + int width; + FILE *out; /* where to write everything to */ + curl_off_t initial_size; +}; + +void progressbarinit(struct ProgressData *bar, + struct Configurable *config); + +/* +** callback for CURLOPT_PROGRESSFUNCTION +*/ + +int tool_progress_cb(void *clientp, + double dltotal, double dlnow, + double ultotal, double 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 000000000..34edb063b --- /dev/null +++ b/src/tool_cb_rea.c @@ -0,0 +1,61 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_cb_rea.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) +{ + ssize_t rc; + struct InStruct *in = userdata; + + rc = read(in->fd, buffer, sz*nmemb); + if(rc < 0) { + if(errno == EAGAIN) { + errno = 0; + in->config->readbusy = TRUE; + return CURL_READFUNC_PAUSE; + } + /* since size_t is unsigned we can't return negative values fine */ + rc = 0; + } + in->config->readbusy = FALSE; + return (size_t)rc; +} + diff --git a/src/tool_cb_rea.h b/src/tool_cb_rea.h new file mode 100644 index 000000000..40c61f6f1 --- /dev/null +++ b/src/tool_cb_rea.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TOOL_CB_REA_H +#define HEADER_CURL_TOOL_CB_REA_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* +** callback for CURLOPT_READFUNCTION +*/ + +size_t tool_read_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); + +#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 000000000..5bac4947b --- /dev/null +++ b/src/tool_cb_see.c @@ -0,0 +1,129 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.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 InStruct *in = userdata; + +#if(CURL_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(in->fd, 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(in->fd, 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(in->fd, 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; +} + +#if defined(WIN32) && !defined(__MINGW64__) + +#ifdef __BORLANDC__ +/* 64-bit lseek-like function unavailable */ +# define _lseeki64(hnd,ofs,whence) lseek(hnd,ofs,whence) +#endif + +#ifdef __POCC__ +# if(__POCC__ < 450) +/* 64-bit lseek-like function unavailable */ +# define _lseeki64(hnd,ofs,whence) _lseek(hnd,ofs,whence) +# else +# define _lseeki64(hnd,ofs,whence) _lseek64(hnd,ofs,whence) +# endif +#endif + +/* + * Truncate a file handle at a 64-bit position 'where'. + */ + +int tool_ftruncate64(int fd, curl_off_t where) +{ + if(_lseeki64(fd, where, SEEK_SET) < 0) + return -1; + + if(!SetEndOfFile((HANDLE)_get_osfhandle(fd))) + return -1; + + return 0; +} + +#endif /* WIN32 && ! __MINGW64__ */ + diff --git a/src/tool_cb_see.h b/src/tool_cb_see.h new file mode 100644 index 000000000..530bfacba --- /dev/null +++ b/src/tool_cb_see.h @@ -0,0 +1,45 @@ +#ifndef HEADER_CURL_TOOL_CB_SEE_H +#define HEADER_CURL_TOOL_CB_SEE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#if defined(WIN32) && !defined(__MINGW64__) + +int tool_ftruncate64(int fd, curl_off_t where); + +#define ftruncate(fd,where) tool_ftruncate64(fd,where) + +#ifndef HAVE_FTRUNCATE +# define HAVE_FTRUNCATE 1 +#endif + +#endif /* WIN32 && ! __MINGW64__ */ + +/* +** 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_skt.c b/src/tool_cb_skt.c new file mode 100644 index 000000000..156c1108e --- /dev/null +++ b/src/tool_cb_skt.c @@ -0,0 +1,97 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" +#include "tool_cb_skt.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_SOCKOPTFUNCTION +*/ + +int tool_sockopt_cb(void *userdata, curl_socket_t curlfd, curlsocktype purpose) +{ + struct Configurable *config = userdata; + + int onoff = 1; /* this callback is only used if we ask for keepalives on the + connection */ + +#if defined(TCP_KEEPIDLE) || defined(TCP_KEEPINTVL) + int keepidle = (int)config->alivetime; +#endif + + switch(purpose) { + case CURLSOCKTYPE_IPCXN: + if(setsockopt(curlfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&onoff, + sizeof(onoff)) < 0) { + /* don't abort operation, just issue a warning */ + SET_SOCKERRNO(0); + warnf(config, "Could not set SO_KEEPALIVE!\n"); + return 0; + } + else { + if(config->alivetime) { +#ifdef TCP_KEEPIDLE + if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPIDLE, (void *)&keepidle, + sizeof(keepidle)) < 0) { + /* don't abort operation, just issue a warning */ + SET_SOCKERRNO(0); + warnf(config, "Could not set TCP_KEEPIDLE!\n"); + return 0; + } +#endif +#ifdef TCP_KEEPINTVL + if(setsockopt(curlfd, IPPROTO_TCP, TCP_KEEPINTVL, (void *)&keepidle, + sizeof(keepidle)) < 0) { + /* don't abort operation, just issue a warning */ + SET_SOCKERRNO(0); + warnf(config, "Could not set TCP_KEEPINTVL!\n"); + return 0; + } +#endif +#if !defined(TCP_KEEPIDLE) || !defined(TCP_KEEPINTVL) + warnf(config, "Keep-alive functionality somewhat crippled due to " + "missing support in your operating system!\n"); +#endif + } + } + break; + default: + break; + } + + return 0; +} + diff --git a/src/tool_cb_skt.h b/src/tool_cb_skt.h new file mode 100644 index 000000000..11bd0c422 --- /dev/null +++ b/src/tool_cb_skt.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_TOOL_CB_SKT_H +#define HEADER_CURL_TOOL_CB_SKT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* +** callback for CURLOPT_SOCKOPTFUNCTION +*/ + +int tool_sockopt_cb(void *userdata, + curl_socket_t curlfd, + curlsocktype purpose); + +#endif /* HEADER_CURL_TOOL_CB_SKT_H */ + diff --git a/src/tool_cb_wrt.c b/src/tool_cb_wrt.c new file mode 100644 index 000000000..de94f6e49 --- /dev/null +++ b/src/tool_cb_wrt.c @@ -0,0 +1,146 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#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 "memdebug.h" /* keep this as LAST include */ + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata) +{ + size_t rc; + struct OutStruct *outs = userdata; + struct Configurable *config = outs->config; + + /* + * Once that libcurl has called back tool_write_cb() the returned value + * is checked against the amount that was intended to be written, if + * it does not match then it fails with CURLE_WRITE_ERROR. So at this + * point returning a value different from sz*nmemb indicates failure. + */ + const size_t failure = (sz * nmemb) ? 0 : 1; + + if(!config) + return failure; + +#ifdef DEBUGBUILD + if(sz * nmemb > (size_t)CURL_MAX_WRITE_SIZE) { + warnf(config, "Data size exceeds single call write limit!\n"); + return failure; + } + + { + /* 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->init) + check_fails = TRUE; + } + if(check_fails) { + warnf(config, "Invalid output struct data for write callback\n"); + return failure; + } + } +#endif + + if(!outs->stream) { + FILE *file; + + if(!outs->filename || !*outs->filename) { + warnf(config, "Remote filename has no length!\n"); + return failure; + } + + if(config->content_disposition) { + /* don't overwrite existing files */ + file = fopen(outs->filename, "rb"); + if(file) { + fclose(file); + warnf(config, "Refusing to overwrite %s: %s\n", outs->filename, + strerror(EEXIST)); + return failure; + } + } + + /* open file for writing */ + file = fopen(outs->filename, "wb"); + if(!file) { + warnf(config, "Failed to create the file %s: %s\n", outs->filename, + strerror(errno)); + return failure; + } + outs->s_isreg = TRUE; + outs->fopened = TRUE; + outs->stream = file; + outs->bytes = 0; + outs->init = 0; + } + + rc = fwrite(buffer, sz, nmemb, outs->stream); + + if((sz * nmemb) == rc) + /* we added this amount of data to the output */ + outs->bytes += (sz * nmemb); + + if(config->readbusy) { + config->readbusy = FALSE; + curl_easy_pause(config->easy, CURLPAUSE_CONT); + } + + if(config->nobuffer) { + /* output buffering disabled */ + int res = fflush(outs->stream); + if(res) + return failure; + } + + return rc; +} + diff --git a/src/tool_cb_wrt.h b/src/tool_cb_wrt.h new file mode 100644 index 000000000..a17c14607 --- /dev/null +++ b/src/tool_cb_wrt.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TOOL_CB_WRT_H +#define HEADER_CURL_TOOL_CB_WRT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* +** callback for CURLOPT_WRITEFUNCTION +*/ + +size_t tool_write_cb(void *buffer, size_t sz, size_t nmemb, void *userdata); + +#endif /* HEADER_CURL_TOOL_CB_WRT_H */ + diff --git a/src/tool_cfgable.c b/src/tool_cfgable.c new file mode 100644 index 000000000..e74ea4375 --- /dev/null +++ b/src/tool_cfgable.c @@ -0,0 +1,131 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "tool_cfgable.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* TODO: review handling of unhandled fields marked below */ + +void free_config_fields(struct Configurable *config) +{ + struct getout *urlnode; + + if(config->easy) { + curl_easy_cleanup(config->easy); + config->easy = NULL; + } + + Curl_safefree(config->random_file); + Curl_safefree(config->egd_file); + Curl_safefree(config->useragent); + Curl_safefree(config->cookie); + Curl_safefree(config->cookiejar); + Curl_safefree(config->cookiefile); + + Curl_safefree(config->postfields); + 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->proxyuserpwd); + Curl_safefree(config->proxy); + + Curl_safefree(config->noproxy); + Curl_safefree(config->mail_from); + curl_slist_free_all(config->mail_rcpt); + + Curl_safefree(config->netrc_file); + + 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->cipher_list); + Curl_safefree(config->cert); + Curl_safefree(config->cert_type); + Curl_safefree(config->cacert); + Curl_safefree(config->capath); + Curl_safefree(config->crlfile); + Curl_safefree(config->key); + Curl_safefree(config->key_type); + Curl_safefree(config->key_passwd); + Curl_safefree(config->pubkey); + Curl_safefree(config->hostpubmd5); + Curl_safefree(config->engine); + + Curl_safefree(config->customrequest); + Curl_safefree(config->krblevel); + Curl_safefree(config->trace_dump); + + config->trace_stream = NULL; /* closed elsewhere when appropriate */ + + Curl_safefree(config->writeout); + + config->errors = NULL; /* closed elsewhere when appropriate */ + + curl_slist_free_all(config->quote); + curl_slist_free_all(config->postquote); + curl_slist_free_all(config->prequote); + + curl_slist_free_all(config->headers); + + if(config->httppost) { + curl_formfree(config->httppost); + config->httppost = NULL; + } + + /* config->last_post not handled */ + + curl_slist_free_all(config->telnet_options); + curl_slist_free_all(config->resolve); + + Curl_safefree(config->socksproxy); + Curl_safefree(config->socks5_gssapi_service); + + Curl_safefree(config->ftp_account); + Curl_safefree(config->ftp_alternative_to_user); + + Curl_safefree(config->libcurl); +} + diff --git a/src/tool_cfgable.h b/src/tool_cfgable.h new file mode 100644 index 000000000..adbb44627 --- /dev/null +++ b/src/tool_cfgable.h @@ -0,0 +1,204 @@ +#ifndef HEADER_CURL_TOOL_CFGABLE_H +#define HEADER_CURL_TOOL_CFGABLE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include "tool_sdecls.h" + +struct Configurable { + CURL *easy; /* once we have one, we keep it here */ + bool remote_time; + char *random_file; + char *egd_file; + char *useragent; + char *cookie; /* single line with specified cookies */ + char *cookiejar; /* write to this file */ + char *cookiefile; /* read from this file */ + bool cookiesession; /* new session? */ + bool encoding; /* Accept-Encoding please */ + bool tr_encoding; /* Transfer-Encoding please */ + long authtype; /* auth bitmask */ + bool use_resume; + bool resume_from_current; + bool disable_epsv; + bool disable_eprt; + bool ftp_pret; + long proto; + bool proto_present; + long proto_redir; + bool proto_redir_present; + curl_off_t resume_from; + char *postfields; + curl_off_t postfieldsize; + char *referer; + long timeout; + long connecttimeout; + long maxredirs; + curl_off_t max_filesize; + char *headerfile; + char *ftpport; + char *iface; + int localport; + int localportrange; + unsigned short porttouse; + char *range; + long low_speed_limit; + long low_speed_time; + int showerror; /* -1 == unset, default => show errors + 0 => -s is used to NOT show errors + 1 => -S has been used to show errors */ + char *userpwd; + char *tls_username; + char *tls_password; + char *tls_authtype; + char *proxyuserpwd; + char *proxy; + int proxyver; /* set to CURLPROXY_HTTP* define */ + char *noproxy; + char *mail_from; + struct curl_slist *mail_rcpt; + bool proxytunnel; + bool ftp_append; /* APPE on ftp */ + bool mute; /* don't show messages, --silent given */ + bool use_ascii; /* select ascii or text transfer */ + bool autoreferer; /* automatically set referer */ + bool failonerror; /* fail on (HTTP) errors */ + bool include_headers; /* send 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 ocations, even when hostname + changed */ + bool netrc_opt; + bool netrc; + char *netrc_file; + bool noprogress; /* don't show progress meter, --silent given */ + bool isatty; /* updated internally only if output is a tty */ + 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 */ + char *cipher_list; + char *cert; + char *cert_type; + char *cacert; + char *capath; + char *crlfile; + char *key; + char *key_type; + char *key_passwd; + char *pubkey; + char *hostpubmd5; + char *engine; + bool list_engines; + bool crlf; + char *customrequest; + char *krblevel; + char *trace_dump; /* file to dump the network trace to, or NULL */ + FILE *trace_stream; + bool trace_fopened; + trace tracetype; + bool tracetime; /* include timestamp? */ + long httpversion; + int progressmode; /* CURL_PROGRESS_BAR or CURL_PROGRESS_STATS */ + 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 create_dirs; + bool ftp_create_dirs; + bool ftp_skip_ip; + bool proxynegotiate; + bool proxyntlm; + bool proxydigest; + bool proxybasic; + bool proxyanyauth; + char *writeout; /* %-styled format string to output */ + bool writeenv; /* write results to environment, if available */ + FILE *errors; /* errors stream, defaults to stderr */ + bool errors_fopened; /* whether errors stream isn't stderr */ + struct curl_slist *quote; + struct curl_slist *postquote; + struct curl_slist *prequote; + long ssl_version; + long ip_version; + curl_TimeCond timecond; + time_t condtime; + struct curl_slist *headers; + struct curl_httppost *httppost; + struct curl_httppost *last_post; + struct curl_slist *telnet_options; + struct curl_slist *resolve; + 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 *socksproxy; /* set to server string */ + int socksver; /* set to CURLPROXY_SOCKS* define */ + char *socks5_gssapi_service; /* set service name for gssapi principal + * default rcmd */ + int socks5_gssapi_nec ; /* The NEC reference server does not protect + * the encryption type exchange */ + + bool tcp_nodelay; + long req_retry; /* number of retries */ + 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 tftp_blksize; /* TFTP BLKSIZE option */ + bool ignorecl; /* --ignore-content-length */ + bool disable_sessionid; + + char *libcurl; /* output libcurl code to this file name */ + bool raw; + bool post301; + bool post302; + 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; + +}; /* struct Configurable */ + +void free_config_fields(struct Configurable *config); + +#endif /* HEADER_CURL_TOOL_CFGABLE_H */ + diff --git a/src/tool_convert.c b/src/tool_convert.c new file mode 100644 index 000000000..e72a091b6 --- /dev/null +++ b/src/tool_convert.c @@ -0,0 +1,152 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef CURL_DOES_CONVERSIONS + +#ifdef HAVE_ICONV +# include <iconv.h> +#endif + +#include <curl/curl.h> + +#include "tool_convert.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef HAVE_ICONV + +/* curl tool iconv conversion descriptors */ +static iconv_t inbound_cd = (iconv_t)-1; +static iconv_t outbound_cd = (iconv_t)-1; + +/* set default codesets for iconv */ +#ifndef CURL_ICONV_CODESET_OF_NETWORK +# define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1" +#endif + +/* + * convert_to_network() is a curl tool function to convert + * from the host encoding to ASCII on non-ASCII platforms. + */ +CURLcode convert_to_network(char *buffer, size_t length) +{ + /* translate from the host encoding to the network encoding */ + char *input_ptr, *output_ptr; + size_t res, in_bytes, out_bytes; + + /* open an iconv conversion descriptor if necessary */ + if(outbound_cd == (iconv_t)-1) { + outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK, + CURL_ICONV_CODESET_OF_HOST); + if(outbound_cd == (iconv_t)-1) { + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + res = iconv(outbound_cd, &input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if((res == (size_t)-1) || (in_bytes != 0)) { + return CURLE_CONV_FAILED; + } + + return CURLE_OK; +} + +/* + * convert_from_network() is a curl tool function + * for performing ASCII conversions on non-ASCII platforms. + */ +CURLcode convert_from_network(char *buffer, size_t length) +{ + /* translate from the network encoding to the host encoding */ + char *input_ptr, *output_ptr; + size_t res, in_bytes, out_bytes; + + /* open an iconv conversion descriptor if necessary */ + if(inbound_cd == (iconv_t)-1) { + inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST, + CURL_ICONV_CODESET_OF_NETWORK); + if(inbound_cd == (iconv_t)-1) { + return CURLE_CONV_FAILED; + } + } + /* call iconv */ + input_ptr = output_ptr = buffer; + in_bytes = out_bytes = length; + res = iconv(inbound_cd, &input_ptr, &in_bytes, + &output_ptr, &out_bytes); + if((res == (size_t)-1) || (in_bytes != 0)) { + return CURLE_CONV_FAILED; + } + + return CURLE_OK; +} + +void convert_cleanup(void) +{ + /* close iconv conversion descriptors */ + if(inbound_cd != (iconv_t)-1) + (void)iconv_close(inbound_cd); + if(outbound_cd != (iconv_t)-1) + (void)iconv_close(outbound_cd); +} + +#endif /* HAVE_ICONV */ + +char convert_char(curl_infotype infotype, char this_char) +{ +/* determine how this specific character should be displayed */ + switch(infotype) { + case CURLINFO_DATA_IN: + case CURLINFO_DATA_OUT: + case CURLINFO_SSL_DATA_IN: + case CURLINFO_SSL_DATA_OUT: + /* data, treat as ASCII */ + if((this_char >= 0x20) && (this_char < 0x7f)) { + /* printable ASCII hex value: convert to host encoding */ + (void)convert_from_network(&this_char, 1); + } + else { + /* non-printable ASCII, use a replacement character */ + return UNPRINTABLE_CHAR; + } + /* fall through to default */ + default: + /* treat as host encoding */ + if(ISPRINT(this_char) + && (this_char != '\t') + && (this_char != '\r') + && (this_char != '\n')) { + /* printable characters excluding tabs and line end characters */ + return this_char; + } + break; + } + /* non-printable, use a replacement character */ + return UNPRINTABLE_CHAR; +} + +#endif /* CURL_DOES_CONVERSIONS */ + diff --git a/src/tool_convert.h b/src/tool_convert.h new file mode 100644 index 000000000..d3ef676b2 --- /dev/null +++ b/src/tool_convert.h @@ -0,0 +1,45 @@ +#ifndef HEADER_CURL_TOOL_CONVERT_H +#define HEADER_CURL_TOOL_CONVERT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef CURL_DOES_CONVERSIONS + +#ifdef HAVE_ICONV + +CURLcode convert_to_network(char *buffer, size_t length); +CURLcode convert_from_network(char *buffer, size_t length); +void convert_cleanup(void); + +#endif /* HAVE_ICONV */ + +char convert_char(curl_infotype infotype, char this_char); + +#endif /* CURL_DOES_CONVERSIONS */ + +#if !defined(CURL_DOES_CONVERSIONS) || !defined(HAVE_ICONV) +#define convert_cleanup() Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_TOOL_CONVERT_H */ + diff --git a/src/tool_dirhie.c b/src/tool_dirhie.c new file mode 100644 index 000000000..f538d8b2f --- /dev/null +++ b/src/tool_dirhie.c @@ -0,0 +1,151 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include <sys/stat.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifdef WIN32 +# include <direct.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_dirhie.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef NETWARE +# ifndef __NOVELL_LIBC__ +# define mkdir mkdir_510 +# endif +#endif + +#ifdef WIN32 +# define mkdir(x,y) (mkdir)((x)) +# ifndef __POCC__ +# define F_OK 0 +# endif +#endif + +static void show_dir_errno(FILE *errors, const char *name) +{ + switch(ERRNO) { +#ifdef EACCES + case EACCES: + fprintf(errors, "You don't have permission to create %s.\n", name); + break; +#endif +#ifdef ENAMETOOLONG + case ENAMETOOLONG: + fprintf(errors, "The directory name %s is too long.\n", name); + break; +#endif +#ifdef EROFS + case EROFS: + fprintf(errors, "%s resides on a read-only file system.\n", name); + break; +#endif +#ifdef ENOSPC + case ENOSPC: + fprintf(errors, "No space left on the file system that will " + "contain the directory %s.\n", name); + break; +#endif +#ifdef EDQUOT + case EDQUOT: + fprintf(errors, "Cannot create directory %s because you " + "exceeded your quota.\n", name); + break; +#endif + default : + fprintf(errors, "Error creating directory %s.\n", name); + break; + } +} + +/* + * Create the needed directory hierarchy recursively in order to save + * multi-GETs in file output, ie: + * curl "http://my.site/dir[1-5]/file[1-5].txt" -o "dir#1/file#2.txt" + * should create all the dir* automagically + */ + +CURLcode create_dir_hierarchy(const char *outfile, FILE *errors) +{ + char *tempdir; + char *tempdir2; + char *outdup; + char *dirbuildup; + CURLcode result = CURLE_OK; + + outdup = strdup(outfile); + if(!outdup) + return CURLE_OUT_OF_MEMORY; + + dirbuildup = malloc(strlen(outfile) + 1); + if(!dirbuildup) { + Curl_safefree(outdup); + return CURLE_OUT_OF_MEMORY; + } + dirbuildup[0] = '\0'; + + tempdir = strtok(outdup, DIR_CHAR); + + while(tempdir != NULL) { + tempdir2 = strtok(NULL, DIR_CHAR); + /* since strtok returns a token for the last word even + if not ending with DIR_CHAR, we need to prune it */ + if(tempdir2 != NULL) { + size_t dlen = strlen(dirbuildup); + if(dlen) + sprintf(&dirbuildup[dlen], "%s%s", DIR_CHAR, tempdir); + else { + if(0 != strncmp(outdup, DIR_CHAR, 1)) + strcpy(dirbuildup, tempdir); + else + sprintf(dirbuildup, "%s%s", DIR_CHAR, tempdir); + } + if(access(dirbuildup, F_OK) == -1) { + if(-1 == mkdir(dirbuildup,(mode_t)0000750)) { + show_dir_errno(errors, 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 000000000..eee30c47f --- /dev/null +++ b/src/tool_dirhie.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_TOOL_DIRHIE_H +#define HEADER_CURL_TOOL_DIRHIE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +CURLcode create_dir_hierarchy(const char *outfile, FILE *errors); + +#endif /* HEADER_CURL_TOOL_DIRHIE_H */ + diff --git a/src/tool_doswin.c b/src/tool_doswin.c new file mode 100644 index 000000000..b23b50af1 --- /dev/null +++ b/src/tool_doswin.c @@ -0,0 +1,300 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#if defined(MSDOS) || defined(WIN32) + +#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) +# include <libgen.h> +#endif + +#ifdef WIN32 +# include <curl/curl.h> +# include "tool_cfgable.h" +# include "tool_libinfo.h" +#endif + +#include "tool_bname.h" +#include "tool_doswin.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* + * Macros ALWAYS_TRUE and ALWAYS_FALSE are used to avoid compiler warnings. + */ + +#define ALWAYS_TRUE (1) +#define ALWAYS_FALSE (0) + +#if defined(_MSC_VER) && !defined(__POCC__) +# undef ALWAYS_TRUE +# undef ALWAYS_FALSE +# if (_MSC_VER < 1500) +# define ALWAYS_TRUE (0, 1) +# define ALWAYS_FALSE (1, 0) +# else +# define ALWAYS_TRUE \ +__pragma(warning(push)) \ +__pragma(warning(disable:4127)) \ +(1) \ +__pragma(warning(pop)) +# define ALWAYS_FALSE \ +__pragma(warning(push)) \ +__pragma(warning(disable:4127)) \ +(0) \ +__pragma(warning(pop)) +# endif +#endif + +#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) ALWAYS_TRUE /* long file names always available */ +#elif !defined(__DJGPP__) || (__DJGPP__ < 2) /* DJGPP 2.0 has _use_lfn() */ +# define _use_lfn(f) ALWAYS_FALSE /* long file names never available */ +#endif + +static const char *msdosify (const char *file_name); +static char *rename_if_dos_device_name (char *file_name); + +/* + * sanitize_dos_name: returns a newly allocated string holding a + * valid file name which will be a transformation of given argument + * in case this wasn't already a valid file name. + * + * This function takes ownership of given argument, free'ing it before + * returning. Caller is responsible of free'ing returned string. Upon + * out of memory condition function returns NULL. + */ + +char *sanitize_dos_name(char *file_name) +{ + char new_name[PATH_MAX]; + + if(!file_name) + return NULL; + + if(strlen(file_name) >= PATH_MAX) + file_name[PATH_MAX-1] = '\0'; /* truncate it */ + + strcpy(new_name, msdosify(file_name)); + + Curl_safefree(file_name); + + return strdup(rename_if_dos_device_name(new_name)); +} + +/* The following functions are taken with modification from the DJGPP + * port of tar 1.12. They use algorithms originally from DJTAR. */ + +static const char *msdosify (const char *file_name) +{ + static 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; + + /* 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++ = *s++; + } + + for(idx = 0, dot_idx = -1; *s && d < dlimit; s++, d++) { + if(memchr(illegal_aliens, *s, len)) { + /* 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. */ + if(*s == '.') { + if(idx == 0 && (s[1] == '/' || (s[1] == '.' && s[2] == '/'))) { + /* Copy "./" and "../" verbatim. */ + *d++ = *s++; + if(*s == '.') + *d++ = *s++; + *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'; + *d = 'x'; + } + else { + /* libg++ etc. */ + memcpy (d, "plus", 4); + d += 3; + } + s++; + idx++; + } + else + *d = '_'; + } + else + *d = *s; + if(*s == '/') { + idx = 0; + dot_idx = -1; + } + else + idx++; + } + + *d = '\0'; + return dos_name; +} + +static char *rename_if_dos_device_name (char *file_name) +{ + /* 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 *base; + struct_stat st_buf; + char fname[PATH_MAX]; + + strncpy(fname, file_name, PATH_MAX-1); + fname[PATH_MAX-1] = '\0'; + base = basename(fname); + if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { + size_t blen = strlen(base); + + if(strlen(fname) >= PATH_MAX-1) { + /* Make room for the '_' */ + blen--; + base[blen] = '\0'; + } + /* Prepend a '_'. */ + memmove(base + 1, base, blen + 1); + base[0] = '_'; + strcpy(file_name, fname); + } + return file_name; +} + +#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 Configurable *config, const char *bundle_file) +{ + CURLcode result = CURLE_OK; + + /* search and set cert file only if libcurl supports SSL */ + if(curlinfo->features & CURL_VERSION_SSL) { + + DWORD res_len; + DWORD buf_tchar_size = PATH_MAX + 1; + DWORD buf_bytes_size = sizeof(TCHAR) * buf_tchar_size; + char *ptr = NULL; + + char *buf = malloc(buf_bytes_size); + if(!buf) + return CURLE_OUT_OF_MEMORY; + buf[0] = '\0'; + + res_len = SearchPathA(NULL, bundle_file, NULL, buf_tchar_size, buf, &ptr); + if(res_len > 0) { + Curl_safefree(config->cacert); + config->cacert = strdup(buf); + if(!config->cacert) + result = CURLE_OUT_OF_MEMORY; + } + else + result = CURLE_SSL_CACERT; + + Curl_safefree(buf); + } + + return result; +} + +#endif /* WIN32 */ + +#endif /* MSDOS || WIN32 */ + diff --git a/src/tool_doswin.h b/src/tool_doswin.h new file mode 100644 index 000000000..ce475acf9 --- /dev/null +++ b/src/tool_doswin.h @@ -0,0 +1,45 @@ +#ifndef HEADER_CURL_TOOL_DOSWIN_H +#define HEADER_CURL_TOOL_DOSWIN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#if defined(MSDOS) || defined(WIN32) + +char *sanitize_dos_name(char *file_name); + +#if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) + +char **__crt0_glob_function(char *arg); + +#endif /* MSDOS && (__DJGPP__ || __GO32__) */ + +#ifdef WIN32 + +CURLcode FindWin32CACert(struct Configurable *config, const char *bundle_file); + +#endif /* WIN32 */ + +#endif /* MSDOS || WIN32 */ + +#endif /* HEADER_CURL_TOOL_DOSWIN_H */ + diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c new file mode 100644 index 000000000..5c42e808e --- /dev/null +++ b/src/tool_easysrc.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#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 curl_slist *easysrc = NULL; +struct curl_slist *easysrc_remarks = NULL; + +static const char *const srchead[]={ + "/********* Sample code generated by the curl command line tool **********", + " * All curl_easy_setopt() options are documented at:", + " * http://curl.haxx.se/libcurl/c/curl_easy_setopt.html", + " ************************************************************************/", + "#include <curl/curl.h>", + "", + "int main(int argc, char *argv[])", + "{", + " CURLcode ret;", + NULL +}; + +void dumpeasysrc(struct Configurable *config) +{ + struct curl_slist *ptr; + char *o = config->libcurl; + + if(o) { + FILE *out; + bool fopened = FALSE; + if(strcmp(o, "-")) { + out = fopen(o, "wt"); + fopened = TRUE; + } + else + out = stdout; + if(!out) + warnf(config, "Failed to open %s to write libcurl code!\n", o); + else { + int i; + const char *c; + + for(i=0; ((c = srchead[i]) != '\0'); i++) + fprintf(out, "%s\n", c); + + ptr = easysrc; + while(ptr) { + fprintf(out, " %s\n", ptr->data); + ptr = ptr->next; + } + + ptr = easysrc_remarks; + if(ptr) { + fprintf(out, + "\n /* Here is a list of options the curl code" + " used that cannot get generated\n" + " as source easily. You may select to either" + " not use them or implement\n them yourself.\n" + "\n"); + while(ptr) { + fprintf(out, " %s\n", ptr->data); + ptr = ptr->next; + } + fprintf(out, "\n */\n"); + } + + fprintf(out, + " return (int)ret;\n" + "}\n" + "/**** End of sample code ****/\n"); + if(fopened) + fclose(out); + } + } + + curl_slist_free_all(easysrc_remarks); + curl_slist_free_all(easysrc); + easysrc_remarks = NULL; + easysrc = NULL; +} + diff --git a/src/tool_easysrc.h b/src/tool_easysrc.h new file mode 100644 index 000000000..21b567458 --- /dev/null +++ b/src/tool_easysrc.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_TOOL_EASYSRC_H +#define HEADER_CURL_TOOL_EASYSRC_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* global variable declarations, for easy-interface source code generation */ + +extern struct curl_slist *easysrc; +extern struct curl_slist *easysrc_remarks; + +void dumpeasysrc(struct Configurable *config); + +#endif /* HEADER_CURL_TOOL_EASYSRC_H */ + diff --git a/src/tool_formparse.c b/src/tool_formparse.c new file mode 100644 index 000000000..5d6263e5c --- /dev/null +++ b/src/tool_formparse.c @@ -0,0 +1,321 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_mfiles.h" +#include "tool_msgs.h" +#include "tool_formparse.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/*************************************************************************** + * + * formparse() + * + * Reads a 'name=value' parameter and builds the appropriate linked list. + * + * Specify files to upload with 'name=@filename'. Supports specified + * given Content-Type of the files. Such as ';type=<content-type>'. + * + * 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' + * + * 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' + * + * This function uses curl_formadd to fulfill it's job. Is heavily based on + * the old curl_formparse code. + * + ***************************************************************************/ + +#define FORM_FILE_SEPARATOR ',' +#define FORM_TYPE_SEPARATOR ';' + +int formparse(struct Configurable *config, + const char *input, + struct curl_httppost **httppost, + struct curl_httppost **last_post, + bool literal_value) +{ + /* nextarg MUST be a string in the format 'name=contents' and we'll + build a linked list with the info */ + char name[256]; + char *contents = NULL; + char major[128]; + char minor[128]; + char *contp; + const char *type = NULL; + char *sep; + char *sep2; + + if((1 == sscanf(input, "%255[^=]=", name)) && + ((contp = strchr(input, '=')) != NULL)) { + /* the input was using the correct format */ + + /* Allocate the contents */ + contents = strdup(contp+1); + if(!contents) { + fprintf(config->errors, "out of memory\n"); + return 1; + } + contp = contents; + + if('@' == contp[0] && !literal_value) { + + /* we use the @-letter to indicate file name(s) */ + + struct multi_files *multi_start = NULL; + struct multi_files *multi_current = NULL; + + contp++; + + do { + /* since this was a file, it may have a content-type specifier + at the end too, or a filename. Or both. */ + char *ptr; + char *filename = NULL; + + sep = strchr(contp, FORM_TYPE_SEPARATOR); + sep2 = strchr(contp, FORM_FILE_SEPARATOR); + + /* pick the closest */ + if(sep2 && (sep2 < sep)) { + sep = sep2; + + /* no type was specified! */ + } + + type = NULL; + + if(sep) { + + /* if we got here on a comma, don't do much */ + if(FORM_FILE_SEPARATOR == *sep) + ptr = NULL; + else + ptr = sep+1; + + *sep = '\0'; /* terminate file name at separator */ + + while(ptr && (FORM_FILE_SEPARATOR!= *ptr)) { + + /* pass all white spaces */ + while(ISSPACE(*ptr)) + ptr++; + + if(checkprefix("type=", ptr)) { + /* set type pointer */ + type = &ptr[5]; + + /* verify that this is a fine type specifier */ + if(2 != sscanf(type, "%127[^/]/%127[^;,\n]", + major, minor)) { + warnf(config, "Illegally formatted content-type field!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 2; /* illegal content-type syntax! */ + } + + /* now point beyond the content-type specifier */ + sep = (char *)type + strlen(major)+strlen(minor)+1; + + /* there's a semicolon following - we check if it is a filename + specified and if not we simply assume that it is text that + the user wants included in the type and include that too up + to the next zero or semicolon. */ + if((*sep==';') && !checkprefix(";filename=", sep)) { + sep2 = strchr(sep+1, ';'); + if(sep2) + sep = sep2; + else + sep = sep + strlen(sep); /* point to end of string */ + } + + if(*sep) { + *sep = '\0'; /* zero terminate type string */ + + ptr = sep+1; + } + else + ptr = NULL; /* end */ + } + else if(checkprefix("filename=", ptr)) { + filename = &ptr[9]; + ptr = strchr(filename, FORM_TYPE_SEPARATOR); + if(!ptr) { + ptr = strchr(filename, FORM_FILE_SEPARATOR); + } + if(ptr) { + *ptr = '\0'; /* zero terminate */ + ptr++; + } + } + else + /* confusion, bail out of loop */ + break; + } + /* find the following comma */ + if(ptr) + sep = strchr(ptr, FORM_FILE_SEPARATOR); + else + sep = NULL; + } + else { + sep = strchr(contp, FORM_FILE_SEPARATOR); + } + if(sep) { + /* the next file name starts here */ + *sep = '\0'; + sep++; + } + /* if type == NULL curl_formadd takes care of the problem */ + + if(!AddMultiFiles(contp, type, filename, &multi_start, + &multi_current)) { + warnf(config, "Error building form post!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 3; + } + contp = sep; /* move the contents pointer to after the separator */ + + } while(sep && *sep); /* loop if there's another file name */ + + /* now we add the multiple files section */ + if(multi_start) { + struct curl_forms *forms = NULL; + struct multi_files *ptr = multi_start; + unsigned int i, count = 0; + while(ptr) { + ptr = ptr->next; + ++count; + } + forms = malloc((count+1)*sizeof(struct curl_forms)); + if(!forms) { + fprintf(config->errors, "Error building form post!\n"); + Curl_safefree(contents); + FreeMultiInfo(&multi_start, &multi_current); + return 4; + } + for(i = 0, ptr = multi_start; i < count; ++i, ptr = ptr->next) { + forms[i].option = ptr->form.option; + forms[i].value = ptr->form.value; + } + forms[count].option = CURLFORM_END; + FreeMultiInfo(&multi_start, &multi_current); + if(curl_formadd(httppost, last_post, + CURLFORM_COPYNAME, name, + CURLFORM_ARRAY, forms, CURLFORM_END) != 0) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(forms); + Curl_safefree(contents); + return 5; + } + Curl_safefree(forms); + } + } + else { + struct curl_forms info[4]; + int i = 0; + char *ct = literal_value ? NULL : strstr(contp, ";type="); + + info[i].option = CURLFORM_COPYNAME; + info[i].value = name; + i++; + + if(ct) { + info[i].option = CURLFORM_CONTENTTYPE; + info[i].value = &ct[6]; + i++; + ct[0] = '\0'; /* zero terminate here */ + } + + if(contp[0]=='<' && !literal_value) { + info[i].option = CURLFORM_FILECONTENT; + info[i].value = contp+1; + i++; + info[i].option = CURLFORM_END; + + if(curl_formadd(httppost, last_post, + CURLFORM_ARRAY, info, CURLFORM_END ) != 0) { + warnf(config, "curl_formadd failed, possibly the file %s is bad!\n", + contp+1); + Curl_safefree(contents); + return 6; + } + } + else { +#ifdef CURL_DOES_CONVERSIONS + if(convert_to_network(contp, strlen(contp))) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(contents); + return 7; + } +#endif + info[i].option = CURLFORM_COPYCONTENTS; + info[i].value = contp; + i++; + info[i].option = CURLFORM_END; + if(curl_formadd(httppost, last_post, + CURLFORM_ARRAY, info, CURLFORM_END) != 0) { + warnf(config, "curl_formadd failed!\n"); + Curl_safefree(contents); + return 8; + } + } + } + + } + else { + warnf(config, "Illegally formatted input field!\n"); + return 1; + } + Curl_safefree(contents); + return 0; +} + diff --git a/src/tool_formparse.h b/src/tool_formparse.h new file mode 100644 index 000000000..eebf507f4 --- /dev/null +++ b/src/tool_formparse.h @@ -0,0 +1,33 @@ +#ifndef HEADER_CURL_TOOL_FORMPARSE_H +#define HEADER_CURL_TOOL_FORMPARSE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +int formparse(struct Configurable *config, + const char *input, + struct curl_httppost **httppost, + struct curl_httppost **last_post, + bool literal_value); + +#endif /* HEADER_CURL_TOOL_FORMPARSE_H */ + diff --git a/src/tool_getparam.c b/src/tool_getparam.c new file mode 100644 index 000000000..bd7375fd9 --- /dev/null +++ b/src/tool_getparam.c @@ -0,0 +1,1634 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#ifdef USE_MANUAL +# include "hugehelp.h" +#endif + +#include "tool_binmode.h" +#include "tool_cfgable.h" +#include "tool_cb_prg.h" +#include "tool_formparse.h" +#include "tool_getparam.h" +#include "tool_help.h" +#include "tool_helpers.h" +#include "tool_libinfo.h" +#include "tool_msgs.h" +#include "tool_paramhlp.h" +#include "tool_parsecfg.h" +#include "tool_version.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +#define GetStr(str,val) do { \ + if(*(str)) { \ + free(*(str)); \ + *(str) = NULL; \ + } \ + if((val)) \ + *(str) = strdup((val)); \ + if(!(val)) \ + return PARAM_NO_MEM; \ +} WHILE_FALSE + +struct LongShort { + const char *letter; /* short name option */ + const char *lname; /* long name option */ + bool extraparam; /* whether it takes an additional argument */ +}; + +static const struct LongShort aliases[]= { + /* all these ones, starting with "*" or "$" as a short-option have *no* + short option to mention. */ + {"*", "url", TRUE}, + {"*a", "random-file", TRUE}, + {"*b", "egd-file", TRUE}, + {"*c", "connect-timeout", TRUE}, + {"*d", "ciphers", TRUE}, + {"*e", "disable-epsv", FALSE}, + {"*E", "epsv", FALSE}, + /* 'epsv' made like this to make --no-epsv and --epsv to work + although --disable-epsv is the documented option */ +#ifdef USE_ENVIRONMENT + {"*f", "environment", FALSE}, +#endif + {"*g", "trace", TRUE}, + {"*h", "trace-ascii", TRUE}, + {"*i", "limit-rate", TRUE}, + {"*j", "compressed", FALSE}, + {"*J", "tr-encoding", FALSE}, + {"*k", "digest", FALSE}, + {"*l", "negotiate", FALSE}, + {"*m", "ntlm", FALSE}, + {"*M", "ntlm-wb", FALSE}, + {"*n", "basic", FALSE}, + {"*o", "anyauth", FALSE}, +#ifdef USE_WATT32 + {"*p", "wdebug", FALSE}, +#endif + {"*q", "ftp-create-dirs", FALSE}, + {"*r", "create-dirs", FALSE}, + {"*s", "max-redirs", TRUE}, + {"*t", "proxy-ntlm", FALSE}, + {"*u", "crlf", FALSE}, + {"*v", "stderr", TRUE}, + {"*w", "interface", TRUE}, + {"*x", "krb" , TRUE}, + {"*x", "krb4" , TRUE}, + /* 'krb4' is the previous name */ + {"*y", "max-filesize", TRUE}, + {"*z", "disable-eprt", FALSE}, + {"*Z", "eprt", FALSE}, + /* 'eprt' made like this to make --no-eprt and --eprt to work + although --disable-eprt is the documented option */ + {"$a", "ftp-ssl", FALSE}, + /* 'ftp-ssl' deprecated name since 7.20.0 */ + {"$a", "ssl", FALSE}, + /* 'ssl' new option name in 7.20.0, previously this was ftp-ssl */ + {"$b", "ftp-pasv", FALSE}, + {"$c", "socks5", TRUE}, + {"$c", "socks", TRUE}, + /* 'socks' is how the option once was documented but we prefer + the --socks5 version for explicit version */ + {"$d", "tcp-nodelay", FALSE}, + {"$e", "proxy-digest", FALSE}, + {"$f", "proxy-basic", FALSE}, + {"$g", "retry", TRUE}, + {"$h", "retry-delay", TRUE}, + {"$i", "retry-max-time", TRUE}, + {"$k", "proxy-negotiate", FALSE}, + {"$m", "ftp-account", TRUE}, + {"$n", "proxy-anyauth", FALSE}, + {"$o", "trace-time", FALSE}, + {"$p", "ignore-content-length", FALSE}, + {"$q", "ftp-skip-pasv-ip", FALSE}, + {"$r", "ftp-method", TRUE}, + {"$s", "local-port", TRUE}, + {"$t", "socks4", TRUE}, + {"$T", "socks4a", TRUE}, + {"$u", "ftp-alternative-to-user", TRUE}, + {"$v", "ftp-ssl-reqd", FALSE}, + /* 'ftp-ssl-reqd' deprecated name since 7.20.0 */ + {"$v", "ssl-reqd", FALSE}, + /* 'ssl-reqd' new in 7.20.0, previously this was ftp-ssl-reqd */ + {"$w", "sessionid", FALSE}, + /* ¡sessionid' listed as --no-sessionid in the help */ + {"$x", "ftp-ssl-control", FALSE}, + {"$y", "ftp-ssl-ccc", FALSE}, + {"$j", "ftp-ssl-ccc-mode", TRUE}, + {"$z", "libcurl", TRUE}, + {"$#", "raw", FALSE}, + {"$0", "post301", FALSE}, + {"$1", "keepalive", FALSE}, + /* 'keepalive' listed as --no-keepalive in the help */ + {"$2", "socks5-hostname", TRUE}, + {"$3", "keepalive-time", TRUE}, + {"$4", "post302", FALSE}, + {"$5", "noproxy", TRUE}, +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + {"$6", "socks5-gssapi-service", TRUE}, + {"$7", "socks5-gssapi-nec", FALSE}, +#endif + {"$8", "proxy1.0", TRUE}, + {"$9", "tftp-blksize", TRUE}, + {"$A", "mail-from", TRUE}, + {"$B", "mail-rcpt", TRUE}, + {"$C", "ftp-pret", FALSE}, + {"$D", "proto", TRUE}, + {"$E", "proto-redir", TRUE}, + {"$F", "resolve", TRUE}, + {"$G", "delegation", TRUE}, + {"0", "http1.0", FALSE}, + {"1", "tlsv1", FALSE}, + {"2", "sslv2", FALSE}, + {"3", "sslv3", FALSE}, + {"4", "ipv4", FALSE}, + {"6", "ipv6", FALSE}, + {"a", "append", FALSE}, + {"A", "user-agent", TRUE}, + {"b", "cookie", TRUE}, + {"B", "use-ascii", FALSE}, + {"c", "cookie-jar", TRUE}, + {"C", "continue-at", TRUE}, + {"d", "data", TRUE}, + {"da", "data-ascii", TRUE}, + {"db", "data-binary", TRUE}, + {"de", "data-urlencode", TRUE}, + {"D", "dump-header", TRUE}, + {"e", "referer", TRUE}, + {"E", "cert", TRUE}, + {"Ea", "cacert", TRUE}, + {"Eb", "cert-type", TRUE}, + {"Ec", "key", TRUE}, + {"Ed", "key-type", TRUE}, + {"Ee", "pass", TRUE}, + {"Ef", "engine", TRUE}, + {"Eg", "capath ", TRUE}, + {"Eh", "pubkey", TRUE}, + {"Ei", "hostpubmd5", TRUE}, + {"Ej", "crlfile", TRUE}, + {"Ek", "tlsuser", TRUE}, + {"El", "tlspassword", TRUE}, + {"Em", "tlsauthtype", TRUE}, + {"f", "fail", FALSE}, + {"F", "form", TRUE}, + {"Fs", "form-string", TRUE}, + {"g", "globoff", FALSE}, + {"G", "get", FALSE}, + {"h", "help", FALSE}, + {"H", "header", TRUE}, + {"i", "include", FALSE}, + {"I", "head", FALSE}, + {"j", "junk-session-cookies", FALSE}, + {"J", "remote-header-name", FALSE}, + {"k", "insecure", FALSE}, + {"K", "config", TRUE}, + {"l", "list-only", FALSE}, + {"L", "location", FALSE}, + {"Lt", "location-trusted", FALSE}, + {"m", "max-time", TRUE}, + {"M", "manual", FALSE}, + {"n", "netrc", FALSE}, + {"no", "netrc-optional", FALSE}, + {"ne", "netrc-file", TRUE}, + {"N", "buffer", FALSE}, + /* 'buffer' listed as --no-buffer in the help */ + {"o", "output", TRUE}, + {"O", "remote-name", FALSE}, + {"Oa", "remote-name-all", FALSE}, + {"p", "proxytunnel", FALSE}, + {"P", "ftpport", TRUE}, + /* 'ftpport' old version */ + {"P", "ftp-port", TRUE}, + {"q", "disable", FALSE}, + {"Q", "quote", TRUE}, + {"r", "range", TRUE}, + {"R", "remote-time", FALSE}, + {"s", "silent", FALSE}, + {"S", "show-error", FALSE}, + {"t", "telnet-options", TRUE}, + /* 'telnet-options' documented as telnet-option */ + {"T", "upload-file", TRUE}, + {"u", "user", TRUE}, + {"U", "proxy-user", TRUE}, + {"v", "verbose", FALSE}, + {"V", "version", FALSE}, + {"w", "write-out", TRUE}, + {"x", "proxy", TRUE}, + {"X", "request", TRUE}, + {"X", "http-request", TRUE}, + /* 'http-request' OBSOLETE VERSION */ + {"Y", "speed-limit", TRUE}, + {"y", "speed-time", TRUE}, + {"z", "time-cond", TRUE}, + {"#", "progress-bar", FALSE}, + {"~", "xattr", FALSE}, +}; + +struct feat { + const char *name; + int bitmask; +}; + +static const struct feat feats[] = { + {"AsynchDNS", CURL_VERSION_ASYNCHDNS}, + {"Debug", CURL_VERSION_DEBUG}, + {"TrackMemory", CURL_VERSION_CURLDEBUG}, + {"GSS-Negotiate", CURL_VERSION_GSSNEGOTIATE}, + {"IDN", CURL_VERSION_IDN}, + {"IPv6", CURL_VERSION_IPV6}, + {"Largefile", CURL_VERSION_LARGEFILE}, + {"NTLM", CURL_VERSION_NTLM}, + {"NTLM_WB", CURL_VERSION_NTLM_WB}, + {"SPNEGO", CURL_VERSION_SPNEGO}, + {"SSL", CURL_VERSION_SSL}, + {"SSPI", CURL_VERSION_SSPI}, + {"krb4", CURL_VERSION_KERBEROS4}, + {"libz", CURL_VERSION_LIBZ}, + {"CharConv", CURL_VERSION_CONV}, + {"TLS-SRP", CURL_VERSION_TLSAUTH_SRP} +}; + +ParameterError getparameter(char *flag, /* f or -long-flag */ + char *nextarg, /* NULL if unset */ + bool *usedarg, /* set to TRUE if the arg + has been used */ + struct Configurable *config) +{ + char letter; + char subletter = '\0'; /* subletters can only occur on long options */ + int rc; + const char *parse = NULL; + unsigned int j; + time_t now; + int hit = -1; + bool longopt = FALSE; + bool singleopt = FALSE; /* when true means '-o foo' used '-ofoo' */ + ParameterError err; + bool toggle = TRUE; /* how to switch boolean options, on or off. Controlled + by using --OPTION or --no-OPTION */ + + + if(('-' != flag[0]) || + (('-' == flag[0]) && ('-' == flag[1]))) { + /* this should be a long name */ + char *word = ('-' == flag[0]) ? flag+2 : flag; + size_t fnam = strlen(word); + int numhits = 0; + + if(!strncmp(word, "no-", 3)) { + /* disable this option but ignore the "no-" part when looking for it */ + word += 3; + toggle = FALSE; + } + + for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { + if(curlx_strnequal(aliases[j].lname, word, fnam)) { + longopt = TRUE; + numhits++; + if(curlx_raw_equal(aliases[j].lname, word)) { + parse = aliases[j].letter; + hit = j; + numhits = 1; /* a single unique hit */ + break; + } + parse = aliases[j].letter; + hit = j; + } + } + if(numhits > 1) { + /* this is at least the second match! */ + return PARAM_OPTION_AMBIGUOUS; + } + if(hit < 0) { + return PARAM_OPTION_UNKNOWN; + } + } + else { + flag++; /* prefixed with one dash, pass it */ + hit = -1; + parse = flag; + } + + do { + /* we can loop here if we have multiple single-letters */ + + if(!longopt) { + if(NULL != parse) { + letter = (char)*parse; + } + else { + letter = '\0'; + } + subletter='\0'; + } + else { + letter = parse[0]; + subletter = parse[1]; + } + *usedarg = FALSE; /* default is that we don't use the arg */ + + if(hit < 0) { + for(j = 0; j < sizeof(aliases)/sizeof(aliases[0]); j++) { + if(letter == aliases[j].letter[0]) { + hit = j; + break; + } + } + if(hit < 0) { + return PARAM_OPTION_UNKNOWN; + } + } + + if(aliases[hit].extraparam) { + /* 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) + return PARAM_REQUIRES_PARAMETER; + else + *usedarg = TRUE; /* mark it as used */ + } + + switch(letter) { + case '*': /* options without a short option */ + switch(subletter) { + case 'a': /* random-file */ + GetStr(&config->random_file, nextarg); + break; + case 'b': /* egd-file */ + GetStr(&config->egd_file, nextarg); + break; + case 'c': /* connect-timeout */ + if(str2num(&config->connecttimeout, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case 'd': /* ciphers */ + GetStr(&config->cipher_list, nextarg); + break; + case 'e': /* --disable-epsv */ + config->disable_epsv = toggle; + break; + case 'E': /* --epsv */ + config->disable_epsv = (!toggle)?TRUE:FALSE; + break; +#ifdef USE_ENVIRONMENT + case 'f': + config->writeenv = toggle; + break; +#endif + case 'g': /* --trace */ + GetStr(&config->trace_dump, nextarg); + if(config->tracetype && (config->tracetype != TRACE_BIN)) + warnf(config, "--trace overrides an earlier trace/verbose option\n"); + config->tracetype = TRACE_BIN; + break; + case 'h': /* --trace-ascii */ + GetStr(&config->trace_dump, nextarg); + if(config->tracetype && (config->tracetype != TRACE_ASCII)) + warnf(config, + "--trace-ascii overrides an earlier trace/verbose option\n"); + config->tracetype = TRACE_ASCII; + break; + case 'i': /* --limit-rate */ + { + /* We support G, M, K too */ + char *unit; + curl_off_t value = curlx_strtoofft(nextarg, &unit, 0); + + if(!*unit) + unit = (char *)"b"; + else if(strlen(unit) > 1) + unit = (char *)"w"; /* unsupported */ + + switch(*unit) { + case 'G': + case 'g': + value *= 1024*1024*1024; + break; + case 'M': + case 'm': + value *= 1024*1024; + break; + case 'K': + case 'k': + value *= 1024; + break; + case 'b': + case 'B': + /* for plain bytes, leave as-is */ + break; + default: + warnf(config, "unsupported rate unit. Use G, M, K or B!\n"); + return PARAM_BAD_USE; + } + config->recvpersecond = value; + config->sendpersecond = value; + } + break; + + case 'j': /* --compressed */ + if(toggle && !(curlinfo->features & CURL_VERSION_LIBZ)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->encoding = toggle; + break; + + case 'J': /* --tr-encoding */ + config->tr_encoding = toggle; + break; + + case 'k': /* --digest */ + if(toggle) + config->authtype |= CURLAUTH_DIGEST; + else + config->authtype &= ~CURLAUTH_DIGEST; + break; + + case 'l': /* --negotiate */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) + config->authtype |= CURLAUTH_GSSNEGOTIATE; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_GSSNEGOTIATE; + break; + + case 'm': /* --ntlm */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_NTLM) + config->authtype |= CURLAUTH_NTLM; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_NTLM; + break; + + case 'M': /* --ntlm-wb */ + if(toggle) { + if(curlinfo->features & CURL_VERSION_NTLM_WB) + config->authtype |= CURLAUTH_NTLM_WB; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + } + else + config->authtype &= ~CURLAUTH_NTLM_WB; + break; + + case 'n': /* --basic for completeness */ + if(toggle) + config->authtype |= CURLAUTH_BASIC; + else + config->authtype &= ~CURLAUTH_BASIC; + break; + + case 'o': /* --anyauth, let libcurl pick it */ + if(toggle) + config->authtype = CURLAUTH_ANY; + /* --no-anyauth simply doesn't touch it */ + break; + +#ifdef USE_WATT32 + case 'p': /* --wdebug */ + dbug_init(); + break; +#endif + case 'q': /* --ftp-create-dirs */ + config->ftp_create_dirs = toggle; + break; + + case 'r': /* --create-dirs */ + config->create_dirs = TRUE; + break; + + case 's': /* --max-redirs */ + /* specified max no of redirects (http(s)) */ + if(str2num(&config->maxredirs, nextarg)) + return PARAM_BAD_NUMERIC; + break; + + case 't': /* --proxy-ntlm */ + if(curlinfo->features & CURL_VERSION_NTLM) + config->proxyntlm = toggle; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + + case 'u': /* --crlf */ + /* LF -> CRLF conversion? */ + config->crlf = TRUE; + break; + + case 'v': /* --stderr */ + if(strcmp(nextarg, "-")) { + FILE *newfile = fopen(nextarg, "wt"); + if(!newfile) + warnf(config, "Failed to open %s!\n", nextarg); + else { + if(config->errors_fopened) + fclose(config->errors); + config->errors = newfile; + config->errors_fopened = TRUE; + } + } + else + config->errors = stdout; + break; + case 'w': /* --interface */ + /* interface */ + GetStr(&config->iface, nextarg); + break; + case 'x': /* --krb */ + /* kerberos level string */ + if(curlinfo->features & (CURL_VERSION_KERBEROS4 | + CURL_VERSION_GSSNEGOTIATE)) + GetStr(&config->krblevel, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'y': /* --max-filesize */ + if(str2offset(&config->max_filesize, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case 'z': /* --disable-eprt */ + config->disable_eprt = toggle; + break; + case 'Z': /* --eprt */ + config->disable_eprt = (!toggle)?TRUE:FALSE; + break; + + default: /* the URL! */ + { + struct getout *url; + if(config->url_get || ((config->url_get = config->url_list) != NULL)) { + /* 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! */ + url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + else { + /* fill in the URL */ + GetStr(&url->url, nextarg); + url->flags |= GETOUT_URL; + } + } + } + break; + case '$': /* more options without a short option */ + switch(subletter) { + case 'a': /* --ftp-ssl */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl = toggle; + break; + case 'b': /* --ftp-pasv */ + Curl_safefree(config->ftpport); + break; + case 'c': /* --socks5 specifies a socks5 proxy to use, and resolves + the name locally and passes on the resolved address */ + GetStr(&config->socksproxy, nextarg); + config->socksver = CURLPROXY_SOCKS5; + break; + case 't': /* --socks4 specifies a socks4 proxy to use */ + GetStr(&config->socksproxy, nextarg); + config->socksver = CURLPROXY_SOCKS4; + break; + case 'T': /* --socks4a specifies a socks4a proxy to use */ + GetStr(&config->socksproxy, nextarg); + config->socksver = CURLPROXY_SOCKS4A; + break; + case '2': /* --socks5-hostname specifies a socks5 proxy and enables name + resolving with the proxy */ + GetStr(&config->socksproxy, nextarg); + config->socksver = CURLPROXY_SOCKS5_HOSTNAME; + break; + case 'd': /* --tcp-nodelay option */ + config->tcp_nodelay = toggle; + break; + case 'e': /* --proxy-digest */ + config->proxydigest = toggle; + break; + case 'f': /* --proxy-basic */ + config->proxybasic = toggle; + break; + case 'g': /* --retry */ + if(str2num(&config->req_retry, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case 'h': /* --retry-delay */ + if(str2num(&config->retry_delay, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case 'i': /* --retry-max-time */ + if(str2num(&config->retry_maxtime, nextarg)) + return PARAM_BAD_NUMERIC; + break; + + case 'k': /* --proxy-negotiate */ + if(curlinfo->features & CURL_VERSION_GSSNEGOTIATE) + config->proxynegotiate = toggle; + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'm': /* --ftp-account */ + GetStr(&config->ftp_account, nextarg); + break; + case 'n': /* --proxy-anyauth */ + config->proxyanyauth = toggle; + break; + case 'o': /* --trace-time */ + config->tracetime = toggle; + break; + case 'p': /* --ignore-content-length */ + config->ignorecl = toggle; + break; + case 'q': /* --ftp-skip-pasv-ip */ + config->ftp_skip_ip = toggle; + break; + case 'r': /* --ftp-method (undocumented at this point) */ + config->ftp_filemethod = ftpfilemethod(config, nextarg); + break; + case 's': /* --local-port */ + rc = sscanf(nextarg, "%d - %d", + &config->localport, + &config->localportrange); + if(!rc) + return PARAM_BAD_USE; + else if(rc == 1) + config->localportrange = 1; /* default number of ports to try */ + else { + config->localportrange -= config->localport; + if(config->localportrange < 1) { + warnf(config, "bad range input\n"); + return PARAM_BAD_USE; + } + } + break; + case 'u': /* --ftp-alternative-to-user */ + GetStr(&config->ftp_alternative_to_user, nextarg); + break; + case 'v': /* --ftp-ssl-reqd */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl_reqd = toggle; + break; + case 'w': /* --no-sessionid */ + config->disable_sessionid = (!toggle)?TRUE:FALSE; + break; + case 'x': /* --ftp-ssl-control */ + if(toggle && !(curlinfo->features & CURL_VERSION_SSL)) + return PARAM_LIBCURL_DOESNT_SUPPORT; + config->ftp_ssl_control = toggle; + break; + case 'y': /* --ftp-ssl-ccc */ + config->ftp_ssl_ccc = toggle; + if(!config->ftp_ssl_ccc_mode) + config->ftp_ssl_ccc_mode = CURLFTPSSL_CCC_PASSIVE; + break; + case 'j': /* --ftp-ssl-ccc-mode */ + config->ftp_ssl_ccc = TRUE; + config->ftp_ssl_ccc_mode = ftpcccmethod(config, nextarg); + break; + case 'z': /* --libcurl */ + GetStr(&config->libcurl, nextarg); + break; + case '#': /* --raw */ + config->raw = toggle; + break; + case '0': /* --post301 */ + config->post301 = toggle; + break; + case '1': /* --no-keepalive */ + config->nokeepalive = (!toggle)?TRUE:FALSE; + break; + case '3': /* --keepalive-time */ + if(str2num(&config->alivetime, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case '4': /* --post302 */ + config->post302 = toggle; + break; + case '5': /* --noproxy */ + /* This specifies the noproxy list */ + GetStr(&config->noproxy, nextarg); + break; +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + case '6': /* --socks5-gssapi-service */ + GetStr(&config->socks5_gssapi_service, nextarg); + break; + case '7': /* --socks5-gssapi-nec*/ + config->socks5_gssapi_nec = TRUE; + break; +#endif + case '8': /* --proxy1.0 */ + /* http 1.0 proxy */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_HTTP_1_0; + break; + case '9': /* --tftp-blksize */ + str2num(&config->tftp_blksize, nextarg); + break; + case 'A': /* --mail-from */ + GetStr(&config->mail_from, nextarg); + break; + case 'B': /* --mail-rcpt */ + /* append receiver to a list */ + err = add2list(&config->mail_rcpt, nextarg); + if(err) + return err; + break; + case 'C': /* --ftp-pret */ + config->ftp_pret = toggle; + break; + case 'D': /* --proto */ + config->proto_present = TRUE; + if(proto2num(config, &config->proto, nextarg)) + return PARAM_BAD_USE; + break; + case 'E': /* --proto-redir */ + config->proto_redir_present = TRUE; + if(proto2num(config, &config->proto_redir, nextarg)) + return PARAM_BAD_USE; + break; + case 'F': /* --resolve */ + err = add2list(&config->resolve, nextarg); + if(err) + return err; + break; + case 'G': /* --delegation LEVEL */ + config->gssapi_delegation = delegation(config, nextarg); + break; + } + break; + case '#': /* --progress-bar */ + if(toggle) + config->progressmode = CURL_PROGRESS_BAR; + else + config->progressmode = CURL_PROGRESS_STATS; + break; + case '~': /* --xattr */ + config->xattr = toggle; + break; + case '0': + /* HTTP version 1.0 */ + config->httpversion = CURL_HTTP_VERSION_1_0; + break; + case '1': + /* TLS version 1 */ + config->ssl_version = CURL_SSLVERSION_TLSv1; + break; + case '2': + /* SSL version 2 */ + config->ssl_version = CURL_SSLVERSION_SSLv2; + break; + case '3': + /* SSL version 3 */ + config->ssl_version = CURL_SSLVERSION_SSLv3; + break; + case '4': + /* IPv4 */ + config->ip_version = 4; + break; + case '6': + /* IPv6 */ + config->ip_version = 6; + break; + case 'a': + /* This makes the FTP sessions use APPE instead of STOR */ + config->ftp_append = toggle; + break; + case 'A': + /* This specifies the User-Agent name */ + GetStr(&config->useragent, nextarg); + break; + case 'b': /* cookie string coming up: */ + if(nextarg[0] == '@') { + nextarg++; + } + else if(strchr(nextarg, '=')) { + /* A cookie string must have a =-letter */ + GetStr(&config->cookie, nextarg); + break; + } + /* We have a cookie file to read from! */ + GetStr(&config->cookiefile, nextarg); + break; + case 'B': + /* use ASCII/text when transferring */ + config->use_ascii = toggle; + break; + case 'c': + /* get the file name to dump all cookies in */ + GetStr(&config->cookiejar, nextarg); + break; + case 'C': + /* This makes us continue an ftp transfer at given position */ + if(!curlx_strequal(nextarg, "-")) { + if(str2offset(&config->resume_from, nextarg)) + return PARAM_BAD_NUMERIC; + config->resume_from_current = FALSE; + } + else { + config->resume_from_current = TRUE; + config->resume_from = 0; + } + config->use_resume=TRUE; + break; + case 'd': + /* postfield data */ + { + char *postdata = NULL; + FILE *file; + size_t size = 0; + + if(subletter == 'e') { /* --data-urlencode*/ + /* [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. + */ + const char *p = strchr(nextarg, '='); + size_t nlen; + char is_file; + 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) { + /* a '@' letter, it means that a file name or - (stdin) follows */ + + if(curlx_strequal("-", p)) { + file = stdin; + set_binmode(stdin); + } + else { + file = fopen(p, "rb"); + if(!file) + warnf(config, + "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + err = file2memory(&postdata, &size, file); + + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + } + else { + GetStr(&postdata, p); + 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(config->easy, postdata, (int)size); + Curl_safefree(postdata); /* no matter if it worked or not */ + if(enc) { + /* now make a string with the name from above and append the + encoded string */ + size_t outlen = nlen + strlen(enc) + 2; + char *n = malloc(outlen); + if(!n) { + curl_free(enc); + return PARAM_NO_MEM; + } + if(nlen > 0) { /* only append '=' if we have a name */ + snprintf(n, outlen, "%.*s=%s", nlen, nextarg, enc); + size = outlen-1; + } + else { + strcpy(n, enc); + size = outlen-2; /* since no '=' was inserted */ + } + curl_free(enc); + postdata = n; + } + else + return PARAM_NO_MEM; + } + } + else if('@' == *nextarg) { + /* the data begins with a '@' letter, it means that a file name + or - (stdin) follows */ + nextarg++; /* pass the @ */ + + if(curlx_strequal("-", nextarg)) { + file = stdin; + if(subletter == 'b') /* forced data-binary */ + set_binmode(stdin); + } + else { + file = fopen(nextarg, "rb"); + if(!file) + warnf(config, "Couldn't read data from file \"%s\", this makes " + "an empty POST.\n", nextarg); + } + + if(subletter == 'b') + /* 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 { + GetStr(&postdata, nextarg); + if(postdata) + size = strlen(postdata); + } + +#ifdef CURL_DOES_CONVERSIONS + if(subletter != 'b') { + /* NOT forced binary, convert to ASCII */ + if(convert_to_network(postdata, strlen(postdata))) { + Curl_safefree(postdata); + return PARAM_NO_MEM; + } + } +#endif + + if(config->postfields) { + /* we already have a string, we append this one with a separating + &-letter */ + char *oldpost = config->postfields; + curl_off_t oldlen = config->postfieldsize; + curl_off_t newlen = oldlen + size + 2; + config->postfields = malloc((size_t)newlen); + if(!config->postfields) { + Curl_safefree(oldpost); + Curl_safefree(postdata); + return PARAM_NO_MEM; + } + memcpy(config->postfields, oldpost, (size_t)oldlen); + /* use byte value 0x26 for '&' to accommodate non-ASCII platforms */ + config->postfields[oldlen] = '\x26'; + memcpy(&config->postfields[oldlen+1], postdata, size); + config->postfields[oldlen+1+size] = '\0'; + Curl_safefree(oldpost); + Curl_safefree(postdata); + config->postfieldsize += size+1; + } + else { + config->postfields = postdata; + config->postfieldsize = size; + } + } + /* + We can't set the request type here, as this data might be used in + a simple GET if -G is used. Already or soon. + + if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) { + Curl_safefree(postdata); + return PARAM_BAD_USE; + } + */ + break; + case 'D': + /* dump-header to given file name */ + GetStr(&config->headerfile, nextarg); + break; + case 'e': + { + char *ptr = strstr(nextarg, ";auto"); + if(ptr) { + /* Automatic referer requested, this may be combined with a + set initial one */ + config->autoreferer = TRUE; + *ptr = 0; /* zero terminate here */ + } + else + config->autoreferer = FALSE; + GetStr(&config->referer, nextarg); + } + break; + case 'E': + switch(subletter) { + case 'a': /* CA info PEM file */ + /* CA info PEM file */ + GetStr(&config->cacert, nextarg); + break; + case 'b': /* cert file type */ + GetStr(&config->cert_type, nextarg); + break; + case 'c': /* private key file */ + GetStr(&config->key, nextarg); + break; + case 'd': /* private key file type */ + GetStr(&config->key_type, nextarg); + break; + case 'e': /* private key passphrase */ + GetStr(&config->key_passwd, nextarg); + cleanarg(nextarg); + break; + case 'f': /* crypto engine */ + GetStr(&config->engine, nextarg); + if(config->engine && curlx_raw_equal(config->engine,"list")) + config->list_engines = TRUE; + break; + case 'g': /* CA info PEM file */ + /* CA cert directory */ + GetStr(&config->capath, nextarg); + break; + case 'h': /* --pubkey public key file */ + GetStr(&config->pubkey, nextarg); + break; + case 'i': /* --hostpubmd5 md5 of the host public key */ + GetStr(&config->hostpubmd5, nextarg); + if(!config->hostpubmd5 || strlen(config->hostpubmd5) != 32) + return PARAM_BAD_USE; + break; + case 'j': /* CRL info PEM file */ + /* CRL file */ + GetStr(&config->crlfile, nextarg); + break; + case 'k': /* TLS username */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) + GetStr(&config->tls_username, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'l': /* TLS password */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) + GetStr(&config->tls_password, nextarg); + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + case 'm': /* TLS authentication type */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + GetStr(&config->tls_authtype, nextarg); + if(!strequal(config->tls_authtype, "SRP")) + return PARAM_LIBCURL_DOESNT_SUPPORT; /* only support TLS-SRP */ + } + else + return PARAM_LIBCURL_DOESNT_SUPPORT; + break; + default: /* certificate file */ + { + char *ptr = strchr(nextarg, ':'); + /* 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(ptr && + (ptr == &nextarg[1]) && + (nextarg[2] == '\\' || nextarg[2] == '/') && + (ISALPHA(nextarg[0])) ) + /* colon in the second column, followed by a backslash, and the + first character is an alphabetic letter: + + this is a drive letter colon */ + ptr = strchr(&nextarg[3], ':'); /* find the next one instead */ +#endif + if(ptr) { + /* we have a password too */ + *ptr = '\0'; + ptr++; + GetStr(&config->key_passwd, ptr); + } + GetStr(&config->cert, nextarg); + cleanarg(nextarg); + } + } + break; + case 'f': + /* fail hard on errors */ + config->failonerror = toggle; + break; + case 'F': + /* "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->httppost, + &config->last_post, + (subletter=='s')?TRUE:FALSE)) /* 's' means literal string */ + return PARAM_BAD_USE; + if(SetHTTPrequest(config, HTTPREQ_POST, &config->httpreq)) + return PARAM_BAD_USE; + break; + + case 'g': /* g disables URLglobbing */ + config->globoff = toggle; + break; + + case 'G': /* HTTP GET */ + config->use_httpget = TRUE; + break; + + case 'h': /* h for help */ + if(toggle) { + tool_help(); + return PARAM_HELP_REQUESTED; + } + /* we now actually support --no-help too! */ + break; + case 'H': + /* A custom header to append to a list */ + err = add2list(&config->headers, nextarg); + if(err) + return err; + break; + case 'i': + config->include_headers = toggle; /* include the headers as well in the + general output stream */ + break; + case 'j': + config->cookiesession = toggle; + break; + case 'I': + /* + * no_body will imply include_headers later on + */ + config->no_body = toggle; + if(SetHTTPrequest(config, + (config->no_body)?HTTPREQ_HEAD:HTTPREQ_GET, + &config->httpreq)) + return PARAM_BAD_USE; + break; + case 'J': /* --remote-header-name */ + if(config->include_headers) { + warnf(config, + "--include and --remote-header-name cannot be combined.\n"); + return PARAM_BAD_USE; + } + config->content_disposition = toggle; + break; + case 'k': /* allow insecure SSL connects */ + config->insecure_ok = toggle; + break; + case 'K': /* parse config file */ + if(parseconfig(nextarg, config)) + warnf(config, "error trying read config from the '%s' file\n", + nextarg); + break; + case 'l': + config->dirlistonly = toggle; /* only list the names of the FTP dir */ + break; + case 'L': + config->followlocation = toggle; /* Follow Location: HTTP headers */ + switch (subletter) { + case 't': + /* Continue to send authentication (user+password) when following + * locations, even when hostname changed */ + config->unrestricted_auth = toggle; + break; + } + break; + case 'm': + /* specified max time */ + if(str2num(&config->timeout, nextarg)) + return PARAM_BAD_NUMERIC; + break; + case 'M': /* M for manual, huge help */ + if(toggle) { /* --no-manual shows no manual... */ +#ifdef USE_MANUAL + hugehelp(); + return PARAM_HELP_REQUESTED; +#else + warnf(config, + "built-in manual was disabled at build-time!\n"); + return PARAM_OPTION_UNKNOWN; +#endif + } + break; + case 'n': + switch(subletter) { + case 'o': /* CA info PEM file */ + /* use .netrc or URL */ + config->netrc_opt = toggle; + break; + case 'e': /* netrc-file */ + GetStr(&config->netrc_file, nextarg); + break; + default: + /* pick info from .netrc, if this is used for http, curl will + automatically enfore user+password with the request */ + config->netrc = toggle; + break; + } + break; + case 'N': + /* disable the output I/O buffering. note that the option is called + --buffer but is mostly used in the negative form: --no-buffer */ + if(longopt) + config->nobuffer = (!toggle)?TRUE:FALSE; + else + config->nobuffer = toggle; + break; + case 'O': /* --remote-name */ + if(subletter == 'a') { /* --remote-name-all */ + config->default_node_flags = toggle?GETOUT_USEREMOTE:0; + break; + } + /* fall-through! */ + case 'o': /* --output */ + /* output file */ + { + struct getout *url; + if(config->url_out || ((config->url_out = config->url_list) != NULL)) { + /* 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 + /* there was no free node, create one! */ + url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + else { + /* fill in the outfile */ + if('o' == letter) { + GetStr(&url->outfile, nextarg); + 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 'P': + /* This makes the FTP sessions use PORT instead of PASV */ + /* use <eth0> or <192.168.10.10> style addresses. Anything except + this will make us try to get the "default" address. + NOTE: this is a changed behaviour since the released 4.1! + */ + GetStr(&config->ftpport, nextarg); + break; + case 'p': + /* proxy tunnel for non-http protocols */ + config->proxytunnel = toggle; + break; + + case 'q': /* if used first, already taken care of, we do it like + this so we don't cause an error! */ + break; + case 'Q': + /* 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; + } + if(err) + return err; + break; + case 'r': + /* 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]; + curl_off_t off; + warnf(config, + "A specified range MUST include at least one dash (-). " + "Appending one for you!\n"); + off = curlx_strtoofft(nextarg, NULL, 10); + snprintf(buffer, sizeof(buffer), "%" CURL_FORMAT_CURL_OFF_T "-", off); + Curl_safefree(config->range); + config->range = strdup(buffer); + if(!config->range) + return PARAM_NO_MEM; + } + { + /* byte range requested */ + char *tmp_range; + tmp_range = nextarg; + while(*tmp_range != '\0') { + if(!ISDIGIT(*tmp_range) && *tmp_range != '-' && *tmp_range != ',') { + warnf(config,"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.\n"); + break; + } + tmp_range++; + } + /* byte range requested */ + GetStr(&config->range, nextarg); + } + break; + case 'R': + /* use remote file's time */ + config->remote_time = toggle; + break; + case 's': + /* don't show progress meter, don't show errors : */ + if(toggle) + config->mute = config->noprogress = TRUE; + else + config->mute = config->noprogress = FALSE; + if(config->showerror < 0) + /* if still on the default value, set showerror to the reverse of + toggle. This is to allow -S and -s to be used in an independent + order but still have the same effect. */ + config->showerror = (!toggle)?TRUE:FALSE; /* toggle off */ + break; + case 'S': + /* show errors */ + config->showerror = toggle?1:0; /* toggle on if used with -s */ + break; + case 't': + /* Telnet options */ + err = add2list(&config->telnet_options, nextarg); + if(err) + return err; + break; + case 'T': + /* we are uploading */ + { + struct getout *url; + if(config->url_out || ((config->url_out = config->url_list) != NULL)) { + /* 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_UPLOAD)) + 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 + /* there was no free node, create one! */ + url = new_getout(config); + + if(!url) + return PARAM_NO_MEM; + else { + url->flags |= GETOUT_UPLOAD; /* mark -T used */ + if(!*nextarg) + url->flags |= GETOUT_NOUPLOAD; + else { + /* "-" equals stdin, but keep the string around for now */ + GetStr(&url->infile, nextarg); + } + } + } + break; + case 'u': + /* user:password */ + GetStr(&config->userpwd, nextarg); + cleanarg(nextarg); + err = checkpasswd("host", &config->userpwd); + if(err) + return err; + break; + case 'U': + /* Proxy user:password */ + GetStr(&config->proxyuserpwd, nextarg); + cleanarg(nextarg); + err = checkpasswd("proxy", &config->proxyuserpwd); + if(err) + return err; + break; + case 'v': + if(toggle) { + /* the '%' thing here will cause the trace get sent to stderr */ + Curl_safefree(config->trace_dump); + config->trace_dump = strdup("%"); + if(!config->trace_dump) + return PARAM_NO_MEM; + if(config->tracetype && (config->tracetype != TRACE_PLAIN)) + warnf(config, + "-v, --verbose overrides an earlier trace/verbose option\n"); + config->tracetype = TRACE_PLAIN; + } + else + /* verbose is disabled here */ + config->tracetype = TRACE_NONE; + break; + case 'V': + { + const char *const *proto; + + if(!toggle) + /* --no-version yields no output! */ + break; + + printf(CURL_ID "%s\n", curl_version()); + if(curlinfo->protocols) { + printf("Protocols: "); + for(proto = curlinfo->protocols; *proto; ++proto) { + printf("%s ", *proto); + } + puts(""); /* newline */ + } + if(curlinfo->features) { + unsigned int i; + printf("Features: "); + for(i = 0; i < sizeof(feats)/sizeof(feats[0]); i++) { + if(curlinfo->features & feats[i].bitmask) + printf("%s ", feats[i].name); + } + puts(""); /* newline */ + } + } + return PARAM_HELP_REQUESTED; + case 'w': + /* 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(curlx_strequal("-", nextarg)) { + fname = "<stdin>"; + file = stdin; + } + else { + fname = nextarg; + file = fopen(nextarg, "r"); + } + err = file2string(&config->writeout, file); + if(file && (file != stdin)) + fclose(file); + if(err) + return err; + if(!config->writeout) + warnf(config, "Failed to read %s", fname); + } + else + GetStr(&config->writeout, nextarg); + break; + case 'x': + /* proxy */ + GetStr(&config->proxy, nextarg); + config->proxyver = CURLPROXY_HTTP; + break; + case 'X': + /* set custom request */ + GetStr(&config->customrequest, nextarg); + break; + case 'y': + /* low speed time */ + if(str2num(&config->low_speed_time, nextarg)) + return PARAM_BAD_NUMERIC; + if(!config->low_speed_limit) + config->low_speed_limit = 1; + break; + case 'Y': + /* low speed limit */ + if(str2num(&config->low_speed_limit, nextarg)) + return PARAM_BAD_NUMERIC; + if(!config->low_speed_time) + config->low_speed_time = 30; + break; + case 'z': /* time condition coming up */ + switch(*nextarg) { + case '+': + nextarg++; + 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_getdate(nextarg, &now); + if(-1 == (int)config->condtime) { + /* now let's see if it is a file name to get the time from instead! */ + struct_stat statbuf; + if(-1 == stat(nextarg, &statbuf)) { + /* failed, remove time condition */ + config->timecond = CURL_TIMECOND_NONE; + warnf(config, + "Illegal date format for -z, --timecond (and not " + "a file name). Disabling time condition. " + "See curl_getdate(3) for valid date syntax.\n"); + } + else { + /* pull the time out from the file */ + config->condtime = statbuf.st_mtime; + } + } + break; + default: /* unknown flag */ + return PARAM_OPTION_UNKNOWN; + } + hit = -1; + + } while(!longopt && !singleopt && *++parse && !*usedarg); + + return PARAM_OK; +} + diff --git a/src/tool_getparam.h b/src/tool_getparam.h new file mode 100644 index 000000000..c402fd77b --- /dev/null +++ b/src/tool_getparam.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_TOOL_GETPARAM_H +#define HEADER_CURL_TOOL_GETPARAM_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +typedef enum { + PARAM_OK, + PARAM_OPTION_AMBIGUOUS, + PARAM_OPTION_UNKNOWN, + PARAM_REQUIRES_PARAMETER, + PARAM_BAD_USE, + PARAM_HELP_REQUESTED, + PARAM_GOT_EXTRA_PARAMETER, + PARAM_BAD_NUMERIC, + PARAM_LIBCURL_DOESNT_SUPPORT, + PARAM_NO_MEM, + PARAM_LAST +} ParameterError; + +ParameterError getparameter(char *flag, + char *nextarg, + bool *usedarg, + struct Configurable *config); + +#endif /* HEADER_CURL_TOOL_GETPARAM_H */ + diff --git a/src/getpass.c b/src/tool_getpass.c index 95d257b2f..b6aa5dd5e 100644 --- a/src/getpass.c +++ b/src/tool_getpass.c @@ -19,46 +19,52 @@ * KIND, either express or implied. * ***************************************************************************/ - -/* This file is a reimplementation of the previous one, due to license - problems. */ - #include "setup.h" #ifndef HAVE_GETPASS_R /* this file is only for systems without getpass_r() */ -#include <stdio.h> -#include <string.h> - #ifdef HAVE_UNISTD_H -#include <unistd.h> +# include <unistd.h> #endif -#include "getpass.h" - #ifdef HAVE_FCNTL_H -#include <fcntl.h> +# include <fcntl.h> #endif + #ifdef HAVE_TERMIOS_H -#include <termios.h> -#else -#ifdef HAVE_TERMIO_H -#include <termio.h> +# include <termios.h> +#elif defined(HAVE_TERMIO_H) +# include <termio.h> #endif + +#ifdef __VMS +# include descrip +# include starlet +# include iodef +#endif + +#ifdef WIN32 +# include <conio.h> #endif -/* The last #include file should be: */ -#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG) -#include "memdebug.h" +#ifdef NETWARE +# ifdef __NOVELL_LIBC__ +# include <screen.h> +# else +# include <nwconio.h> +# endif #endif +#define _MPRINTF_REPLACE +#include <curl/mprintf.h> + +#include "tool_getpass.h" + +#include "memdebug.h" /* keep this as LAST include */ + #ifdef __VMS /* VMS implementation */ -#include descrip -#include starlet -#include iodef -/* #include iosbdef */ char *getpass_r(const char *prompt, char *buffer, size_t buflen) { long sts; @@ -76,15 +82,15 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) $DESCRIPTOR(ttdesc, "TT"); - buffer[0]='\0'; - sts = sys$assign(&ttdesc, &chan,0,0); + 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)) + if((sts & 1) && (iosb.iosb$w_status & 1)) buffer[iosb.iosb$w_bcnt] = '\0'; sts = sys$dassgn(chan); @@ -94,14 +100,8 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) #define DONE #endif /* __VMS */ - -#ifdef WIN32 -/* Windows implementation */ -#include <conio.h> -#endif - #ifdef __SYMBIAN32__ -#define getch() getchar() +# define getch() getchar() #endif #if defined(WIN32) || defined(__SYMBIAN32__) @@ -111,25 +111,25 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) size_t i; fputs(prompt, stderr); - for(i=0; i<buflen; i++) { + for(i = 0; i < buflen; i++) { buffer[i] = (char)getch(); if(buffer[i] == '\r' || buffer[i] == '\n') { - buffer[i] = 0; + 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); + i = i - (i >= 1) ? 2 : 1; } #ifndef __SYMBIAN32__ /* since echo is disabled, print a newline */ fputs("\n", stderr); #endif /* if user didn't hit ENTER, terminate buffer */ - if(i==buflen) - buffer[buflen-1]=0; + if(i == buflen) + buffer[buflen-1] = '\0'; return buffer; /* we always return success */ } @@ -139,13 +139,11 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) #ifdef NETWARE /* NetWare implementation */ #ifdef __NOVELL_LIBC__ -#include <screen.h> char *getpass_r(const char *prompt, char *buffer, size_t buflen) { return getpassword(prompt, buffer, buflen); } #else -#include <nwconio.h> char *getpass_r(const char *prompt, char *buffer, size_t buflen) { size_t i = 0; @@ -169,7 +167,7 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) putchar('*'); } while((buffer[i-1] != 13) && (i < buflen)); - buffer[i-1] = 0; + buffer[i-1] = '\0'; printf("\r\n"); return buffer; } @@ -180,13 +178,11 @@ char *getpass_r(const char *prompt, char *buffer, size_t buflen) #ifndef DONE /* not previously provided */ #ifdef HAVE_TERMIOS_H -#define struct_term struct termios -#else -#ifdef HAVE_TERMIO_H -#define struct_term struct termio +# define struct_term struct termios +#elif defined(HAVE_TERMIO_H) +# define struct_term struct termio #else -#undef struct_term -#endif +# undef struct_term #endif static bool ttyecho(bool enable, int fd) @@ -203,18 +199,16 @@ static bool ttyecho(bool enable, int fd) noecho = withecho; noecho.c_lflag &= ~ECHO; tcsetattr(fd, TCSANOW, &noecho); -#else /* HAVE_TERMIOS_H */ -#ifdef HAVE_TERMIO_H +#elif defined(HAVE_TERMIO_H) ioctl(fd, TCGETA, &withecho); noecho = withecho; noecho.c_lflag &= ~ECHO; ioctl(fd, TCSETA, &noecho); -#else /* HAVE_TERMIO_H */ -/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ - (void)fd; /* prevent compiler warning on unused variable */ +#else + /* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H, we can't disable echo! */ + (void)fd; return FALSE; /* not disabled */ #endif -#endif return TRUE; /* disabled */ } else { @@ -222,14 +216,11 @@ static bool ttyecho(bool enable, int fd) now use to reset the terminal status) */ #ifdef HAVE_TERMIOS_H tcsetattr(fd, TCSAFLUSH, &withecho); -#else /* HAVE_TERMIOS_H */ -#ifdef HAVE_TERMIO_H +#elif defined(HAVE_TERMIO_H) ioctl(fd, TCSETA, &withecho); #else -/* neither HAVE_TERMIO_H nor HAVE_TERMIOS_H */ return FALSE; /* not enabled */ #endif -#endif return TRUE; /* enabled */ } } @@ -240,18 +231,18 @@ char *getpass_r(const char *prompt, /* prompt to display */ { ssize_t nread; bool disabled; - int fd=open("/dev/tty", O_RDONLY); + int fd = open("/dev/tty", O_RDONLY); if(-1 == fd) fd = 1; /* use stdin if the tty couldn't be used */ disabled = ttyecho(FALSE, fd); /* disable terminal echo */ fputs(prompt, stderr); - nread=read(fd, password, buflen); + nread = read(fd, password, buflen); if(nread > 0) - password[--nread]=0; /* zero terminate where enter is stored */ + password[--nread] = '\0'; /* zero terminate where enter is stored */ else - password[0]=0; /* got nothing */ + password[0] = '\0'; /* got nothing */ if(disabled) { /* if echo actually was disabled, add a newline */ diff --git a/src/getpass.h b/src/tool_getpass.h index 3b29d47a1..506d0feef 100644 --- a/src/getpass.h +++ b/src/tool_getpass.h @@ -1,5 +1,5 @@ -#ifndef __GETPASS_H -#define __GETPASS_H +#ifndef HEADER_CURL_TOOL_GETPASS_H +#define HEADER_CURL_TOOL_GETPASS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,8 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "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. */ @@ -28,7 +30,7 @@ /* * Returning NULL will abort the continued operation! */ -char* getpass_r(const char *prompt, char* buffer, size_t buflen ); +char* getpass_r(const char *prompt, char* buffer, size_t buflen); #endif -#endif +#endif /* HEADER_CURL_TOOL_GETPASS_H */ diff --git a/src/tool_help.c b/src/tool_help.c new file mode 100644 index 000000000..7c7d8d315 --- /dev/null +++ b/src/tool_help.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include "tool_panykey.h" +#include "tool_help.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef MSDOS +# define USE_WATT32 +#endif + +/* + * A few of these source lines are >80 columns wide, but that's only because + * breaking the strings narrower makes this chunk look even worse! + * + * Starting with 7.18.0, this list of command line options is sorted based + * on the long option name. It is not done automatically, although a command + * line like the following can help out: + * + * curl --help | cut -c5- | grep "^-" | sort + */ + +static const char *const helptext[] = { + "Usage: curl [options...] <url>", + "Options: (H) means HTTP/HTTPS only, (F) means FTP only", + " --anyauth Pick \"any\" authentication method (H)", + " -a, --append Append to target file when uploading (F/SFTP)", + " --basic Use HTTP Basic Authentication (H)", + " --cacert FILE CA certificate to verify peer against (SSL)", + " --capath DIR CA directory to verify peer against (SSL)", + " -E, --cert CERT[:PASSWD] Client certificate file and password (SSL)", + " --cert-type TYPE Certificate file type (DER/PEM/ENG) (SSL)", + " --ciphers LIST SSL ciphers to use (SSL)", + " --compressed Request compressed response (using deflate or gzip)", + " -K, --config FILE Specify which config file to read", + " --connect-timeout SECONDS Maximum time allowed for connection", + " -C, --continue-at OFFSET Resumed transfer offset", + " -b, --cookie STRING/FILE String or file to read cookies from (H)", + " -c, --cookie-jar FILE Write cookies to this file after operation (H)", + " --create-dirs Create necessary local directory hierarchy", + " --crlf Convert LF to CRLF in upload", + " --crlfile FILE Get a CRL list in PEM format from the given file", + " -d, --data DATA HTTP POST data (H)", + " --data-ascii DATA HTTP POST ASCII data (H)", + " --data-binary DATA HTTP POST binary data (H)", + " --data-urlencode DATA HTTP POST data url encoded (H)", + " --delegation STRING GSS-API delegation permission", + " --digest Use HTTP Digest Authentication (H)", + " --disable-eprt Inhibit using EPRT or LPRT (F)", + " --disable-epsv Inhibit using EPSV (F)", + " -D, --dump-header FILE Write the headers to this file", + " --egd-file FILE EGD socket path for random data (SSL)", + " --engine ENGINGE Crypto engine (SSL). \"--engine list\" for list", +#ifdef USE_ENVIRONMENT + " --environment Write results to environment variables (RISC OS)", +#endif + " -f, --fail Fail silently (no output at all) on HTTP errors (H)", + " -F, --form CONTENT Specify HTTP multipart POST data (H)", + " --form-string STRING Specify HTTP multipart POST data (H)", + " --ftp-account DATA Account data string (F)", + " --ftp-alternative-to-user COMMAND " + "String to replace \"USER [name]\" (F)", + " --ftp-create-dirs Create the remote dirs if not present (F)", + " --ftp-method [MULTICWD/NOCWD/SINGLECWD] Control CWD usage (F)", + " --ftp-pasv Use PASV/EPSV instead of PORT (F)", + " -P, --ftp-port ADR Use PORT with given address instead of PASV (F)", + " --ftp-skip-pasv-ip Skip the IP address for PASV (F)\n" + " --ftp-pret Send PRET before PASV (for drftpd) (F)", + " --ftp-ssl-ccc Send CCC after authenticating (F)", + " --ftp-ssl-ccc-mode ACTIVE/PASSIVE Set CCC mode (F)", + " --ftp-ssl-control Require SSL/TLS for ftp login, " + "clear for transfer (F)", + " -G, --get Send the -d data with a HTTP GET (H)", + " -g, --globoff Disable URL sequences and ranges using {} and []", + " -H, --header LINE Custom header to pass to server (H)", + " -I, --head Show document info only", + " -h, --help This help text", + " --hostpubmd5 MD5 " + "Hex encoded MD5 string of the host public key. (SSH)", + " -0, --http1.0 Use HTTP 1.0 (H)", + " --ignore-content-length Ignore the HTTP Content-Length header", + " -i, --include Include protocol headers in the output (H/F)", + " -k, --insecure Allow connections to SSL sites without certs (H)", + " --interface INTERFACE Specify network interface/address to use", + " -4, --ipv4 Resolve name to IPv4 address", + " -6, --ipv6 Resolve name to IPv6 address", + " -j, --junk-session-cookies Ignore session cookies read from file (H)", + " --keepalive-time SECONDS Interval between keepalive probes", + " --key KEY Private key file name (SSL/SSH)", + " --key-type TYPE Private key file type (DER/PEM/ENG) (SSL)", + " --krb LEVEL Enable Kerberos with specified security level (F)", + " --libcurl FILE Dump libcurl equivalent code of this command line", + " --limit-rate RATE Limit transfer speed to this rate", + " -l, --list-only List only names of an FTP directory (F)", + " --local-port RANGE Force use of these local port numbers", + " -L, --location Follow redirects (H)", + " --location-trusted like --location and send auth to other hosts (H)", + " -M, --manual Display the full manual", + " --mail-from FROM Mail from this address", + " --mail-rcpt TO Mail to this receiver(s)", + " --max-filesize BYTES Maximum file size to download (H/F)", + " --max-redirs NUM Maximum number of redirects allowed (H)", + " -m, --max-time SECONDS Maximum time allowed for the transfer", + " --negotiate Use HTTP Negotiate Authentication (H)", + " -n, --netrc Must read .netrc for user name and password", + " --netrc-optional Use either .netrc or URL; overrides -n", + " --netrc-file FILE Set up the netrc filename to use", + " -N, --no-buffer Disable buffering of the output stream", + " --no-keepalive Disable keepalive use on the connection", + " --no-sessionid Disable SSL session-ID reusing (SSL)", + " --noproxy List of hosts which do not use proxy", + " --ntlm Use HTTP NTLM authentication (H)", + " -o, --output FILE Write output to <file> instead of stdout", + " --pass PASS Pass phrase for the private key (SSL/SSH)", + " --post301 " + "Do not switch to GET after following a 301 redirect (H)", + " --post302 " + "Do not switch to GET after following a 302 redirect (H)", + " -#, --progress-bar Display transfer progress as a progress bar", + " --proto PROTOCOLS Enable/disable specified protocols", + " --proto-redir PROTOCOLS " + "Enable/disable specified protocols on redirect", + " -x, --proxy [PROTOCOL://]HOST[:PORT] Use proxy on given port", + " --proxy-anyauth Pick \"any\" proxy authentication method (H)", + " --proxy-basic Use Basic authentication on the proxy (H)", + " --proxy-digest Use Digest authentication on the proxy (H)", + " --proxy-negotiate Use Negotiate authentication on the proxy (H)", + " --proxy-ntlm Use NTLM authentication on the proxy (H)", + " -U, --proxy-user USER[:PASSWORD] Proxy user and password", + " --proxy1.0 HOST[:PORT] Use HTTP/1.0 proxy on given port", + " -p, --proxytunnel Operate through a HTTP proxy tunnel (using CONNECT)", + " --pubkey KEY Public key file name (SSH)", + " -Q, --quote CMD Send command(s) to server before transfer (F/SFTP)", + " --random-file FILE File for reading random data from (SSL)", + " -r, --range RANGE Retrieve only the bytes within a range", + " --raw Do HTTP \"raw\", without any transfer decoding (H)", + " -e, --referer Referer URL (H)", + " -J, --remote-header-name Use the header-provided filename (H)", + " -O, --remote-name Write output to a file named as the remote file", + " --remote-name-all Use the remote file name for all URLs", + " -R, --remote-time Set the remote file's time on the local output", + " -X, --request COMMAND Specify request command to use", + " --resolve HOST:PORT:ADDRESS Force resolve of HOST:PORT to ADDRESS", + " --retry NUM " + "Retry request NUM times if transient problems occur", + " --retry-delay SECONDS " + "When retrying, wait this many seconds between each", + " --retry-max-time SECONDS Retry only within this period", + " -S, --show-error " + "Show error. With -s, make curl show errors when they occur", + " -s, --silent Silent mode. Don't output anything", + " --socks4 HOST[:PORT] SOCKS4 proxy on given host + port", + " --socks4a HOST[:PORT] SOCKS4a proxy on given host + port", + " --socks5 HOST[:PORT] SOCKS5 proxy on given host + port", + " --socks5-hostname HOST[:PORT] " + "SOCKS5 proxy, pass host name to proxy", +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + " --socks5-gssapi-service NAME SOCKS5 proxy service name for gssapi", + " --socks5-gssapi-nec Compatibility with NEC SOCKS5 server", +#endif + " -Y, --speed-limit RATE " + "Stop transfers below speed-limit for 'speed-time' secs", + " -y, --speed-time SECONDS " + "Time for trig speed-limit abort. Defaults to 30", + " --ssl Try SSL/TLS (FTP, IMAP, POP3, SMTP)", + " --ssl-reqd Require SSL/TLS (FTP, IMAP, POP3, SMTP)", + " -2, --sslv2 Use SSLv2 (SSL)", + " -3, --sslv3 Use SSLv3 (SSL)", + " --stderr FILE Where to redirect stderr. - means stdout", + " --tcp-nodelay Use the TCP_NODELAY option", + " -t, --telnet-option OPT=VAL Set telnet option", + " --tftp-blksize VALUE Set TFTP BLKSIZE option (must be >512)", + " -z, --time-cond TIME Transfer based on a time condition", + " -1, --tlsv1 Use TLSv1 (SSL)", + " --trace FILE Write a debug trace to the given file", + " --trace-ascii FILE Like --trace but without the hex output", + " --trace-time Add time stamps to trace/verbose output", + " --tr-encoding Request compressed transfer encoding (H)", + " -T, --upload-file FILE Transfer FILE to destination", + " --url URL URL to work with", + " -B, --use-ascii Use ASCII/text transfer", + " -u, --user USER[:PASSWORD] Server user and password", + " --tlsuser USER TLS username", + " --tlspassword STRING TLS password", + " --tlsauthtype STRING TLS authentication type (default SRP)", + " -A, --user-agent STRING User-Agent to send to server (H)", + " -v, --verbose Make the operation more talkative", + " -V, --version Show version number and quit", +#ifdef USE_WATT32 + " --wdebug Turn on Watt-32 debugging", +#endif + " -w, --write-out FORMAT What to output after completion", + " --xattr Store metadata in extended file attributes", + " -q If used as the first parameter disables .curlrc", + NULL +}; + +#ifdef NETWARE +# define PRINT_LINES_PAUSE 23 +#endif + +#ifdef __SYMBIAN32__ +# define PRINT_LINES_PAUSE 16 +#endif + +void tool_help(void) +{ + int i; + for(i = 0; helptext[i]; i++) { + puts(helptext[i]); +#ifdef PRINT_LINES_PAUSE + if(i && ((i % PRINT_LINES_PAUSE) == 0)) + tool_pressanykey(); +#endif + } +} + diff --git a/src/writeenv.h b/src/tool_help.h index 8d92f6c89..f9664113a 100644 --- a/src/writeenv.h +++ b/src/tool_help.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_WRITEENV_H -#define HEADER_CURL_WRITEENV_H +#ifndef HEADER_CURL_TOOL_HELP_H +#define HEADER_CURL_TOOL_HELP_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,7 +21,9 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" -void ourWriteEnv(CURL *curl); +void tool_help(void); + +#endif /* HEADER_CURL_TOOL_HELP_H */ -#endif /* HEADER_CURL_WRITEENV_H */ diff --git a/src/tool_helpers.c b/src/tool_helpers.c new file mode 100644 index 000000000..b6371785d --- /dev/null +++ b/src/tool_helpers.c @@ -0,0 +1,78 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.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 tha 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_LIBCURL_DOESNT_SUPPORT: + return "the installed libcurl version doesn't support this"; + case PARAM_NO_MEM: + return "out of memory"; + default: + return "unknown error"; + } +} + +int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store) +{ + if((*store == HTTPREQ_UNSPEC) || + (*store == req)) { + *store = req; + return 0; + } + warnf(config, "You can only select one HTTP request!\n"); + return 1; +} + diff --git a/src/tool_helpers.h b/src/tool_helpers.h new file mode 100644 index 000000000..4385bfce4 --- /dev/null +++ b/src/tool_helpers.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_TOOL_HELPERS_H +#define HEADER_CURL_TOOL_HELPERS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +const char *param2text(int res); + +int SetHTTPrequest(struct Configurable *config, HttpReq req, HttpReq *store); + +#endif /* HEADER_CURL_TOOL_HELPERS_H */ + diff --git a/src/homedir.c b/src/tool_homedir.c index 52f69c7ee..95d25c74f 100644 --- a/src/homedir.c +++ b/src/tool_homedir.c @@ -19,31 +19,23 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> - #ifdef HAVE_PWD_H -#include <pwd.h> +# include <pwd.h> #endif #ifdef HAVE_UNISTD_H -#include <unistd.h> +# include <unistd.h> #endif #ifdef __VMS -#include <unixlib.h> +# include <unixlib.h> #endif -#include "homedir.h" +#include "tool_homedir.h" -#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG) -#include "memdebug.h" -#endif +#include "memdebug.h" /* keep this as LAST include */ -static -char *GetEnv(const char *variable, char do_expand) +static char *GetEnv(const char *variable, char do_expand) { char *env = NULL; #ifdef WIN32 @@ -77,7 +69,7 @@ char *GetEnv(const char *variable, char do_expand) env = getenv(variable); #endif #endif - return (env && env[0])?strdup(env):NULL; + return (env && env[0]) ? strdup(env) : NULL; } /* return the home directory of the current user as an allocated string */ diff --git a/src/homedir.h b/src/tool_homedir.h index c88d51723..109c1f282 100644 --- a/src/homedir.h +++ b/src/tool_homedir.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_HOMEDIR_H -#define HEADER_CURL_HOMEDIR_H +#ifndef HEADER_CURL_TOOL_HOMEDIR_H +#define HEADER_CURL_TOOL_HOMEDIR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,7 +21,8 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" char *homedir(void); -#endif /* HEADER_CURL_HOMEDIR_H */ +#endif /* HEADER_CURL_TOOL_HOMEDIR_H */ diff --git a/src/tool_libinfo.c b/src/tool_libinfo.c new file mode 100644 index 000000000..1469c8807 --- /dev/null +++ b/src/tool_libinfo.c @@ -0,0 +1,102 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_libinfo.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* global variable definitions, for libcurl run-time info */ + +curl_version_info_data *curlinfo = NULL; +long built_in_protos = 0; + +/* + * libcurl_info_init: retrieves run-time information about libcurl, + * setting a global pointer 'curlinfo' to libcurl's run-time info + * struct, and a global bit pattern 'built_in_protos' composed of + * CURLPROTO_* bits indicating which protocols are actually built + * into library being used. + */ + +CURLcode get_libcurl_info(void) +{ + static struct proto_name_pattern { + const char *proto_name; + long proto_pattern; + } const possibly_built_in[] = { + { "dict", CURLPROTO_DICT }, + { "file", CURLPROTO_FILE }, + { "ftp", CURLPROTO_FTP }, + { "ftps", CURLPROTO_FTPS }, + { "gopher", CURLPROTO_GOPHER }, + { "http", CURLPROTO_HTTP }, + { "https", CURLPROTO_HTTPS }, + { "imap", CURLPROTO_IMAP }, + { "imaps", CURLPROTO_IMAPS }, + { "ldap", CURLPROTO_LDAP }, + { "ldaps", CURLPROTO_LDAPS }, + { "pop3", CURLPROTO_POP3 }, + { "pop3s", CURLPROTO_POP3S }, + { "rtmp", CURLPROTO_RTMP }, + { "rtsp", CURLPROTO_RTSP }, + { "scp", CURLPROTO_SCP }, + { "sftp", CURLPROTO_SFTP }, + { "smtp", CURLPROTO_SMTP }, + { "smtps", CURLPROTO_SMTPS }, + { "telnet", CURLPROTO_TELNET }, + { "tftp", CURLPROTO_TFTP }, + { NULL, 0 } + }; + + struct proto_name_pattern const *p; + const char *const *proto; + + /* Pointer to libcurl's run-time version information */ + curlinfo = curl_version_info(CURLVERSION_NOW); + if(!curlinfo) + return CURLE_FAILED_INIT; + + /* Build CURLPROTO_* bit pattern with libcurl's built-in protocols */ + built_in_protos = 0; + if(curlinfo->protocols) { + for(proto = curlinfo->protocols; *proto; proto++) { + for(p = possibly_built_in; p->proto_name; p++) { + if(curlx_raw_equal(*proto, p->proto_name)) { + built_in_protos |= p->proto_pattern; + break; + } + } + } + } + + return CURLE_OK; +} + diff --git a/src/tool_libinfo.h b/src/tool_libinfo.h new file mode 100644 index 000000000..dfdf78a61 --- /dev/null +++ b/src/tool_libinfo.h @@ -0,0 +1,34 @@ +#ifndef HEADER_CURL_TOOL_LIBINFO_H +#define HEADER_CURL_TOOL_LIBINFO_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* global variable declarations, for libcurl run-time info */ + +extern curl_version_info_data *curlinfo; +extern long built_in_protos; + +CURLcode get_libcurl_info(void); + +#endif /* HEADER_CURL_TOOL_LIBINFO_H */ + diff --git a/src/tool_main.c b/src/tool_main.c new file mode 100644 index 000000000..86780c7f1 --- /dev/null +++ b/src/tool_main.c @@ -0,0 +1,112 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include <sys/stat.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_convert.h" +#include "tool_operate.h" +#include "tool_panykey.h" +#include "tool_vms.h" +#include "tool_main.h" + +/* + * This is low-level hard-hacking memory leak tracking and similar. Using + * the library level code from this client-side is ugly, but we do this + * anyway for convenience. + */ +#include "memdebug.h" /* keep this as LAST include */ + +#ifdef __VMS +static int vms_show = 0; +#endif + +/* + * Ensure that file descriptors 0, 1 and 2 (stdin, stdout, stderr) are + * open before starting to run. Otherwise, the first three network + * sockets opened by curl could be used for input sources, downloaded data + * or error logs as they will effectively be stdin, stdout and/or stderr. + */ +static void main_checkfds(void) +{ +#ifdef HAVE_PIPE + int fd[2] = { STDIN_FILENO, STDIN_FILENO }; + while(fd[0] == STDIN_FILENO || + fd[0] == STDOUT_FILENO || + fd[0] == STDERR_FILENO || + fd[1] == STDIN_FILENO || + fd[1] == STDOUT_FILENO || + fd[1] == STDERR_FILENO) + if(pipe(fd) < 0) + return; /* Out of handles. This isn't really a big problem now, but + will be when we try to create a socket later. */ + close(fd[0]); + close(fd[1]); +#endif +} + +/* +** curl tool main function. +*/ +int main(int argc, char *argv[]) +{ + int res; + struct Configurable config; + + memset(&config, 0, sizeof(struct Configurable)); + + config.errors = stderr; /* default errors to stderr */ + + main_checkfds(); + + res = operate(&config, argc, argv); + +#ifdef __SYMBIAN32__ + if(config.showerror) + tool_pressanykey(); +#endif + + free_config_fields(&config); + +#ifdef __NOVELL_LIBC__ + if(getenv("_IN_NETWARE_BASH_") == NULL) + tool_pressanykey(); +#endif + +#ifdef __VMS + vms_special_exit(res, vms_show); +#else + return res; +#endif +} + diff --git a/src/tool_main.h b/src/tool_main.h new file mode 100644 index 000000000..2193cb96e --- /dev/null +++ b/src/tool_main.h @@ -0,0 +1,44 @@ +#ifndef HEADER_CURL_TOOL_MAIN_H +#define HEADER_CURL_TOOL_MAIN_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#define DEFAULT_MAXREDIRS 50L + +#define RETRY_SLEEP_DEFAULT 1000L /* ms */ +#define RETRY_SLEEP_MAX 600000L /* ms == 10 minutes */ + +#ifndef STDIN_FILENO +# define STDIN_FILENO fileno(stdin) +#endif + +#ifndef STDOUT_FILENO +# define STDOUT_FILENO fileno(stdout) +#endif + +#ifndef STDERR_FILENO +# define STDERR_FILENO fileno(stderr) +#endif + +#endif /* HEADER_CURL_TOOL_MAIN_H */ + diff --git a/src/tool_mfiles.c b/src/tool_mfiles.c new file mode 100644 index 000000000..17edbfaab --- /dev/null +++ b/src/tool_mfiles.c @@ -0,0 +1,129 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "tool_mfiles.h" + +#include "memdebug.h" /* keep this as LAST include */ + +static void AppendNode(struct multi_files **first, + struct multi_files **last, + struct multi_files *new) +{ + DEBUGASSERT(((*first) && (*last)) || ((!*first) && (!*last))); + + if(*last) + (*last)->next = new; + else + *first = new; + *last = new; +} + +/* + * AddMultiFiles: Add a new list node possibly followed with a type_name. + * + * multi_first argument is the address of a pointer to the first element + * of the multi_files linked list. A NULL pointer indicates empty list. + * + * multi_last argument is the address of a pointer to the last element + * of the multi_files linked list. A NULL pointer indicates empty list. + * + * Pointers stored in multi_first and multi_last are modified while + * function is executed. An out of memory condition free's the whole + * list and returns with pointers stored in multi_first and multi_last + * set to NULL and a NULL function result. + * + * Function returns same pointer as stored at multi_last. + */ + +struct multi_files *AddMultiFiles(const char *file_name, + const char *type_name, + const char *show_filename, + struct multi_files **multi_first, + struct multi_files **multi_last) +{ + struct multi_files *multi; + struct multi_files *multi_type; + struct multi_files *multi_name; + + multi = calloc(1, sizeof(struct multi_files)); + if(multi) { + multi->form.option = CURLFORM_FILE; + multi->form.value = file_name; + AppendNode(multi_first, multi_last, multi); + } + else { + FreeMultiInfo(multi_first, multi_last); + return NULL; + } + + if(type_name) { + multi_type = calloc(1, sizeof(struct multi_files)); + if(multi_type) { + multi_type->form.option = CURLFORM_CONTENTTYPE; + multi_type->form.value = type_name; + AppendNode(multi_first, multi_last, multi_type); + } + else { + FreeMultiInfo(multi_first, multi_last); + return NULL; + } + } + + if(show_filename) { + multi_name = calloc(1, sizeof(struct multi_files)); + if(multi_name) { + multi_name->form.option = CURLFORM_FILENAME; + multi_name->form.value = show_filename; + AppendNode(multi_first, multi_last, multi_name); + } + else { + FreeMultiInfo(multi_first, multi_last); + return NULL; + } + } + + return *multi_last; +} + +/* + * FreeMultiInfo: Free the items of the list. + */ + +void FreeMultiInfo(struct multi_files **multi_first, + struct multi_files **multi_last) +{ + struct multi_files *next; + struct multi_files *item = *multi_first; + + while(item) { + next = item->next; + Curl_safefree(item); + item = next; + } + *multi_first = NULL; + if(multi_last) + *multi_last = NULL; +} + diff --git a/src/tool_mfiles.h b/src/tool_mfiles.h new file mode 100644 index 000000000..8a3b53935 --- /dev/null +++ b/src/tool_mfiles.h @@ -0,0 +1,46 @@ +#ifndef HEADER_CURL_TOOL_MFILES_H +#define HEADER_CURL_TOOL_MFILES_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +/* + * Structure for storing the information needed to build + * a multiple files section. + */ + +struct multi_files { + struct curl_forms form; + struct multi_files *next; +}; + +struct multi_files *AddMultiFiles(const char *file_name, + const char *type_name, + const char *show_filename, + struct multi_files **multi_first, + struct multi_files **multi_last); + +void FreeMultiInfo(struct multi_files **multi_first, + struct multi_files **multi_last); + +#endif /* HEADER_CURL_TOOL_MFILES_H */ + diff --git a/src/tool_msgs.c b/src/tool_msgs.c new file mode 100644 index 000000000..b6a80a2dd --- /dev/null +++ b/src/tool_msgs.c @@ -0,0 +1,100 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_msgs.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define WARN_PREFIX "Warning: " +#define WARN_TEXTWIDTH (79 - (int)strlen(WARN_PREFIX)) + +/* + * Emit warning formatted message on configured 'errors' stream unless + * mute (--silent) was selected. + */ + +void warnf(struct Configurable *config, const char *fmt, ...) +{ + if(!config->mute) { + va_list ap; + int len; + char *ptr; + char print_buffer[256]; + + va_start(ap, fmt); + len = vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap); + va_end(ap); + + ptr = print_buffer; + while(len > 0) { + fputs(WARN_PREFIX, config->errors); + + if(len > (int)WARN_TEXTWIDTH) { + int cut = WARN_TEXTWIDTH-1; + + while(!ISSPACE(ptr[cut]) && cut) { + cut--; + } + if(0 == cut) + /* not a single cutting position was found, just cut it at the + max text width then! */ + cut = WARN_TEXTWIDTH-1; + + (void)fwrite(ptr, cut + 1, 1, config->errors); + fputs("\n", config->errors); + ptr += cut+1; /* skip the space too */ + len -= cut; + } + else { + fputs(ptr, config->errors); + len = 0; + } + } + } +} + +/* + * Emit help formatted message on given stream. + */ + +void helpf(FILE *errors, const char *fmt, ...) +{ + va_list ap; + if(fmt) { + va_start(ap, fmt); + fputs("curl: ", errors); /* prefix it */ + vfprintf(errors, fmt, ap); + va_end(ap); + } + fprintf(errors, "curl: try 'curl --help' " +#ifdef USE_MANUAL + "or 'curl --manual' " +#endif + "for more information\n"); +} + diff --git a/src/tool_msgs.h b/src/tool_msgs.h new file mode 100644 index 000000000..9102139bd --- /dev/null +++ b/src/tool_msgs.h @@ -0,0 +1,31 @@ +#ifndef HEADER_CURL_TOOL_MSGS_H +#define HEADER_CURL_TOOL_MSGS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +void warnf(struct Configurable *config, const char *fmt, ...); + +void helpf(FILE *errors, const char *fmt, ...); + +#endif /* HEADER_CURL_TOOL_MSGS_H */ + diff --git a/src/tool_operate.c b/src/tool_operate.c new file mode 100644 index 000000000..7ab815f83 --- /dev/null +++ b/src/tool_operate.c @@ -0,0 +1,1559 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif + +#ifdef HAVE_UTIME_H +# include <utime.h> +#elif defined(HAVE_SYS_UTIME_H) +# include <sys/utime.h> +#endif + +#ifdef HAVE_LOCALE_H +# include <locale.h> +#endif + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_binmode.h" +#include "tool_cfgable.h" +#include "tool_cb_dbg.h" +#include "tool_cb_hdr.h" +#include "tool_cb_prg.h" +#include "tool_cb_rea.h" +#include "tool_cb_see.h" +#include "tool_cb_skt.h" +#include "tool_cb_wrt.h" +#include "tool_dirhie.h" +#include "tool_doswin.h" +#include "tool_easysrc.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_homedir.h" +#include "tool_libinfo.h" +#include "tool_main.h" +#include "tool_msgs.h" +#include "tool_operate.h" +#include "tool_operhlp.h" +#include "tool_parsecfg.h" +#include "tool_setopt.h" +#include "tool_sleep.h" +#include "tool_urlglob.h" +#include "tool_util.h" +#include "tool_writeenv.h" +#include "tool_writeout.h" +#include "tool_xattr.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define CURLseparator "--_curl_--" + +#ifndef O_BINARY +/* since O_BINARY as used in bitmasks, setting it to zero makes it usable in + source code but yet it doesn't ruin anything */ +# define O_BINARY 0 +#endif + +#define CURL_CA_CERT_ERRORMSG1 \ + "More details here: http://curl.haxx.se/docs/sslcerts.html\n\n" \ + "curl performs SSL certificate verification by default, " \ + "using a \"bundle\"\n" \ + " of Certificate Authority (CA) public keys (CA certs). If the default\n" \ + " bundle file isn't adequate, you can specify an alternate file\n" \ + " using the --cacert option.\n" + +#define CURL_CA_CERT_ERRORMSG2 \ + "If this HTTPS server uses a certificate signed by a CA represented in\n" \ + " the bundle, the certificate verification probably failed due to a\n" \ + " problem with the certificate (it might be expired, or the name might\n" \ + " not match the domain name in the URL).\n" \ + "If you'd like to turn off curl's verification of the certificate, use\n" \ + " the -k (or --insecure) option.\n" + +int operate(struct Configurable *config, int argc, argv_item_t argv[]) +{ + char errorbuffer[CURL_ERROR_SIZE]; + struct ProgressData progressbar; + struct getout *urlnode; + + struct OutStruct heads; + + CURL *curl = NULL; + char *httpgetfields = NULL; + + bool stillflags; + int res = 0; + int i; + + errorbuffer[0] = '\0'; + /* default headers output stream is stdout */ + memset(&heads, 0, sizeof(struct OutStruct)); + heads.stream = stdout; + heads.config = config; + + memory_tracking_init(); + + /* + ** Initialize curl library - do not call any libcurl functions before + ** this point. Note that the memory_tracking_init() magic above is an + ** exception, but then that's not part of the official public API. + */ + if(main_init() != CURLE_OK) { + helpf(config->errors, "error initializing curl library\n"); + return CURLE_FAILED_INIT; + } + + /* Get libcurl info right away */ + if(get_libcurl_info() != CURLE_OK) { + helpf(config->errors, "error retrieving curl library information\n"); + main_free(); + return CURLE_FAILED_INIT; + } + + /* Get a curl handle to use for all forthcoming curl transfers */ + curl = curl_easy_init(); + if(!curl) { + helpf(config->errors, "error initializing curl easy handle\n"); + main_free(); + return CURLE_FAILED_INIT; + } + config->easy = curl; + + /* + ** Beyond this point no return'ing from this function allowed. + ** Jump to label 'quit_curl' in order to abandon this function + ** from outside of nested loops further down below. + */ + + /* setup proper locale from environment */ +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + + /* inits */ + config->postfieldsize = -1; + config->showerror = -1; /* will show errors */ + config->use_httpget = FALSE; + config->create_dirs = FALSE; + config->maxredirs = DEFAULT_MAXREDIRS; + config->proto = CURLPROTO_ALL; /* FIXME: better to read from library */ + config->proto_present = FALSE; + config->proto_redir = + CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */ + config->proto_redir_present = FALSE; + + if((argc > 1) && + (!curlx_strnequal("--", argv[1], 2) && (argv[1][0] == '-')) && + strchr(argv[1], 'q')) { + /* + * The first flag, that is not a verbose name, but a shortname + * and it includes the 'q' flag! + */ + ; + } + else { + parseconfig(NULL, config); /* ignore possible failure */ + } + + if((argc < 2) && !config->url_list) { + helpf(config->errors, NULL); + res = CURLE_FAILED_INIT; + goto quit_curl; + } + + /* Parse options */ + for(i = 1, stillflags = TRUE; i < argc; i++) { + if(stillflags && + ('-' == argv[i][0])) { + char *nextarg; + bool passarg; + char *origopt = argv[i]; + + char *flag = argv[i]; + + if(curlx_strequal("--", argv[i])) + /* this indicates the end of the flags and thus enables the + following (URL) argument to start with -. */ + stillflags = FALSE; + else { + nextarg = (i < (argc-1)) ? argv[i+1] : NULL; + + res = getparameter(flag, nextarg, &passarg, config); + if(res) { + int retval = CURLE_OK; + if(res != PARAM_HELP_REQUESTED) { + const char *reason = param2text(res); + helpf(config->errors, "option %s: %s\n", origopt, reason); + retval = CURLE_FAILED_INIT; + } + res = retval; + goto quit_curl; + } + + if(passarg) /* we're supposed to skip this */ + i++; + } + } + else { + bool used; + /* just add the URL please */ + res = getparameter((char *)"--url", argv[i], &used, config); + if(res) + goto quit_curl; + } + } + + if((!config->url_list || !config->url_list->url) && !config->list_engines) { + helpf(config->errors, "no URL specified!\n"); + res = CURLE_FAILED_INIT; + goto quit_curl; + } + + if(!config->useragent) + config->useragent = my_useragent(); + if(!config->useragent) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + + /* On WIN32 we can't set the path to curl-ca-bundle.crt + * at compile time. So we look here for the file in two ways: + * 1: look at the environment variable CURL_CA_BUNDLE for a path + * 2: if #1 isn't found, use the windows API function SearchPath() + * to find it along the app's path (includes app's dir and CWD) + * + * We support the environment variable thing for non-Windows platforms + * too. Just for the sake of it. + */ + if(!config->cacert && + !config->capath && + !config->insecure_ok) { + char *env; + env = curlx_getenv("CURL_CA_BUNDLE"); + if(env) { + config->cacert = strdup(env); + if(!config->cacert) { + curl_free(env); + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + } + else { + env = curlx_getenv("SSL_CERT_DIR"); + if(env) { + config->capath = strdup(env); + if(!config->capath) { + curl_free(env); + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + } + else { + env = curlx_getenv("SSL_CERT_FILE"); + if(env) { + config->cacert = strdup(env); + if(!config->cacert) { + curl_free(env); + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + } + } + } + + if(env) + curl_free(env); +#ifdef WIN32 + else { + res = FindWin32CACert(config, "curl-ca-bundle.crt"); + if(res) + goto quit_curl; + } +#endif + } + + if(config->postfields) { + if(config->use_httpget) { + /* Use the postfields data for a http get */ + httpgetfields = strdup(config->postfields); + Curl_safefree(config->postfields); + if(!httpgetfields) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + if(SetHTTPrequest(config, + (config->no_body?HTTPREQ_HEAD:HTTPREQ_GET), + &config->httpreq)) { + res = PARAM_BAD_USE; + goto quit_curl; + } + } + else { + if(SetHTTPrequest(config, HTTPREQ_SIMPLEPOST, &config->httpreq)) { + res = PARAM_BAD_USE; + goto quit_curl; + } + } + } + + /* This is the first entry added to easysrc and it initializes the slist */ + easysrc = curl_slist_append(easysrc, "CURL *hnd = curl_easy_init();"); + if(!easysrc) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + goto quit_curl; + } + + if(config->list_engines) { + struct curl_slist *engines = NULL; + curl_easy_getinfo(curl, CURLINFO_SSL_ENGINES, &engines); + list_engines(engines); + curl_slist_free_all(engines); + res = CURLE_OK; + goto quit_curl; + } + + /* Single header file for all URLs */ + if(config->headerfile) { + /* open file for output: */ + if(!curlx_strequal(config->headerfile, "-")) { + FILE *newfile = fopen(config->headerfile, "wb"); + if(!newfile) { + warnf(config, "Failed to open %s\n", config->headerfile); + res = CURLE_WRITE_ERROR; + goto quit_curl; + } + else { + heads.filename = config->headerfile; + heads.s_isreg = TRUE; + heads.fopened = TRUE; + heads.stream = newfile; + } + } + } + + /* + ** Nested loops start here. + */ + + /* loop through the list of given URLs */ + + for(urlnode = config->url_list; urlnode; urlnode = urlnode->next) { + + int up; /* upload file counter within a single upload glob */ + char *infiles; /* might be a glob pattern */ + char *outfiles; + int infilenum; + URLGlob *inglob; + + outfiles = NULL; + infilenum = 0; + inglob = NULL; + + /* urlnode->url is the full URL (it might be NULL) */ + + if(!urlnode->url) { + /* This node has no URL. Free node data without destroying the + node itself nor modifying next pointer and continue to next */ + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + urlnode->flags = 0; + continue; /* next URL please */ + } + + /* save outfile pattern before expansion */ + if(urlnode->outfile) { + outfiles = strdup(urlnode->outfile); + if(!outfiles) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + break; + } + } + + infiles = urlnode->infile; + + if(!config->globoff && infiles) { + /* Unless explicitly shut off */ + res = glob_url(&inglob, infiles, &infilenum, + config->showerror?config->errors:NULL); + if(res) { + Curl_safefree(outfiles); + break; + } + } + + /* Here's the loop for uploading multiple files within the same + single globbed string. If no upload, we enter the loop once anyway. */ + for(up = 0 ;; up++) { + + char *uploadfile; /* a single file, never a glob */ + int separator; + URLGlob *urls; + int urlnum; + + uploadfile = NULL; + separator = 0; + urls = NULL; + urlnum = 0; + + if(!up && !infiles) + Curl_nop_stmt; + else { + if(inglob) { + res = glob_next_url(&uploadfile, inglob); + if(res == CURLE_OUT_OF_MEMORY) + helpf(config->errors, "out of memory\n"); + } + else if(!up) { + uploadfile = strdup(infiles); + if(!uploadfile) { + helpf(config->errors, "out of memory\n"); + res = CURLE_OUT_OF_MEMORY; + } + } + else + uploadfile = NULL; + if(!uploadfile) + break; + } + + if(!config->globoff) { + /* Unless explicitly shut off, we expand '{...}' and '[...]' + expressions and return total number of URLs in pattern set */ + res = glob_url(&urls, urlnode->url, &urlnum, + config->showerror?config->errors:NULL); + if(res) { + Curl_safefree(uploadfile); + break; + } + } + else + urlnum = 1; /* without globbing, this is a single URL */ + + /* if multiple files extracted to stdout, insert separators! */ + separator= ((!outfiles || curlx_strequal(outfiles, "-")) && urlnum > 1); + + /* Here's looping around each globbed URL */ + for(i = 0 ;; i++) { + + int infd; + bool infdopen; + char *outfile; + struct OutStruct outs; + struct InStruct input; + struct timeval retrystart; + curl_off_t uploadfilesize; + long retry_numretries; + long retry_sleep_default; + long retry_sleep; + char *this_url; + + outfile = NULL; + infdopen = FALSE; + infd = STDIN_FILENO; + uploadfilesize = -1; /* -1 means unknown */ + + /* default output stream is stdout */ + memset(&outs, 0, sizeof(struct OutStruct)); + outs.stream = stdout; + outs.config = config; + + if(urls) { + res = glob_next_url(&this_url, urls); + if(res) + goto show_error; + } + else if(!i) { + this_url = strdup(urlnode->url); + if(!this_url) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + } + else + this_url = NULL; + if(!this_url) + break; + + if(outfiles) { + outfile = strdup(outfiles); + if(!outfile) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + } + + if((urlnode->flags&GETOUT_USEREMOTE) || + (outfile && !curlx_strequal("-", outfile)) ) { + + /* + * We have specified a file name to store the result in, or we have + * decided we want to use the remote file name. + */ + + if(!outfile) { + /* extract the file name from the URL */ + res = get_url_file_name(&outfile, this_url); + if(res) + goto show_error; + if((!outfile || !*outfile) && !config->content_disposition) { + helpf(config->errors, "Remote file name has no length!\n"); + res = CURLE_WRITE_ERROR; + goto quit_urls; + } +#if defined(MSDOS) || defined(WIN32) + /* For DOS and WIN32, we do some major replacing of + bad characters in the file name before using it */ + outfile = sanitize_dos_name(outfile); + if(!outfile) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } +#endif /* MSDOS || WIN32 */ + } + else if(urls) { + /* fill '#1' ... '#9' terms from URL pattern */ + char *storefile = outfile; + res = glob_match_url(&outfile, storefile, urls); + Curl_safefree(storefile); + if(res) { + /* bad globbing */ + warnf(config, "bad output glob!\n"); + goto quit_urls; + } + } + + /* Create the directory hierarchy, if not pre-existent to a multiple + file output call */ + + if(config->create_dirs) { + res = create_dir_hierarchy(outfile, config->errors); + /* create_dir_hierarchy shows error upon CURLE_WRITE_ERROR */ + if(res == CURLE_WRITE_ERROR) + goto quit_urls; + if(res) { + goto show_error; + } + } + + if((urlnode->flags & GETOUT_USEREMOTE) + && config->content_disposition) { + /* Our header callback sets the filename */ + DEBUGASSERT(!outs.filename); + } + else { + if(config->resume_from_current) { + /* We're told to continue from where we are now. Get the size + of the file as it is now and open it for append instead */ + struct_stat fileinfo; + /* VMS -- Danger, the filesize is only valid for stream files */ + if(0 == stat(outfile, &fileinfo)) + /* set offset to current file size: */ + config->resume_from = fileinfo.st_size; + else + /* let offset be 0 */ + config->resume_from = 0; + } + + if(config->resume_from) { + /* open file for output: */ + FILE *file = fopen(outfile, config->resume_from?"ab":"wb"); + if(!file) { + helpf(config->errors, "Can't open '%s'!\n", outfile); + res = CURLE_WRITE_ERROR; + goto quit_urls; + } + outs.fopened = TRUE; + outs.stream = file; + outs.init = config->resume_from; + } + else { + outs.stream = NULL; /* open when needed */ + } + outs.filename = outfile; + outs.s_isreg = TRUE; + } + } + + if(uploadfile && !stdin_upload(uploadfile)) { + /* + * We have specified a file to upload and it isn't "-". + */ + struct_stat fileinfo; + + this_url = add_file_name_to_url(curl, this_url, uploadfile); + if(!this_url) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + /* VMS Note: + * + * Reading binary from files can be a problem... Only FIXED, VAR + * etc WITHOUT implied CC will work Others need a \n appended to a + * line + * + * - Stat gives a size but this is UNRELIABLE in VMS As a f.e. a + * fixed file with implied CC needs to have a byte added for every + * record processed, this can by derived from Filesize & recordsize + * for VARiable record files the records need to be counted! for + * every record add 1 for linefeed and subtract 2 for the record + * header for VARIABLE header files only the bare record data needs + * to be considered with one appended if implied CC + */ + + infd = open(uploadfile, O_RDONLY | O_BINARY); + if((infd == -1) || fstat(infd, &fileinfo)) { + helpf(config->errors, "Can't open '%s'!\n", uploadfile); + if(infd != -1) { + close(infd); + infd = STDIN_FILENO; + } + res = CURLE_READ_ERROR; + goto quit_urls; + } + infdopen = TRUE; + + /* we ignore file size for char/block devices, sockets, etc. */ + if(S_ISREG(fileinfo.st_mode)) + uploadfilesize = fileinfo.st_size; + + } + else if(uploadfile && stdin_upload(uploadfile)) { + /* count to see if there are more than one auth bit set + in the authtype field */ + int authbits = 0; + int bitcheck = 0; + while(bitcheck < 32) { + if(config->authtype & (1 << bitcheck++)) { + authbits++; + if(authbits > 1) { + /* more than one, we're done! */ + break; + } + } + } + + /* + * If the user has also selected --anyauth or --proxy-anyauth + * we should warn him/her. + */ + if(config->proxyanyauth || (authbits>1)) { + warnf(config, + "Using --anyauth or --proxy-anyauth with upload from stdin" + " involves a big risk of it not working. Use a temporary" + " file or a fixed auth type instead!\n"); + } + + DEBUGASSERT(infdopen == FALSE); + DEBUGASSERT(infd == STDIN_FILENO); + + set_binmode(stdin); + if(curlx_strequal(uploadfile, ".")) { + if(curlx_nonblock((curl_socket_t)infd, TRUE) < 0) + warnf(config, + "fcntl failed on fd=%d: %s\n", infd, strerror(errno)); + } + } + + if(uploadfile && config->resume_from_current) + config->resume_from = -1; /* -1 will then force get-it-yourself */ + + if(output_expected(this_url, uploadfile) + && outs.stream && isatty(fileno(outs.stream))) + /* we send the output to a tty, therefore we switch off the progress + meter */ + config->noprogress = config->isatty = TRUE; + + if(urlnum > 1 && !(config->mute)) { + fprintf(config->errors, "\n[%d/%d]: %s --> %s\n", + i+1, urlnum, this_url, outfile ? outfile : "<stdout>"); + if(separator) + printf("%s%s\n", CURLseparator, this_url); + } + if(httpgetfields) { + char *urlbuffer; + /* Find out whether the url contains a file name */ + const char *pc = strstr(this_url, "://"); + char sep = '?'; + if(pc) + pc += 3; + else + pc = this_url; + + pc = strrchr(pc, '/'); /* check for a slash */ + + if(pc) { + /* there is a slash present in the URL */ + + if(strchr(pc, '?')) + /* Ouch, there's already a question mark in the URL string, we + then append the data with an ampersand separator instead! */ + sep='&'; + } + /* + * Then append ? followed by the get fields to the url. + */ + urlbuffer = malloc(strlen(this_url) + strlen(httpgetfields) + 3); + if(!urlbuffer) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + if(pc) + sprintf(urlbuffer, "%s%c%s", this_url, sep, httpgetfields); + else + /* Append / before the ? to create a well-formed url + if the url contains a hostname only + */ + sprintf(urlbuffer, "%s/?%s", this_url, httpgetfields); + + Curl_safefree(this_url); /* free previous URL */ + this_url = urlbuffer; /* use our new URL instead! */ + } + + if(!config->errors) + config->errors = stderr; + + if((!outfile || !strcmp(outfile, "-")) && !config->use_ascii) { + /* We get the output to stdout and we have not got the ASCII/text + flag, then set stdout to be binary */ + set_binmode(stdout); + } + + if(config->tcp_nodelay) + my_setopt(curl, CURLOPT_TCP_NODELAY, 1); + + /* where to store */ + my_setopt(curl, CURLOPT_WRITEDATA, &outs); + /* what call to write */ + my_setopt(curl, CURLOPT_WRITEFUNCTION, tool_write_cb); + + /* for uploads */ + input.fd = infd; + input.config = config; + my_setopt(curl, CURLOPT_READDATA, &input); + /* what call to read */ + if((outfile && !curlx_strequal("-", outfile)) || + !checkprefix("telnet:", this_url)) + my_setopt(curl, CURLOPT_READFUNCTION, tool_read_cb); + + /* in 7.18.0, the CURLOPT_SEEKFUNCTION/DATA pair is taking over what + CURLOPT_IOCTLFUNCTION/DATA pair previously provided for seeking */ + my_setopt(curl, CURLOPT_SEEKDATA, &input); + my_setopt(curl, CURLOPT_SEEKFUNCTION, tool_seek_cb); + + if(config->recvpersecond) + /* tell libcurl to use a smaller sized buffer as it allows us to + make better sleeps! 7.9.9 stuff! */ + my_setopt(curl, CURLOPT_BUFFERSIZE, config->recvpersecond); + + /* size of uploaded file: */ + if(uploadfilesize != -1) + my_setopt(curl, CURLOPT_INFILESIZE_LARGE, uploadfilesize); + my_setopt_str(curl, CURLOPT_URL, this_url); /* what to fetch */ + my_setopt(curl, CURLOPT_NOPROGRESS, config->noprogress); + if(config->no_body) { + my_setopt(curl, CURLOPT_NOBODY, 1); + my_setopt(curl, CURLOPT_HEADER, 1); + } + else + my_setopt(curl, CURLOPT_HEADER, config->include_headers); + +#if !defined(CURL_DISABLE_PROXY) + { + /* TODO: Make this a run-time check instead of compile-time one. */ + + my_setopt_str(curl, CURLOPT_PROXY, config->proxy); + my_setopt_str(curl, CURLOPT_PROXYUSERPWD, config->proxyuserpwd); + + /* new in libcurl 7.3 */ + my_setopt(curl, CURLOPT_HTTPPROXYTUNNEL, config->proxytunnel); + + /* new in libcurl 7.5 */ + if(config->proxy) + my_setopt(curl, CURLOPT_PROXYTYPE, config->proxyver); + + /* new in libcurl 7.10 */ + if(config->socksproxy) { + my_setopt_str(curl, CURLOPT_PROXY, config->socksproxy); + my_setopt(curl, CURLOPT_PROXYTYPE, config->socksver); + } + + /* new in libcurl 7.10.6 */ + if(config->proxyanyauth) + my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY); + else if(config->proxynegotiate) + my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_GSSNEGOTIATE); + else if(config->proxyntlm) + my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); + else if(config->proxydigest) + my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_DIGEST); + else if(config->proxybasic) + my_setopt(curl, CURLOPT_PROXYAUTH, CURLAUTH_BASIC); + + /* new in libcurl 7.19.4 */ + my_setopt(curl, CURLOPT_NOPROXY, config->noproxy); + } +#endif + + my_setopt(curl, CURLOPT_FAILONERROR, config->failonerror); + my_setopt(curl, CURLOPT_UPLOAD, uploadfile?TRUE:FALSE); + my_setopt(curl, CURLOPT_DIRLISTONLY, config->dirlistonly); + my_setopt(curl, CURLOPT_APPEND, config->ftp_append); + + if(config->netrc_opt) + my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_OPTIONAL); + else if(config->netrc || config->netrc_file) + my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_REQUIRED); + else + my_setopt(curl, CURLOPT_NETRC, CURL_NETRC_IGNORED); + + if(config->netrc_file) + my_setopt(curl, CURLOPT_NETRC_FILE, config->netrc_file); + + my_setopt(curl, CURLOPT_TRANSFERTEXT, config->use_ascii); + my_setopt_str(curl, CURLOPT_USERPWD, config->userpwd); + my_setopt_str(curl, CURLOPT_RANGE, config->range); + my_setopt(curl, CURLOPT_ERRORBUFFER, errorbuffer); + my_setopt(curl, CURLOPT_TIMEOUT, config->timeout); + + if(built_in_protos & CURLPROTO_HTTP) { + + my_setopt(curl, CURLOPT_FOLLOWLOCATION, + config->followlocation); + my_setopt(curl, CURLOPT_UNRESTRICTED_AUTH, + config->unrestricted_auth); + + switch(config->httpreq) { + case HTTPREQ_SIMPLEPOST: + my_setopt_str(curl, CURLOPT_POSTFIELDS, + config->postfields); + my_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, + config->postfieldsize); + break; + case HTTPREQ_POST: + my_setopt(curl, CURLOPT_HTTPPOST, config->httppost); + break; + default: + break; + } + + my_setopt_str(curl, CURLOPT_REFERER, config->referer); + my_setopt(curl, CURLOPT_AUTOREFERER, config->autoreferer); + my_setopt_str(curl, CURLOPT_USERAGENT, config->useragent); + my_setopt(curl, CURLOPT_HTTPHEADER, config->headers); + + /* new in libcurl 7.5 */ + my_setopt(curl, CURLOPT_MAXREDIRS, config->maxredirs); + + /* new in libcurl 7.9.1 */ + if(config->httpversion) + my_setopt(curl, CURLOPT_HTTP_VERSION, config->httpversion); + + /* new in libcurl 7.10.6 (default is Basic) */ + if(config->authtype) + my_setopt(curl, CURLOPT_HTTPAUTH, config->authtype); + + /* curl 7.19.1 (the 301 version existed in 7.18.2) */ + my_setopt(curl, CURLOPT_POSTREDIR, config->post301 | + (config->post302 ? CURL_REDIR_POST_302 : FALSE)); + + /* new in libcurl 7.21.6 */ + if(config->encoding) + my_setopt_str(curl, CURLOPT_ACCEPT_ENCODING, ""); + + /* new in libcurl 7.21.6 */ + if(config->tr_encoding) + my_setopt(curl, CURLOPT_TRANSFER_ENCODING, 1); + + } /* (built_in_protos & CURLPROTO_HTTP) */ + + my_setopt_str(curl, CURLOPT_FTPPORT, config->ftpport); + my_setopt(curl, CURLOPT_LOW_SPEED_LIMIT, + config->low_speed_limit); + my_setopt(curl, CURLOPT_LOW_SPEED_TIME, config->low_speed_time); + my_setopt(curl, CURLOPT_MAX_SEND_SPEED_LARGE, + config->sendpersecond); + my_setopt(curl, CURLOPT_MAX_RECV_SPEED_LARGE, + config->recvpersecond); + my_setopt(curl, CURLOPT_RESUME_FROM_LARGE, + config->use_resume?config->resume_from:0); + + my_setopt(curl, CURLOPT_SSLCERT, config->cert); + my_setopt_str(curl, CURLOPT_SSLCERTTYPE, config->cert_type); + my_setopt(curl, CURLOPT_SSLKEY, config->key); + my_setopt_str(curl, CURLOPT_SSLKEYTYPE, config->key_type); + my_setopt_str(curl, CURLOPT_KEYPASSWD, config->key_passwd); + + if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { + + /* SSH and SSL private key uses same command-line option */ + /* new in libcurl 7.16.1 */ + my_setopt_str(curl, CURLOPT_SSH_PRIVATE_KEYFILE, config->key); + /* new in libcurl 7.16.1 */ + my_setopt_str(curl, CURLOPT_SSH_PUBLIC_KEYFILE, config->pubkey); + + /* new in libcurl 7.17.1: SSH host key md5 checking allows us + to fail if we are not talking to who we think we should */ + my_setopt_str(curl, CURLOPT_SSH_HOST_PUBLIC_KEY_MD5, + config->hostpubmd5); + } + + if(config->cacert) + my_setopt_str(curl, CURLOPT_CAINFO, config->cacert); + if(config->capath) + my_setopt_str(curl, CURLOPT_CAPATH, config->capath); + if(config->crlfile) + my_setopt_str(curl, CURLOPT_CRLFILE, config->crlfile); + + if(curlinfo->features & CURL_VERSION_SSL) { + if(config->insecure_ok) { + my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); + my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 1L); + } + else { + my_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); + /* libcurl default is strict verifyhost -> 2L */ + /* my_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); */ + } + } + + if(built_in_protos & (CURLPROTO_SCP|CURLPROTO_SFTP)) { + if(!config->insecure_ok) { + char *home; + char *file; + res = CURLE_OUT_OF_MEMORY; + home = homedir(); + if(home) { + file = aprintf("%s/%sssh/known_hosts", home, DOT_CHAR); + if(file) { + /* new in curl 7.19.6 */ + res = res_setopt_str(curl, CURLOPT_SSH_KNOWNHOSTS, file); + curl_free(file); + if(res == CURLE_UNKNOWN_OPTION) + /* libssh2 version older than 1.1.1 */ + res = CURLE_OK; + } + Curl_safefree(home); + } + if(res) + goto show_error; + } + } + + if(config->no_body || config->remote_time) { + /* no body or use remote time */ + my_setopt(curl, CURLOPT_FILETIME, TRUE); + } + + my_setopt(curl, CURLOPT_CRLF, config->crlf); + my_setopt(curl, CURLOPT_QUOTE, config->quote); + my_setopt(curl, CURLOPT_POSTQUOTE, config->postquote); + my_setopt(curl, CURLOPT_PREQUOTE, config->prequote); + +#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES) + { + /* TODO: Make this a run-time check instead of compile-time one. */ + + if(config->cookie) + my_setopt_str(curl, CURLOPT_COOKIE, config->cookie); + + if(config->cookiefile) + my_setopt_str(curl, CURLOPT_COOKIEFILE, config->cookiefile); + + /* new in libcurl 7.9 */ + if(config->cookiejar) + my_setopt_str(curl, CURLOPT_COOKIEJAR, config->cookiejar); + + /* new in libcurl 7.9.7 */ + my_setopt(curl, CURLOPT_COOKIESESSION, config->cookiesession); + } +#endif + + my_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version); + my_setopt(curl, CURLOPT_TIMECONDITION, config->timecond); + my_setopt(curl, CURLOPT_TIMEVALUE, config->condtime); + my_setopt_str(curl, CURLOPT_CUSTOMREQUEST, config->customrequest); + my_setopt(curl, CURLOPT_STDERR, config->errors); + + /* three new ones in libcurl 7.3: */ + my_setopt_str(curl, CURLOPT_INTERFACE, config->iface); + my_setopt_str(curl, CURLOPT_KRBLEVEL, config->krblevel); + + progressbarinit(&progressbar, config); + if((config->progressmode == CURL_PROGRESS_BAR) && + !config->noprogress && !config->mute) { + /* we want the alternative style, then we have to implement it + ourselves! */ + my_setopt(curl, CURLOPT_PROGRESSFUNCTION, tool_progress_cb); + my_setopt(curl, CURLOPT_PROGRESSDATA, &progressbar); + } + + /* new in libcurl 7.6.2: */ + my_setopt(curl, CURLOPT_TELNETOPTIONS, config->telnet_options); + + /* new in libcurl 7.7: */ + my_setopt_str(curl, CURLOPT_RANDOM_FILE, config->random_file); + my_setopt(curl, CURLOPT_EGDSOCKET, config->egd_file); + my_setopt(curl, CURLOPT_CONNECTTIMEOUT, config->connecttimeout); + + if(config->cipher_list) + my_setopt_str(curl, CURLOPT_SSL_CIPHER_LIST, config->cipher_list); + + /* new in libcurl 7.9.2: */ + if(config->disable_epsv) + /* disable it */ + my_setopt(curl, CURLOPT_FTP_USE_EPSV, FALSE); + + /* new in libcurl 7.10.5 */ + if(config->disable_eprt) + /* disable it */ + my_setopt(curl, CURLOPT_FTP_USE_EPRT, FALSE); + + if(config->tracetype != TRACE_NONE) { + my_setopt(curl, CURLOPT_DEBUGFUNCTION, tool_debug_cb); + my_setopt(curl, CURLOPT_DEBUGDATA, config); + my_setopt(curl, CURLOPT_VERBOSE, TRUE); + } + + /* new in curl 7.9.3 */ + if(config->engine) { + res = res_setopt_str(curl, CURLOPT_SSLENGINE, config->engine); + if(res) + goto show_error; + my_setopt(curl, CURLOPT_SSLENGINE_DEFAULT, 1); + } + + /* new in curl 7.10.7, extended in 7.19.4 but this only sets 0 or 1 */ + my_setopt(curl, CURLOPT_FTP_CREATE_MISSING_DIRS, + config->ftp_create_dirs); + + /* new in curl 7.10.8 */ + if(config->max_filesize) + my_setopt(curl, CURLOPT_MAXFILESIZE_LARGE, + config->max_filesize); + + if(4 == config->ip_version) + my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4); + else if(6 == config->ip_version) + my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6); + else + my_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER); + + /* new in curl 7.15.5 */ + if(config->ftp_ssl_reqd) + my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL); + + /* new in curl 7.11.0 */ + else if(config->ftp_ssl) + my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_TRY); + + /* new in curl 7.16.0 */ + else if(config->ftp_ssl_control) + my_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_CONTROL); + + /* new in curl 7.16.1 */ + if(config->ftp_ssl_ccc) + my_setopt(curl, CURLOPT_FTP_SSL_CCC, config->ftp_ssl_ccc_mode); + +#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI) + { + /* TODO: Make this a run-time check instead of compile-time one. */ + + /* new in curl 7.19.4 */ + if(config->socks5_gssapi_service) + my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_SERVICE, + config->socks5_gssapi_service); + + /* new in curl 7.19.4 */ + if(config->socks5_gssapi_nec) + my_setopt_str(curl, CURLOPT_SOCKS5_GSSAPI_NEC, + config->socks5_gssapi_nec); + } +#endif + /* curl 7.13.0 */ + my_setopt_str(curl, CURLOPT_FTP_ACCOUNT, config->ftp_account); + + my_setopt(curl, CURLOPT_IGNORE_CONTENT_LENGTH, config->ignorecl); + + /* curl 7.14.2 */ + my_setopt(curl, CURLOPT_FTP_SKIP_PASV_IP, config->ftp_skip_ip); + + /* curl 7.15.1 */ + my_setopt(curl, CURLOPT_FTP_FILEMETHOD, config->ftp_filemethod); + + /* curl 7.15.2 */ + if(config->localport) { + my_setopt(curl, CURLOPT_LOCALPORT, config->localport); + my_setopt_str(curl, CURLOPT_LOCALPORTRANGE, + config->localportrange); + } + + /* curl 7.15.5 */ + my_setopt_str(curl, CURLOPT_FTP_ALTERNATIVE_TO_USER, + config->ftp_alternative_to_user); + + /* curl 7.16.0 */ + if(config->disable_sessionid) + my_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, + !config->disable_sessionid); + + /* curl 7.16.2 */ + if(config->raw) { + my_setopt(curl, CURLOPT_HTTP_CONTENT_DECODING, FALSE); + my_setopt(curl, CURLOPT_HTTP_TRANSFER_DECODING, FALSE); + } + + /* curl 7.17.1 */ + if(!config->nokeepalive) { + my_setopt(curl, CURLOPT_SOCKOPTFUNCTION, tool_sockopt_cb); + my_setopt(curl, CURLOPT_SOCKOPTDATA, config); + } + + /* curl 7.20.0 */ + if(config->tftp_blksize) + my_setopt(curl, CURLOPT_TFTP_BLKSIZE, config->tftp_blksize); + + if(config->mail_from) + my_setopt_str(curl, CURLOPT_MAIL_FROM, config->mail_from); + + if(config->mail_rcpt) + my_setopt(curl, CURLOPT_MAIL_RCPT, config->mail_rcpt); + + /* curl 7.20.x */ + if(config->ftp_pret) + my_setopt(curl, CURLOPT_FTP_USE_PRET, TRUE); + + if(config->proto_present) + my_setopt(curl, CURLOPT_PROTOCOLS, config->proto); + if(config->proto_redir_present) + my_setopt(curl, CURLOPT_REDIR_PROTOCOLS, config->proto_redir); + + if((urlnode->flags & GETOUT_USEREMOTE) + && config->content_disposition) { + my_setopt(curl, CURLOPT_HEADERFUNCTION, tool_header_cb); + my_setopt(curl, CURLOPT_HEADERDATA, &outs); + } + else { + /* if HEADERFUNCTION was set to something in the previous loop, it + is important that we set it (back) to NULL now */ + my_setopt(curl, CURLOPT_HEADERFUNCTION, NULL); + my_setopt(curl, CURLOPT_HEADERDATA, config->headerfile?&heads:NULL); + } + + if(config->resolve) + /* new in 7.21.3 */ + my_setopt(curl, CURLOPT_RESOLVE, config->resolve); + + /* new in 7.21.4 */ + if(curlinfo->features & CURL_VERSION_TLSAUTH_SRP) { + if(config->tls_username) + my_setopt_str(curl, CURLOPT_TLSAUTH_USERNAME, + config->tls_username); + if(config->tls_password) + my_setopt_str(curl, CURLOPT_TLSAUTH_PASSWORD, + config->tls_password); + if(config->tls_authtype) + my_setopt_str(curl, CURLOPT_TLSAUTH_TYPE, + config->tls_authtype); + } + + /* new in 7.22.0 */ + if(config->gssapi_delegation) + my_setopt_str(curl, CURLOPT_GSSAPI_DELEGATION, + config->gssapi_delegation); + + /* initialize retry vars for loop below */ + retry_sleep_default = (config->retry_delay) ? + config->retry_delay*1000L : RETRY_SLEEP_DEFAULT; /* ms */ + + retry_numretries = config->req_retry; + retry_sleep = retry_sleep_default; /* ms */ + retrystart = tvnow(); + + if(!curl_slist_append(easysrc, "ret = curl_easy_perform(hnd);")) { + res = CURLE_OUT_OF_MEMORY; + goto show_error; + } + + for(;;) { + res = curl_easy_perform(curl); + + if(config->content_disposition && outs.stream && !config->mute && + outs.filename) + printf("curl: Saved to filename '%s'\n", outs.filename); + + /* if retry-max-time is non-zero, make sure we haven't exceeded the + time */ + if(retry_numretries && + (!config->retry_maxtime || + (tvdiff(tvnow(), retrystart) < + config->retry_maxtime*1000L)) ) { + enum { + RETRY_NO, + RETRY_TIMEOUT, + RETRY_HTTP, + RETRY_FTP, + RETRY_LAST /* not used */ + } retry = RETRY_NO; + long response; + if(CURLE_OPERATION_TIMEDOUT == res) + /* retry timeout always */ + retry = RETRY_TIMEOUT; + else if((CURLE_OK == res) || + (config->failonerror && + (CURLE_HTTP_RETURNED_ERROR == res))) { + /* If it returned OK. _or_ failonerror was enabled and it + returned due to such an error, check for HTTP transient + errors to retry on. */ + char *effective_url = NULL; + curl_easy_getinfo(curl, CURLINFO_EFFECTIVE_URL, &effective_url); + if(effective_url && + checkprefix("http", effective_url)) { + /* This was HTTP(S) */ + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + + switch(response) { + case 500: /* Internal Server Error */ + case 502: /* Bad Gateway */ + case 503: /* Service Unavailable */ + case 504: /* Gateway Timeout */ + retry = RETRY_HTTP; + /* + * At this point, we have already written data to the output + * file (or terminal). If we write to a file, we must rewind + * or close/re-open the file so that the next attempt starts + * over from the beginning. + * + * TODO: similar action for the upload case. We might need + * to start over reading from a previous point if we have + * uploaded something when this was returned. + */ + break; + } + } + } /* if CURLE_OK */ + else if(res) { + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response); + + if(response/100 == 4) + /* + * This is typically when the FTP server only allows a certain + * amount of users and we are not one of them. All 4xx codes + * are transient. + */ + retry = RETRY_FTP; + } + + if(retry) { + static const char * const m[]={ + NULL, "timeout", "HTTP error", "FTP error" + }; + warnf(config, "Transient problem: %s " + "Will retry in %ld seconds. " + "%ld retries left.\n", + m[retry], retry_sleep/1000L, retry_numretries); + + tool_go_sleep(retry_sleep); + retry_numretries--; + if(!config->retry_delay) { + retry_sleep *= 2; + if(retry_sleep > RETRY_SLEEP_MAX) + retry_sleep = RETRY_SLEEP_MAX; + } + if(outs.bytes && outs.filename) { + /* We have written data to a output file, we truncate file + */ + if(!config->mute) + fprintf(config->errors, "Throwing away %" + CURL_FORMAT_CURL_OFF_T " bytes\n", + outs.bytes); + fflush(outs.stream); + /* truncate file at the position where we started appending */ +#ifdef HAVE_FTRUNCATE + if(ftruncate( fileno(outs.stream), outs.init)) { + /* when truncate fails, we can't just append as then we'll + create something strange, bail out */ + if(!config->mute) + fprintf(config->errors, + "failed to truncate, exiting\n"); + res = CURLE_WRITE_ERROR; + goto quit_urls; + } + /* now seek to the end of the file, the position where we + just truncated the file in a large file-safe way */ + fseek(outs.stream, 0, SEEK_END); +#else + /* ftruncate is not available, so just reposition the file + to the location we would have truncated it. This won't + work properly with large files on 32-bit systems, but + most of those will have ftruncate. */ + fseek(outs.stream, (long)outs.init, SEEK_SET); +#endif + outs.bytes = 0; /* clear for next round */ + } + continue; /* curl_easy_perform loop */ + } + } /* if retry_numretries */ + + /* In all ordinary cases, just break out of loop here */ + break; /* curl_easy_perform loop */ + + } + + if((config->progressmode == CURL_PROGRESS_BAR) && + progressbar.calls) + /* if the custom progress bar has been displayed, we output a + newline here */ + fputs("\n", progressbar.out); + + if(config->writeout) + ourWriteOut(curl, config->writeout); + + if(config->writeenv) + ourWriteEnv(curl); + + /* + ** Code within this loop may jump directly here to label 'show_error' + ** in order to display an error message for CURLcode stored in 'res' + ** variable and exit loop once that necessary writing and cleanup + ** in label 'quit_urls' has been done. + */ + + show_error: + +#ifdef __VMS + if(is_vms_shell()) { + /* VMS DCL shell behavior */ + if(!config->showerror) + vms_show = VMSSTS_HIDE; + } + else +#endif + if(res && config->showerror) { + fprintf(config->errors, "curl: (%d) %s\n", res, (errorbuffer[0]) ? + errorbuffer : curl_easy_strerror((CURLcode)res)); + if(res == CURLE_SSL_CACERT) + fprintf(config->errors, "%s%s", + CURL_CA_CERT_ERRORMSG1, CURL_CA_CERT_ERRORMSG2); + } + + /* Fall through comment to 'quit_urls' label */ + + /* + ** Upon error condition and always that a message has already been + ** displayed, code within this loop may jump directly here to label + ** 'quit_urls' otherwise it should jump to 'show_error' label above. + ** + ** When 'res' variable is _not_ CURLE_OK loop will exit once that + ** all code following 'quit_urls' has been executed. Otherwise it + ** will loop to the beginning from where it may exit if there are + ** no more urls left. + */ + + quit_urls: + + /* Set file extended attributes */ + if(!res && config->xattr && outs.fopened && outs.stream) { + int rc = fwrite_xattr(curl, fileno(outs.stream)); + if(rc) + warnf(config, "Error setting extended attributes: %s\n", + strerror(errno)); + } + + /* Close the file */ + if(outs.fopened && outs.stream) { + int rc = fclose(outs.stream); + if(!res && rc) { + /* something went wrong in the writing process */ + res = CURLE_WRITE_ERROR; + fprintf(config->errors, "(%d) Failed writing body\n", res); + } + } + else if(!outs.s_isreg && outs.stream) { + /* Dump standard stream buffered data */ + int rc = fflush(outs.stream); + if(!res && rc) { + /* something went wrong in the writing process */ + res = CURLE_WRITE_ERROR; + fprintf(config->errors, "(%d) Failed writing body\n", res); + } + } + +#ifdef __AMIGA__ + if(!res && outs.s_isreg && outs.filename) { + /* Set the url (up to 80 chars) as comment for the file */ + if(strlen(url) > 78) + url[79] = '\0'; + SetComment(outs.filename, url); + } +#endif + +#ifdef HAVE_UTIME + /* File time can only be set _after_ the file has been closed */ + if(!res && config->remote_time && outs.s_isreg && outs.filename) { + /* Ask libcurl if we got a remote file time */ + long filetime = -1; + curl_easy_getinfo(curl, CURLINFO_FILETIME, &filetime); + if(filetime >= 0) { + struct utimbuf times; + times.actime = (time_t)filetime; + times.modtime = (time_t)filetime; + utime(outs.filename, ×); /* set the time we got */ + } + } +#endif + /* No more business with this output struct */ + if(outs.alloc_filename) + Curl_safefree(outs.filename); + memset(&outs, 0, sizeof(struct OutStruct)); + + /* Free loop-local allocated memory and close loop-local opened fd */ + + Curl_safefree(outfile); + Curl_safefree(this_url); + + if(infdopen) { + close(infd); + infdopen = FALSE; + infd = STDIN_FILENO; + } + + /* upon error exit loop */ + if(res) + break; + + } /* loop to the next URL */ + + /* Free loop-local allocated memory */ + + Curl_safefree(uploadfile); + + if(urls) { + /* Free list of remaining URLs */ + glob_cleanup(urls); + urls = NULL; + } + + /* upon error exit loop */ + if(res) + break; + + } /* loop to the next globbed upload file */ + + /* Free loop-local allocated memory */ + + Curl_safefree(outfiles); + + if(inglob) { + /* Free list of globbed upload files */ + glob_cleanup(inglob); + inglob = NULL; + } + + /* Free this URL node data without destroying the + the node itself nor modifying next pointer. */ + Curl_safefree(urlnode->url); + Curl_safefree(urlnode->outfile); + Curl_safefree(urlnode->infile); + urlnode->flags = 0; + + /* TODO: Should CURLE_SSL_CACERT be included as critical error ? */ + + /* + ** Bail out upon critical errors + */ + switch(res) { + case CURLE_FAILED_INIT: + case CURLE_OUT_OF_MEMORY: + case CURLE_FUNCTION_NOT_FOUND: + case CURLE_BAD_FUNCTION_ARGUMENT: + goto quit_curl; + default: + /* Merrily loop to next URL */ + break; + } + + } /* for-loop through all URLs */ + + /* + ** Nested loops end here. + */ + + quit_curl: + + /* Free function-local referenced allocated memory */ + Curl_safefree(httpgetfields); + + /* Free list of given URLs */ + clean_getout(config); + + /* Cleanup the curl handle now that our + progressbar struct is still in scope */ + if(curl) { + curl_easy_cleanup(curl); + config->easy = curl = NULL; + } + if(easysrc) + curl_slist_append(easysrc, "curl_easy_cleanup(hnd);"); + + /* Close function-local opened file descriptors */ + + if(heads.fopened && heads.stream) + fclose(heads.stream); + if(heads.alloc_filename) + Curl_safefree(heads.filename); + + if(config->trace_fopened && config->trace_stream) + fclose(config->trace_stream); + + /* Dump the libcurl code if previously enabled. + NOTE: that this function relies on config->errors amongst other things + so not everything can be closed and cleaned before this is called */ + dumpeasysrc(config); + + if(config->errors_fopened && config->errors) + fclose(config->errors); + + main_free(); /* cleanup */ + + return res; +} + diff --git a/src/tool_operate.h b/src/tool_operate.h new file mode 100644 index 000000000..4986cc4e3 --- /dev/null +++ b/src/tool_operate.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_TOOL_OPERATE_H +#define HEADER_CURL_TOOL_OPERATE_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +int operate(struct Configurable *config, int argc, argv_item_t argv[]); + +#endif /* HEADER_CURL_TOOL_OPERATE_H */ + diff --git a/src/tool_operhlp.c b/src/tool_operhlp.c new file mode 100644 index 000000000..808d2d564 --- /dev/null +++ b/src/tool_operhlp.c @@ -0,0 +1,238 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_convert.h" +#include "tool_operhlp.h" +#include "tool_version.h" + +#include "memdebug.h" /* keep this as LAST include */ + +/* + * my_useragent: returns allocated string with default user agent + */ +char *my_useragent(void) +{ + char useragent[256]; /* we don't want a larger default user agent */ + + snprintf(useragent, sizeof(useragent), + CURL_NAME "/" CURL_VERSION " (" OS ") " "%s", curl_version()); + + return strdup(useragent); +} + +/* + * Print list of OpenSSL supported engines + */ +void list_engines(const struct curl_slist *engines) +{ + puts("Build-time engines:"); + if(!engines) { + puts(" <none>"); + return; + } + for(; engines; engines = engines->next) + printf(" %s\n", engines->data); +} + +void clean_getout(struct Configurable *config) +{ + struct getout *next; + struct getout *node = config->url_list; + + while(node) { + next = node->next; + Curl_safefree(node->url); + Curl_safefree(node->outfile); + Curl_safefree(node->infile); + Curl_safefree(node); + node = next; + } + config->url_list = NULL; +} + +bool output_expected(const char *url, const char *uploadfile) +{ + if(!uploadfile) + return TRUE; /* download */ + if(checkprefix("http://", url) || checkprefix("https://", url)) + return TRUE; /* HTTP(S) upload */ + + return FALSE; /* non-HTTP upload, probably no output should be expected */ +} + +bool stdin_upload(const char *uploadfile) +{ + return (curlx_strequal(uploadfile, "-") || + curlx_strequal(uploadfile, ".")) ? TRUE : FALSE; +} + +/* + * Adds the file name to the URL if it doesn't already have one. + * url will be freed before return if the returned pointer is different + */ +char *add_file_name_to_url(CURL *curl, char *url, const char *filename) +{ + /* If no file name part is given in the URL, we add this file name */ + char *ptr = strstr(url, "://"); + if(ptr) + ptr += 3; + else + ptr = url; + ptr = strrchr(ptr, '/'); + if(!ptr || !strlen(++ptr)) { + /* The URL has no file name part, add the local file name. In order + to be able to do so, we have to create a new URL in another + buffer.*/ + + /* We only want the part of the local path that is on the right + side of the rightmost slash and backslash. */ + const char *filep = strrchr(filename, '/'); + char *file2 = strrchr(filep?filep:filename, '\\'); + char *encfile; + + if(file2) + filep = file2 + 1; + else if(filep) + filep++; + else + filep = filename; + + /* URL encode the file name */ + encfile = curl_easy_escape(curl, filep, 0 /* use strlen */); + if(encfile) { + char *urlbuffer = malloc(strlen(url) + strlen(encfile) + 3); + if(!urlbuffer) { + curl_free(encfile); + Curl_safefree(url); + return NULL; + } + if(ptr) + /* there is a trailing slash on the URL */ + sprintf(urlbuffer, "%s%s", url, encfile); + else + /* there is no trailing slash on the URL */ + sprintf(urlbuffer, "%s/%s", url, encfile); + + curl_free(encfile); + Curl_safefree(url); + + url = urlbuffer; /* use our new URL instead! */ + } + } + return url; +} + +/* Extracts the name portion of the URL. + * Returns a pointer to a heap-allocated string or NULL if + * no name part, at location indicated by first argument. + */ +CURLcode get_url_file_name(char **filename, const char *url) +{ + const char *pc; + + *filename = NULL; + + /* Find and get the remote file name */ + pc = strstr(url, "://"); + if(pc) + pc += 3; + else + pc = url; + pc = strrchr(pc, '/'); + + if(pc) { + /* duplicate the string beyond the slash */ + pc++; + if(*pc) { + *filename = strdup(pc); + if(!*filename) + return CURLE_OUT_OF_MEMORY; + } + } + return CURLE_OK; +} + +/* + * This is the main global constructor for the app. Call this before + * _any_ libcurl usage. If this fails, *NO* libcurl functions may be + * used, or havoc may be the result. + */ +CURLcode main_init(void) +{ +#if defined(__DJGPP__) || defined(__GO32__) + /* stop stat() wasting time */ + _djstat_flags |= _STAT_INODE | _STAT_EXEC_MAGIC | _STAT_DIRSIZE; +#endif + + return curl_global_init(CURL_GLOBAL_DEFAULT); +} + +/* + * This is the main global destructor for the app. Call this after + * _all_ libcurl usage is done. + */ +void main_free(void) +{ + curl_global_cleanup(); + convert_cleanup(); +} + +#ifdef CURLDEBUG +void memory_tracking_init(void) +{ + char *env; + /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ + env = curlx_getenv("CURL_MEMDEBUG"); + if(env) { + /* use the value as file name */ + char fname[CURL_MT_LOGFNAME_BUFSIZE]; + if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) + env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; + strcpy(fname, env); + curl_free(env); + curl_memdebug(fname); + /* this weird stuff here is to make curl_free() get called + before curl_memdebug() as otherwise memory tracking will + log a free() without an alloc! */ + } + /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ + env = curlx_getenv("CURL_MEMLIMIT"); + if(env) { + char *endptr; + long num = strtol(env, &endptr, 10); + if((endptr != env) && (endptr == env + strlen(env)) && (num > 0)) + curl_memlimit(num); + curl_free(env); + } +} +#endif + diff --git a/src/tool_operhlp.h b/src/tool_operhlp.h new file mode 100644 index 000000000..3629bf13a --- /dev/null +++ b/src/tool_operhlp.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_TOOL_OPERHLP_H +#define HEADER_CURL_TOOL_OPERHLP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +char *my_useragent(void); + +void list_engines(const struct curl_slist *engines); + +void clean_getout(struct Configurable *config); + +bool output_expected(const char *url, const char *uploadfile); + +bool stdin_upload(const char *uploadfile); + +char *add_file_name_to_url(CURL *curl, char *url, const char *filename); + +CURLcode get_url_file_name(char **filename, const char *url); + +CURLcode main_init(void); + +void main_free(void); + +#ifdef CURLDEBUG +void memory_tracking_init(void); +#else +# define memory_tracking_init() Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_TOOL_OPERHLP_H */ + diff --git a/src/tool_panykey.c b/src/tool_panykey.c new file mode 100644 index 000000000..95fa6a763 --- /dev/null +++ b/src/tool_panykey.c @@ -0,0 +1,48 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#if defined(__SYMBIAN32__) || defined(NETWARE) + +#ifdef NETWARE +# ifdef __NOVELL_LIBC__ +# include <screen.h> +# else +# include <nwconio.h> +# endif +#endif + +#include "tool_panykey.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void tool_pressanykey(void) +{ +#if defined(__SYMBIAN32__) + getchar(); +#elif defined(NETWARE) + pressanykey(); +#endif +} + +#endif /* __SYMBIAN32__ || NETWARE */ + diff --git a/src/tool_panykey.h b/src/tool_panykey.h new file mode 100644 index 000000000..30fd658d3 --- /dev/null +++ b/src/tool_panykey.h @@ -0,0 +1,37 @@ +#ifndef HEADER_CURL_TOOL_PANYKEY_H +#define HEADER_CURL_TOOL_PANYKEY_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#if defined(__SYMBIAN32__) || defined(NETWARE) + +void tool_pressanykey(void); + +#else + +#define tool_pressanykey() Curl_nop_stmt + +#endif + +#endif /* HEADER_CURL_TOOL_PANYKEY_H */ + diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c new file mode 100644 index 000000000..adb12ce70 --- /dev/null +++ b/src/tool_paramhlp.c @@ -0,0 +1,387 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#include "rawstr.h" + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_getparam.h" +#include "tool_getpass.h" +#include "tool_homedir.h" +#include "tool_msgs.h" +#include "tool_paramhlp.h" + +#include "memdebug.h" /* keep this as LAST include */ + +struct getout *new_getout(struct Configurable *config) +{ + struct getout *node = calloc(1, sizeof(struct getout)); + struct getout *last = config->url_last; + if(node) { + /* append this new node last in the list */ + if(last) + last->next = node; + else + config->url_list = node; /* first node */ + + /* move the last pointer */ + config->url_last = node; + + node->flags = config->default_node_flags; + } + return node; +} + +ParameterError file2string(char **bufp, FILE *file) +{ + char buffer[256]; + char *ptr; + char *string = NULL; + size_t stringlen = 0; + size_t buflen; + + if(file) { + while(fgets(buffer, sizeof(buffer), file)) { + if((ptr = strchr(buffer, '\r')) != NULL) + *ptr = '\0'; + if((ptr = strchr(buffer, '\n')) != NULL) + *ptr = '\0'; + buflen = strlen(buffer); + if((ptr = realloc(string, stringlen+buflen+1)) == NULL) { + Curl_safefree(string); + return PARAM_NO_MEM; + } + string = ptr; + strcpy(string+stringlen, buffer); + stringlen += buflen; + } + } + *bufp = string; + return PARAM_OK; +} + +ParameterError file2memory(char **bufp, size_t *size, FILE *file) +{ + char *newbuf; + char *buffer = NULL; + size_t alloc = 512; + size_t nused = 0; + size_t nread; + + if(file) { + do { + if(!buffer || (alloc == nused)) { + /* size_t overflow detection for huge files */ + if(alloc+1 > ((size_t)-1)/2) { + Curl_safefree(buffer); + return PARAM_NO_MEM; + } + alloc *= 2; + /* allocate an extra char, reserved space, for null termination */ + if((newbuf = realloc(buffer, alloc+1)) == NULL) { + Curl_safefree(buffer); + return PARAM_NO_MEM; + } + buffer = newbuf; + } + nread = fread(buffer+nused, 1, alloc-nused, file); + nused += nread; + } while(nread); + /* null terminate the buffer in case it's used as a string later */ + buffer[nused] = '\0'; + /* free trailing slack space, if possible */ + if(alloc != nused) { + if((newbuf = realloc(buffer, nused+1)) == NULL) { + Curl_safefree(buffer); + return PARAM_NO_MEM; + } + buffer = newbuf; + } + /* discard buffer if nothing was read */ + if(!nused) { + Curl_safefree(buffer); /* no string */ + } + } + *size = nused; + *bufp = buffer; + return PARAM_OK; +} + +void cleanarg(char *str) +{ +#ifdef HAVE_WRITABLE_ARGV + /* 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 + (void)str; +#endif +} + +/* + * Parse the string and write the integer in the given address. Return + * non-zero on failure, zero on success. + * + * The string must start with a digit to be valid. + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +int str2num(long *val, const char *str) +{ + if(str && ISDIGIT(*str)) { + char *endptr; + long num = strtol(str, &endptr, 10); + if((endptr != str) && (endptr == str + strlen(str))) { + *val = num; + return 0; /* Ok */ + } + } + return 1; /* badness */ +} + +/* + * Parse the string and modify the long in the given address. Return + * non-zero on failure, zero on success. + * + * The string is a list of protocols + * + * Since this function gets called with the 'nextarg' pointer from within the + * getparameter a lot, we must check it for NULL before accessing the str + * data. + */ + +long proto2num(struct Configurable *config, long *val, const char *str) +{ + char *buffer; + const char *sep = ","; + char *token; + + static struct sprotos { + const char *name; + long bit; + } const protos[] = { + { "all", CURLPROTO_ALL }, + { "http", CURLPROTO_HTTP }, + { "https", CURLPROTO_HTTPS }, + { "ftp", CURLPROTO_FTP }, + { "ftps", CURLPROTO_FTPS }, + { "scp", CURLPROTO_SCP }, + { "sftp", CURLPROTO_SFTP }, + { "telnet", CURLPROTO_TELNET }, + { "ldap", CURLPROTO_LDAP }, + { "ldaps", CURLPROTO_LDAPS }, + { "dict", CURLPROTO_DICT }, + { "file", CURLPROTO_FILE }, + { "tftp", CURLPROTO_TFTP }, + { "imap", CURLPROTO_IMAP }, + { "imaps", CURLPROTO_IMAPS }, + { "pop3", CURLPROTO_POP3 }, + { "pop3s", CURLPROTO_POP3S }, + { "smtp", CURLPROTO_SMTP }, + { "smtps", CURLPROTO_SMTPS }, + { "rtsp", CURLPROTO_RTSP }, + { "gopher", CURLPROTO_GOPHER }, + { NULL, 0 } + }; + + if(!str) + return 1; + + buffer = strdup(str); /* because strtok corrupts it */ + if(!buffer) + return 1; + + for(token = strtok(buffer, sep); + token; + token = strtok(NULL, sep)) { + enum e_action { allow, deny, set } action = allow; + + struct sprotos const *pp; + + /* Process token modifiers */ + while(!ISALNUM(*token)) { /* may be NULL if token is all modifiers */ + switch (*token++) { + case '=': + action = set; + break; + case '-': + action = deny; + break; + case '+': + action = allow; + break; + default: /* Includes case of terminating NULL */ + Curl_safefree(buffer); + return 1; + } + } + + for(pp=protos; pp->name; pp++) { + if(curlx_raw_equal(token, pp->name)) { + switch (action) { + case deny: + *val &= ~(pp->bit); + break; + case allow: + *val |= pp->bit; + break; + case set: + *val = pp->bit; + break; + } + break; + } + } + + if(!(pp->name)) { /* unknown protocol */ + /* If they have specified only this protocol, we say treat it as + if no protocols are allowed */ + if(action == set) + *val = 0; + warnf(config, "unrecognized protocol '%s'\n", token); + } + } + Curl_safefree(buffer); + return 0; +} + +/** + * Parses the given string looking for an offset (which may be + * a larger-than-integer value). + * + * @param val the offset to populate + * @param str the buffer containing the offset + * @return zero if successful, non-zero if failure. + */ +int str2offset(curl_off_t *val, const char *str) +{ +#if(CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG) + *val = curlx_strtoofft(str, NULL, 0); + if((*val == CURL_OFF_T_MAX || *val == CURL_OFF_T_MIN) && (ERRNO == ERANGE)) + return 1; +#else + *val = strtol(str, NULL, 0); + if((*val == LONG_MIN || *val == LONG_MAX) && ERRNO == ERANGE) + return 1; +#endif + return 0; +} + +ParameterError checkpasswd(const char *kind, /* for what purpose */ + char **userpwd) /* pointer to allocated string */ +{ + char *ptr; + + if(!*userpwd) + return PARAM_OK; + + ptr = strchr(*userpwd, ':'); + if(!ptr) { + /* no password present, prompt for one */ + char passwd[256] = ""; + char prompt[256]; + size_t passwdlen; + size_t userlen = strlen(*userpwd); + char *passptr; + + /* build a nice-looking prompt */ + curlx_msnprintf(prompt, sizeof(prompt), + "Enter %s password for user '%s':", + kind, *userpwd); + + /* get password */ + getpass_r(prompt, passwd, sizeof(passwd)); + passwdlen = strlen(passwd); + + /* extend the allocated memory area to fit the password too */ + passptr = realloc(*userpwd, + passwdlen + 1 + /* an extra for the colon */ + userlen + 1); /* an extra for the zero */ + if(!passptr) + return PARAM_NO_MEM; + + /* append the password separated with a colon */ + passptr[userlen] = ':'; + memcpy(&passptr[userlen+1], passwd, passwdlen+1); + *userpwd = passptr; + } + return PARAM_OK; +} + +ParameterError add2list(struct curl_slist **list, const char *ptr) +{ + struct curl_slist *newlist = curl_slist_append(*list, ptr); + if(newlist) + *list = newlist; + else + return PARAM_NO_MEM; + + return PARAM_OK; +} + +int ftpfilemethod(struct Configurable *config, const char *str) +{ + if(curlx_raw_equal("singlecwd", str)) + return CURLFTPMETHOD_SINGLECWD; + if(curlx_raw_equal("nocwd", str)) + return CURLFTPMETHOD_NOCWD; + if(curlx_raw_equal("multicwd", str)) + return CURLFTPMETHOD_MULTICWD; + warnf(config, "unrecognized ftp file method '%s', using default\n", str); + return CURLFTPMETHOD_MULTICWD; +} + +int ftpcccmethod(struct Configurable *config, const char *str) +{ + if(curlx_raw_equal("passive", str)) + return CURLFTPSSL_CCC_PASSIVE; + if(curlx_raw_equal("active", str)) + return CURLFTPSSL_CCC_ACTIVE; + warnf(config, "unrecognized ftp CCC method '%s', using default\n", str); + return CURLFTPSSL_CCC_PASSIVE; +} + +long delegation(struct Configurable *config, char *str) +{ + if(curlx_raw_equal("none", str)) + return CURLGSSAPI_DELEGATION_NONE; + if(curlx_raw_equal("policy", str)) + return CURLGSSAPI_DELEGATION_POLICY_FLAG; + if(curlx_raw_equal("always", str)) + return CURLGSSAPI_DELEGATION_FLAG; + warnf(config, "unrecognized delegation method '%s', using none\n", str); + return CURLGSSAPI_DELEGATION_NONE; +} + diff --git a/src/tool_paramhlp.h b/src/tool_paramhlp.h new file mode 100644 index 000000000..f17999198 --- /dev/null +++ b/src/tool_paramhlp.h @@ -0,0 +1,51 @@ +#ifndef HEADER_CURL_TOOL_PARAMHLP_H +#define HEADER_CURL_TOOL_PARAMHLP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +struct getout *new_getout(struct Configurable *config); + +ParameterError file2string(char **bufp, FILE *file); + +ParameterError file2memory(char **bufp, size_t *size, FILE *file); + +void cleanarg(char *str); + +int str2num(long *val, const char *str); + +long proto2num(struct Configurable *config, long *val, const char *str); + +int str2offset(curl_off_t *val, const char *str); + +ParameterError checkpasswd(const char *kind, char **userpwd); + +ParameterError add2list(struct curl_slist **list, const char *ptr); + +int ftpfilemethod(struct Configurable *config, const char *str); + +int ftpcccmethod(struct Configurable *config, const char *str); + +long delegation(struct Configurable *config, char *str); + +#endif /* HEADER_CURL_TOOL_PARAMHLP_H */ + diff --git a/src/tool_parsecfg.c b/src/tool_parsecfg.c new file mode 100644 index 000000000..b60d31830 --- /dev/null +++ b/src/tool_parsecfg.c @@ -0,0 +1,308 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_getparam.h" +#include "tool_helpers.h" +#include "tool_homedir.h" +#include "tool_msgs.h" +#include "tool_parsecfg.h" + +#include "memdebug.h" /* keep this as LAST include */ + +#define CURLRC DOT_CHAR "curlrc" +#define ISSEP(x) (((x) == '=') || ((x) == ':')) + +static const char *unslashquote(const char *line, char *param); +static char *my_get_line(FILE *fp); + +/* return 0 on everything-is-fine, and non-zero otherwise */ +int parseconfig(const char *filename, + struct Configurable *config) +{ + int res; + FILE *file; + char filebuffer[512]; + bool usedarg; + char *home; + int rc = 0; + + if(!filename || !*filename) { + /* NULL or no file name attempts to load .curlrc from the homedir! */ + +#ifndef __AMIGA__ + filename = CURLRC; /* sensible default */ + home = homedir(); /* portable homedir finder */ + if(home) { + if(strlen(home) < (sizeof(filebuffer) - strlen(CURLRC))) { + snprintf(filebuffer, sizeof(filebuffer), + "%s%s%s", home, DIR_CHAR, CURLRC); + +#ifdef WIN32 + /* Check if the file exists - if not, try CURLRC in the same + * directory as our executable + */ + file = fopen(filebuffer, "r"); + if(file != NULL) { + fclose(file); + filename = filebuffer; + } + else { + /* Get the filename of our executable. GetModuleFileName is + * already declared via inclusions done in setup header file. + * We assume that we are using the ASCII version here. + */ + int n = GetModuleFileName(0, filebuffer, sizeof(filebuffer)); + if(n > 0 && n < (int)sizeof(filebuffer)) { + /* We got a valid filename - get the directory part */ + char *lastdirchar = strrchr(filebuffer, '\\'); + if(lastdirchar) { + size_t remaining; + *lastdirchar = 0; + /* If we have enough space, build the RC filename */ + remaining = sizeof(filebuffer) - strlen(filebuffer); + if(strlen(CURLRC) < remaining - 1) { + snprintf(lastdirchar, remaining, + "%s%s", DIR_CHAR, CURLRC); + /* Don't bother checking if it exists - we do + * that later + */ + filename = filebuffer; + } + } + } + } +#else /* WIN32 */ + filename = filebuffer; +#endif /* WIN32 */ + } + Curl_safefree(home); /* we've used it, now free it */ + } + +# else /* __AMIGA__ */ + /* On AmigaOS all the config files are into env: + */ + filename = "ENV:" CURLRC; + +#endif + } + + if(strcmp(filename,"-")) + file = fopen(filename, "r"); + else + file = stdin; + + if(file) { + char *line; + char *aline; + char *option; + char *param; + int lineno = 0; + bool alloced_param; + + while(NULL != (aline = my_get_line(file))) { + lineno++; + line = aline; + alloced_param=FALSE; + + /* line with # in the first non-blank column is a comment! */ + while(*line && ISSPACE(*line)) + line++; + + switch(*line) { + case '#': + case '/': + case '\r': + case '\n': + case '*': + case '\0': + Curl_safefree(aline); + continue; + } + + /* the option keywords starts here */ + option = line; + while(*line && !ISSPACE(*line) && !ISSEP(*line)) + line++; + /* ... and has ended here */ + + if(*line) + *line++ = '\0'; /* zero terminate, we have a local copy of the data */ + +#ifdef DEBUG_CONFIG + fprintf(stderr, "GOT: %s\n", option); +#endif + + /* pass spaces and separator(s) */ + while(*line && (ISSPACE(*line) || ISSEP(*line))) + line++; + + /* the parameter starts here (unless quoted) */ + if(*line == '\"') { + /* quoted parameter, do the quote dance */ + line++; + param = malloc(strlen(line) + 1); /* parameter */ + if(!param) { + /* out of memory */ + Curl_safefree(aline); + rc = 1; + break; + } + alloced_param = TRUE; + (void)unslashquote(line, param); + } + else { + param = line; /* parameter starts here */ + while(*line && !ISSPACE(*line)) + line++; + *line = '\0'; /* zero terminate */ + } + + if(param && !*param) { + /* do this so getparameter can check for required parameters. + Otherwise it always thinks there's a parameter. */ + if(alloced_param) + Curl_safefree(param); + param = NULL; + } + +#ifdef DEBUG_CONFIG + fprintf(stderr, "PARAM: \"%s\"\n",(param ? param : "(null)")); +#endif + res = getparameter(option, param, &usedarg, config); + + if(param && *param && !usedarg) + /* we passed in a parameter that wasn't used! */ + res = PARAM_GOT_EXTRA_PARAMETER; + + if(res != PARAM_OK) { + /* the help request isn't really an error */ + if(!strcmp(filename, "-")) { + filename = (char *)"<stdin>"; + } + if(PARAM_HELP_REQUESTED != res) { + const char *reason = param2text(res); + warnf(config, "%s:%d: warning: '%s' %s\n", + filename, lineno, option, reason); + } + } + + if(alloced_param) + Curl_safefree(param); + + Curl_safefree(aline); + } + if(file != stdin) + fclose(file); + } + else + rc = 1; /* couldn't open the file */ + + return rc; +} + +/* + * Copies the string from line to the buffer at param, unquoting + * backslash-quoted characters and NUL-terminating the output string. + * Stops at the first non-backslash-quoted double quote character or the + * end of the input string. param must be at least as long as the input + * string. Returns the pointer after the last handled input character. + */ +static const char *unslashquote(const char *line, char *param) +{ + while(*line && (*line != '\"')) { + if(*line == '\\') { + char out; + line++; + + /* default is to output the letter after the backslash */ + switch(out = *line) { + case '\0': + continue; /* this'll break out of the loop */ + case 't': + out = '\t'; + break; + case 'n': + out = '\n'; + break; + case 'r': + out = '\r'; + break; + case 'v': + out = '\v'; + break; + } + *param++ = out; + line++; + } + else + *param++ = *line++; + } + *param = '\0'; /* always zero terminate */ + return line; +} + +/* + * Reads a line from the given file, ensuring is NUL terminated. + * The pointer must be freed by the caller. + * NULL is returned on an out of memory condition. + */ +static char *my_get_line(FILE *fp) +{ + char buf[4096]; + char *nl = NULL; + char *retval = NULL; + + do { + if(NULL == fgets(buf, sizeof(buf), fp)) + break; + if(!retval) { + retval = strdup(buf); + if(!retval) + return NULL; + } + else { + char *ptr; + ptr = realloc(retval, strlen(retval) + strlen(buf) + 1); + if(!ptr) { + Curl_safefree(retval); + return NULL; + } + retval = ptr; + strcat(retval, buf); + } + nl = strchr(retval, '\n'); + } while(!nl); + + if(nl) + *nl = '\0'; + + return retval; +} + diff --git a/src/tool_parsecfg.h b/src/tool_parsecfg.h new file mode 100644 index 000000000..faa1f1924 --- /dev/null +++ b/src/tool_parsecfg.h @@ -0,0 +1,30 @@ +#ifndef HEADER_CURL_TOOL_PARSECFG_H +#define HEADER_CURL_TOOL_PARSECFG_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +int parseconfig(const char *filename, + struct Configurable *config); + +#endif /* HEADER_CURL_TOOL_PARSECFG_H */ + diff --git a/src/tool_sdecls.h b/src/tool_sdecls.h new file mode 100644 index 000000000..50365273b --- /dev/null +++ b/src/tool_sdecls.h @@ -0,0 +1,141 @@ +#ifndef HEADER_CURL_TOOL_SDECLS_H +#define HEADER_CURL_TOOL_SDECLS_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + + +/* + * OutStruct variables keep track of information relative to curl's + * output writing, which may take place to a standard stream or a file. + * + * 'filename' member is either a pointer to a file name string or NULL + * when dealing with a standard stream. + * + * 'alloc_filename' member is TRUE when string pointed by 'filename' has been + * dynamically allocated and 'belongs' to this OutStruct, otherwise FALSE. + * + * 's_isreg' member is TRUE when output goes to a regular file, this also + * implies that output is 'seekable' and 'appendable' and also that member + * 'filename' points to file name's string. For any standard stream member + * 's_isreg' will be FALSE. + * + * 'fopened' member is TRUE when output goes to a regular file and it + * has been fopen'ed, requiring it to be closed later on. In any other + * case this is FALSE. + * + * 'stream' member is a pointer to a stream controlling object as returned + * from a 'fopen' call or a standard stream. + * + * 'config' member is a pointer to associated 'Configurable' struct. + * + * 'bytes' member represents amount written so far. + * + * 'init' member holds original file size or offset at which truncation is + * taking place. Always zero unless appending to a non-empty regular file. + */ + +struct OutStruct { + char *filename; + bool alloc_filename; + bool s_isreg; + bool fopened; + FILE *stream; + struct Configurable *config; + curl_off_t bytes; + curl_off_t init; +}; + + +/* + * InStruct variables keep track of information relative to curl's + * input reading, which may take place from stdin or from some file. + * + * 'fd' member is either 'stdin' file descriptor number STDIN_FILENO + * or a file descriptor as returned from an 'open' call for some file. + * + * 'config' member is a pointer to associated 'Configurable' struct. + */ + +struct InStruct { + int fd; + struct Configurable *config; +}; + + +/* + * A linked list of these 'getout' nodes contain URL's to fetch, + * as well as information relative to where URL contents should + * be stored or which file should be uploaded. + */ + +struct getout { + struct getout *next; /* next one */ + char *url; /* the URL we deal with */ + char *outfile; /* where to store the output */ + char *infile; /* file to upload, if GETOUT_UPLOAD is set */ + int flags; /* options - composed of GETOUT_* bits */ +}; + +#define GETOUT_OUTFILE (1<<0) /* set when outfile is deemed done */ +#define GETOUT_URL (1<<1) /* set when URL is deemed done */ +#define GETOUT_USEREMOTE (1<<2) /* use remote file name locally */ +#define GETOUT_UPLOAD (1<<3) /* if set, -T has been used */ +#define GETOUT_NOUPLOAD (1<<4) /* if set, -T "" has been used */ + + +/* + * 'trace' enumeration represents curl's output look'n feel possibilities. + */ + +typedef enum { + TRACE_NONE, /* no trace/verbose output at all */ + TRACE_BIN, /* tcpdump inspired look */ + TRACE_ASCII, /* like *BIN but without the hex output */ + TRACE_PLAIN /* -v/--verbose type */ +} trace; + + +/* + * 'HttpReq' enumeration represents HTTP request types. + */ + +typedef enum { + HTTPREQ_UNSPEC, /* first in list */ + HTTPREQ_GET, + HTTPREQ_HEAD, + HTTPREQ_POST, + HTTPREQ_SIMPLEPOST, + HTTPREQ_CUSTOM, + HTTPREQ_LAST /* last in list */ +} HttpReq; + + +/* + * Complete struct declarations which have Configurable struct members, + * just in case this header is directly included in some source file. + */ + +#include "tool_cfgable.h" + +#endif /* HEADER_CURL_TOOL_SDECLS_H */ + diff --git a/src/tool_setopt.c b/src/tool_setopt.c new file mode 100644 index 000000000..b636aab38 --- /dev/null +++ b/src/tool_setopt.c @@ -0,0 +1,125 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#include <curl/curl.h> + +#define ENABLE_CURLX_PRINTF +/* use our own printf() functions */ +#include "curlx.h" + +#include "tool_cfgable.h" +#include "tool_easysrc.h" +#include "tool_setopt.h" + +#include "memdebug.h" /* keep this as LAST include */ + +CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, + const char *name, CURLoption tag, ...) +{ + va_list arg; + char *bufp; + char value[256]; + bool remark = FALSE; + bool skip = FALSE; + CURLcode ret = CURLE_OK; + + va_start(arg, tag); + + if(tag < CURLOPTTYPE_OBJECTPOINT) { + long lval = va_arg(arg, long); + snprintf(value, sizeof(value), "%ldL", lval); + ret = curl_easy_setopt(curl, tag, lval); + if(!lval) + skip = TRUE; + } + else if(tag < CURLOPTTYPE_OFF_T) { + void *pval = va_arg(arg, void *); + unsigned char *ptr = (unsigned char *)pval; + + /* function pointers are never printable */ + if(tag >= CURLOPTTYPE_FUNCTIONPOINT) { + if(pval) { + strcpy(value, "functionpointer"); /* 'value' fits 256 bytes */ + remark = TRUE; + } + else + skip = TRUE; + } + + else if(pval && str) + snprintf(value, sizeof(value), "\"%s\"", (char *)ptr); + else if(pval) { + strcpy(value, "objectpointer"); /* 'value' fits 256 bytes */ + remark = TRUE; + } + else + skip = TRUE; + + ret = curl_easy_setopt(curl, tag, pval); + + } + else { + curl_off_t oval = va_arg(arg, curl_off_t); + snprintf(value, sizeof(value), + "(curl_off_t)%" CURL_FORMAT_CURL_OFF_T, oval); + ret = curl_easy_setopt(curl, tag, oval); + + if(!oval) + skip = TRUE; + } + + va_end(arg); + + if(config->libcurl && !skip && !ret) { + /* we only use this for real if --libcurl was used */ + + if(remark) + bufp = curlx_maprintf("%s set to a %s", name, value); + else + bufp = curlx_maprintf("curl_easy_setopt(hnd, %s, %s);", name, value); + + if(!bufp) + ret = CURLE_OUT_OF_MEMORY; + else { + struct curl_slist *list = + curl_slist_append(remark?easysrc_remarks:easysrc, bufp); + + curl_free(bufp); + + if(!list) { + curl_slist_free_all(easysrc_remarks); + curl_slist_free_all(easysrc); + easysrc_remarks = NULL; + easysrc = NULL; + ret = CURLE_OUT_OF_MEMORY; + } + else if(remark) + easysrc_remarks = list; + else + easysrc = list; + } + } + + return ret; +} + diff --git a/src/tool_setopt.h b/src/tool_setopt.h new file mode 100644 index 000000000..d01c9eb24 --- /dev/null +++ b/src/tool_setopt.h @@ -0,0 +1,50 @@ +#ifndef HEADER_CURL_TOOL_SETOPT_H +#define HEADER_CURL_TOOL_SETOPT_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +CURLcode tool_setopt(CURL *curl, bool str, struct Configurable *config, + const char *name, CURLoption tag, ...); + +/* + * Macros used in operate() + */ + +#define my_setopt(x,y,z) do { \ + res = tool_setopt(x, FALSE, config, #y, y, z); \ + if(res) \ + goto show_error; \ +} WHILE_FALSE + +#define my_setopt_str(x,y,z) do { \ + res = tool_setopt(x, TRUE, config, #y, y, z); \ + if(res) \ + goto show_error; \ +} WHILE_FALSE + +#define res_setopt(x,y,z) tool_setopt(x, FALSE, config, #y, y, z) + +#define res_setopt_str(x,y,z) tool_setopt(x, TRUE, config, #y, y, z) + +#endif /* HEADER_CURL_TOOL_SETOPT_H */ + diff --git a/src/tool_sleep.c b/src/tool_sleep.c new file mode 100644 index 000000000..08db8861b --- /dev/null +++ b/src/tool_sleep.c @@ -0,0 +1,62 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif + +#ifdef HAVE_SYS_SOCKET_H +# include <sys/socket.h> +#endif + +#ifdef HAVE_SYS_POLL_H +# include <sys/poll.h> +#elif defined(HAVE_POLL_H) +# include <poll.h> +#endif + +#ifdef MSDOS +# include <dos.h> +#endif + +#include "tool_sleep.h" + +#include "memdebug.h" /* keep this as LAST include */ + +void tool_go_sleep(long ms) +{ +#if defined(MSDOS) + delay(ms); +#elif defined(WIN32) + Sleep(ms); +#elif defined(HAVE_POLL_FINE) + poll((void *)0, 0, (int)ms); +#else + struct timeval timeout; + timeout.tv_sec = ms / 1000L; + ms = ms % 1000L; + timeout.tv_usec = ms * 1000L; + select(0, NULL, NULL, NULL, &timeout); +#endif +} + diff --git a/src/tool_sleep.h b/src/tool_sleep.h new file mode 100644 index 000000000..29655cedd --- /dev/null +++ b/src/tool_sleep.h @@ -0,0 +1,29 @@ +#ifndef HEADER_CURL_TOOL_SLEEP_H +#define HEADER_CURL_TOOL_SLEEP_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +void tool_go_sleep(long ms); + +#endif /* HEADER_CURL_TOOL_SLEEP_H */ + diff --git a/src/urlglob.c b/src/tool_urlglob.c index 8dd77e136..f5c09a1e8 100644 --- a/src/urlglob.c +++ b/src/tool_urlglob.c @@ -19,28 +19,21 @@ * KIND, either express or implied. * ***************************************************************************/ - -/* client-local setup.h */ #include "setup.h" -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <ctype.h> #include <curl/curl.h> #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */ #include <curl/mprintf.h> -#include "urlglob.h" -#include "os-specific.h" +#include "tool_urlglob.h" +#include "tool_vms.h" -#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG) -#include "memdebug.h" -#endif +#include "memdebug.h" /* keep this as LAST include */ typedef enum { GLOB_OK, + GLOB_NO_MEM, GLOB_ERROR } GlobCode; @@ -61,11 +54,12 @@ static GlobCode glob_set(URLGlob *glob, char *pattern, /* processes a set expression with the point behind the opening '{' ','-separated elements are collected until the next closing '}' */ + URLPattern *pat; + GlobCode res; bool done = FALSE; char* buf = glob->glob_buffer; - URLPattern *pat; - pat = (URLPattern*)&glob->pattern[glob->size / 2]; + pat = &glob->pattern[glob->size / 2]; /* patterns 0,1,2,... correspond to size=1,3,5,... */ pat->type = UPTSet; pat->content.Set.size = 0; @@ -90,22 +84,36 @@ static GlobCode glob_set(URLGlob *glob, char *pattern, case ',': case '}': /* set element completed */ *buf = '\0'; - if(pat->content.Set.elements) - pat->content.Set.elements = - realloc(pat->content.Set.elements, - (pat->content.Set.size + 1) * sizeof(char*)); + if(pat->content.Set.elements) { + char **new_arr = realloc(pat->content.Set.elements, + (pat->content.Set.size + 1) * sizeof(char*)); + if(!new_arr) { + short elem; + for(elem = 0; elem < pat->content.Set.size; elem++) + Curl_safefree(pat->content.Set.elements[elem]); + Curl_safefree(pat->content.Set.elements); + pat->content.Set.ptr_s = 0; + pat->content.Set.size = 0; + } + pat->content.Set.elements = new_arr; + } else - pat->content.Set.elements = - malloc((pat->content.Set.size + 1) * sizeof(char*)); + pat->content.Set.elements = malloc(sizeof(char*)); if(!pat->content.Set.elements) { - snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory"); - return GLOB_ERROR; + snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); + return GLOB_NO_MEM; } pat->content.Set.elements[pat->content.Set.size] = strdup(glob->glob_buffer); if(!pat->content.Set.elements[pat->content.Set.size]) { - snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory"); - return GLOB_ERROR; + short elem; + for(elem = 0; elem < pat->content.Set.size; elem++) + Curl_safefree(pat->content.Set.elements[elem]); + Curl_safefree(pat->content.Set.elements); + pat->content.Set.ptr_s = 0; + pat->content.Set.size = 0; + snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); + return GLOB_NO_MEM; } ++pat->content.Set.size; @@ -114,8 +122,17 @@ static GlobCode glob_set(URLGlob *glob, char *pattern, int wordamount; /* always check for a literal (may be "") between patterns */ - if(GLOB_ERROR == glob_word(glob, ++pattern, ++pos, &wordamount)) - return GLOB_ERROR; + res = glob_word(glob, ++pattern, ++pos, &wordamount); + if(res) { + short elem; + for(elem = 0; elem < pat->content.Set.size; elem++) + Curl_safefree(pat->content.Set.elements[elem]); + Curl_safefree(pat->content.Set.elements); + pat->content.Set.ptr_s = 0; + pat->content.Set.size = 0; + return res; + } + *amount = pat->content.Set.size * wordamount; done = TRUE; @@ -157,22 +174,26 @@ static GlobCode glob_range(URLGlob *glob, char *pattern, */ URLPattern *pat; char *c; - int wordamount=1; char sep; char sep2; int step; int rc; + GlobCode res; + int wordamount = 1; - pat = (URLPattern*)&glob->pattern[glob->size / 2]; + pat = &glob->pattern[glob->size / 2]; /* patterns 0,1,2,... correspond to size=1,3,5,... */ ++glob->size; - if(ISALPHA(*pattern)) { /* character range detected */ + if(ISALPHA(*pattern)) { + /* character range detected */ char min_c; char max_c; pat->type = UPTCharRange; + rc = sscanf(pattern, "%c-%c%c%d%c", &min_c, &max_c, &sep, &step, &sep2); + if((rc < 3) || (min_c >= max_c) || ((max_c - min_c) > ('z' - 'a'))) { /* the pattern is not well-formed */ snprintf(glob->errormsg, sizeof(glob->errormsg), @@ -190,12 +211,13 @@ static GlobCode glob_range(URLGlob *glob, char *pattern, /* if there was a ":[num]" thing, use that as step or else use 1 */ pat->content.CharRange.step = - ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1; + ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1; pat->content.CharRange.ptr_c = pat->content.CharRange.min_c = min_c; pat->content.CharRange.max_c = max_c; } - else if(ISDIGIT(*pattern)) { /* numeric range detected */ + else if(ISDIGIT(*pattern)) { + /* numeric range detected */ int min_n; int max_n; @@ -210,14 +232,15 @@ static GlobCode glob_range(URLGlob *glob, char *pattern, "error: bad range specification after pos %zu\n", pos); return GLOB_ERROR; } - pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n; + pat->content.NumRange.ptr_n = pat->content.NumRange.min_n = min_n; pat->content.NumRange.max_n = max_n; /* if there was a ":[num]" thing, use that as step or else use 1 */ pat->content.NumRange.step = - ((sep == ':') && (rc == 5) && (sep2 == ']'))?step:1; + ((sep == ':') && (rc == 5) && (sep2 == ']')) ? step : 1; - if(*pattern == '0') { /* leading zero specified */ + if(*pattern == '0') { + /* leading zero specified */ c = pattern; while(ISDIGIT(*c)) { c++; @@ -225,7 +248,6 @@ static GlobCode glob_range(URLGlob *glob, char *pattern, instances of this pattern */ } } - } else { snprintf(glob->errormsg, sizeof(glob->errormsg), @@ -243,18 +265,22 @@ static GlobCode glob_range(URLGlob *glob, char *pattern, /* always check for a literal (may be "") between patterns */ - if(GLOB_ERROR == glob_word(glob, c, pos + (c - pattern), &wordamount)) + res = glob_word(glob, c, pos + (c - pattern), &wordamount); + if(res == GLOB_ERROR) { wordamount = 1; + res = GLOB_OK; + } - if(pat->type == UPTCharRange) - *amount = (pat->content.CharRange.max_c - - pat->content.CharRange.min_c + 1) * - wordamount; - else - *amount = (pat->content.NumRange.max_n - - pat->content.NumRange.min_n + 1) * wordamount; + if(!res) { + if(pat->type == UPTCharRange) + *amount = wordamount * (pat->content.CharRange.max_c - + pat->content.CharRange.min_c + 1); + else + *amount = wordamount * (pat->content.NumRange.max_n - + pat->content.NumRange.min_n + 1); + } - return GLOB_OK; + return res; /* GLOB_OK or GLOB_NO_MEM */ } static GlobCode glob_word(URLGlob *glob, char *pattern, @@ -285,20 +311,23 @@ static GlobCode glob_word(URLGlob *glob, char *pattern, ++pattern; ++pos; } - *buf++ = *pattern++; /* copy character to literal */ + *buf++ = *pattern++; /* copy character to literal */ ++pos; } *buf = '\0'; litindex = glob->size / 2; /* literals 0,1,2,... correspond to size=0,2,4,... */ glob->literal[litindex] = strdup(glob->glob_buffer); - if(!glob->literal[litindex]) - return GLOB_ERROR; + if(!glob->literal[litindex]) { + snprintf(glob->errormsg, sizeof(glob->errormsg), "out of memory\n"); + return GLOB_NO_MEM; + } ++glob->size; switch (*pattern) { case '\0': - break; /* singular URL processed */ + /* singular URL processed */ + break; case '{': /* process set pattern */ @@ -307,15 +336,14 @@ static GlobCode glob_word(URLGlob *glob, char *pattern, case '[': /* process range pattern */ - res= glob_range(glob, ++pattern, ++pos, amount); + res = glob_range(glob, ++pattern, ++pos, amount); break; } - if(GLOB_OK != res) - /* free that strdup'ed string again */ - free(glob->literal[litindex]); + if(res) + Curl_safefree(glob->literal[litindex]); - return res; /* something got wrong */ + return res; } int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error) @@ -326,35 +354,40 @@ int glob_url(URLGlob** glob, char* url, int *urlnum, FILE *error) */ URLGlob *glob_expand; int amount; - char *glob_buffer = malloc(strlen(url)+1); + char *glob_buffer; + GlobCode res; *glob = NULL; - if(NULL == glob_buffer) + + glob_buffer = malloc(strlen(url) + 1); + if(!glob_buffer) return CURLE_OUT_OF_MEMORY; glob_expand = calloc(1, sizeof(URLGlob)); - if(NULL == glob_expand) { - free(glob_buffer); + if(!glob_expand) { + Curl_safefree(glob_buffer); return CURLE_OUT_OF_MEMORY; } glob_expand->size = 0; glob_expand->urllen = strlen(url); glob_expand->glob_buffer = glob_buffer; - glob_expand->beenhere=0; - if(GLOB_OK == glob_word(glob_expand, url, 1, &amount)) + glob_expand->beenhere = 0; + + res = glob_word(glob_expand, url, 1, &amount); + if(!res) *urlnum = amount; else { if(error && glob_expand->errormsg[0]) { /* send error description to the error-stream */ fprintf(error, "curl: (%d) [globbing] %s", - CURLE_URL_MALFORMAT, glob_expand->errormsg); + (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT, + glob_expand->errormsg); } /* it failed, we cleanup */ - free(glob_buffer); - free(glob_expand); - glob_expand = NULL; + Curl_safefree(glob_buffer); + Curl_safefree(glob_expand); *urlnum = 1; - return CURLE_URL_MALFORMAT; + return (res == GLOB_NO_MEM) ? CURLE_OUT_OF_MEMORY : CURLE_URL_MALFORMAT; } *glob = glob_expand; @@ -368,7 +401,7 @@ void glob_cleanup(URLGlob* glob) for(i = glob->size - 1; i < glob->size; --i) { if(!(i & 1)) { /* even indexes contain literals */ - free(glob->literal[i/2]); + Curl_safefree(glob->literal[i/2]); } else { /* odd indexes contain sets or ranges */ if((glob->pattern[i/2].type == UPTSet) && @@ -376,26 +409,27 @@ void glob_cleanup(URLGlob* glob) for(elem = glob->pattern[i/2].content.Set.size - 1; elem >= 0; --elem) { - if(glob->pattern[i/2].content.Set.elements[elem]) - free(glob->pattern[i/2].content.Set.elements[elem]); + Curl_safefree(glob->pattern[i/2].content.Set.elements[elem]); } - free(glob->pattern[i/2].content.Set.elements); + Curl_safefree(glob->pattern[i/2].content.Set.elements); } } } - free(glob->glob_buffer); - free(glob); + Curl_safefree(glob->glob_buffer); + Curl_safefree(glob); } -char *glob_next_url(URLGlob *glob) +int glob_next_url(char **globbed, URLGlob *glob) { - char *buf = glob->glob_buffer; URLPattern *pat; char *lit; size_t i; size_t j; - size_t buflen = glob->urllen+1; size_t len; + size_t buflen = glob->urllen + 1; + char *buf = glob->glob_buffer; + + *globbed = NULL; if(!glob->beenhere) glob->beenhere = 1; @@ -404,12 +438,13 @@ char *glob_next_url(URLGlob *glob) /* implement a counter over the index ranges of all patterns, starting with the rightmost pattern */ - for(i = glob->size / 2 - 1; carry && i < glob->size; --i) { + for(i = glob->size / 2 - 1; carry && (i < glob->size); --i) { carry = FALSE; pat = &glob->pattern[i]; switch (pat->type) { case UPTSet: - if(++pat->content.Set.ptr_s == pat->content.Set.size) { + if((pat->content.Set.elements) && + (++pat->content.Set.ptr_s == pat->content.Set.size)) { pat->content.Set.ptr_s = 0; carry = TRUE; } @@ -431,11 +466,13 @@ char *glob_next_url(URLGlob *glob) break; default: printf("internal error: invalid pattern type (%d)\n", (int)pat->type); - exit (CURLE_FAILED_INIT); + return CURLE_FAILED_INIT; } } - if(carry) /* first pattern ptr has run into overflow, done! */ - return NULL; + if(carry) { /* first pattern ptr has run into overflow, done! */ + /* TODO: verify if this should actally return CURLE_OK. */ + return CURLE_OK; /* CURLE_OK to match previous behavior */ + } } for(j = 0; j < glob->size; ++j) { @@ -449,11 +486,13 @@ char *glob_next_url(URLGlob *glob) pat = &glob->pattern[j/2]; switch(pat->type) { case UPTSet: - len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]); - snprintf(buf, buflen, "%s", - pat->content.Set.elements[pat->content.Set.ptr_s]); - buf += len; - buflen -= len; + if(pat->content.Set.elements) { + len = strlen(pat->content.Set.elements[pat->content.Set.ptr_s]); + snprintf(buf, buflen, "%s", + pat->content.Set.elements[pat->content.Set.ptr_s]); + buf += len; + buflen -= len; + } break; case UPTCharRange: *buf++ = pat->content.CharRange.ptr_c; @@ -467,52 +506,62 @@ char *glob_next_url(URLGlob *glob) break; default: printf("internal error: invalid pattern type (%d)\n", (int)pat->type); - exit (CURLE_FAILED_INIT); + return CURLE_FAILED_INIT; } } } *buf = '\0'; - return strdup(glob->glob_buffer); + + *globbed = strdup(glob->glob_buffer); + if(!*globbed) + return CURLE_OUT_OF_MEMORY; + + return CURLE_OK; } -char *glob_match_url(char *filename, URLGlob *glob) +int glob_match_url(char **result, char *filename, URLGlob *glob) { char *target; size_t allocsize; - size_t stringlen=0; char numbuf[18]; char *appendthis = NULL; size_t appendlen = 0; + size_t stringlen = 0; + + *result = NULL; /* We cannot use the glob_buffer for storage here since the filename may * be longer than the URL we use. We allocate a good start size, then * we need to realloc in case of need. */ - allocsize=strlen(filename)+1; /* make it at least one byte to store the - trailing zero */ + allocsize = strlen(filename) + 1; /* make it at least one byte to store the + trailing zero */ target = malloc(allocsize); - if(NULL == target) - return NULL; /* major failure */ + if(!target) + return CURLE_OUT_OF_MEMORY; while(*filename) { if(*filename == '#' && ISDIGIT(filename[1])) { unsigned long i; char *ptr = filename; unsigned long num = strtoul(&filename[1], &filename, 10); - i = num-1; + i = num - 1UL; if(num && (i <= glob->size / 2)) { URLPattern pat = glob->pattern[i]; switch (pat.type) { case UPTSet: - appendthis = pat.content.Set.elements[pat.content.Set.ptr_s]; - appendlen = strlen(pat.content.Set.elements[pat.content.Set.ptr_s]); + if(pat.content.Set.elements) { + appendthis = pat.content.Set.elements[pat.content.Set.ptr_s]; + appendlen = + strlen(pat.content.Set.elements[pat.content.Set.ptr_s]); + } break; case UPTCharRange: - numbuf[0]=pat.content.CharRange.ptr_c; - numbuf[1]=0; - appendthis=numbuf; - appendlen=1; + numbuf[0] = pat.content.CharRange.ptr_c; + numbuf[1] = 0; + appendthis = numbuf; + appendlen = 1; break; case UPTNumRange: snprintf(numbuf, sizeof(numbuf), "%0*d", @@ -524,36 +573,38 @@ char *glob_match_url(char *filename, URLGlob *glob) default: printf("internal error: invalid pattern type (%d)\n", (int)pat.type); - free(target); - return NULL; + Curl_safefree(target); + return CURLE_FAILED_INIT; } } else { /* #[num] out of range, use the #[num] in the output */ filename = ptr; - appendthis=filename++; - appendlen=1; + appendthis = filename++; + appendlen = 1; } } else { - appendthis=filename++; - appendlen=1; + appendthis = filename++; + appendlen = 1; } if(appendlen + stringlen >= allocsize) { char *newstr; /* we append a single byte to allow for the trailing byte to be appended at the end of this function outside the while() loop */ - allocsize = (appendlen + stringlen)*2; - newstr=realloc(target, allocsize + 1); - if(NULL ==newstr) { - free(target); - return NULL; + allocsize = (appendlen + stringlen) * 2; + newstr = realloc(target, allocsize + 1); + if(!newstr) { + Curl_safefree(target); + return CURLE_OUT_OF_MEMORY; } - target=newstr; + target = newstr; } memcpy(&target[stringlen], appendthis, appendlen); stringlen += appendlen; } target[stringlen]= '\0'; - return target; + *result = target; + return CURLE_OK; } + diff --git a/src/urlglob.h b/src/tool_urlglob.h index a5b789e6b..18281bf61 100644 --- a/src/urlglob.h +++ b/src/tool_urlglob.h @@ -1,5 +1,5 @@ -#ifndef __URLGLOB_H -#define __URLGLOB_H +#ifndef HEADER_CURL_TOOL_URLGLOB_H +#define HEADER_CURL_TOOL_URLGLOB_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,8 +21,10 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" + typedef enum { - UPTSet=1, + UPTSet = 1, UPTCharRange, UPTNumRange } URLPatternType; @@ -36,12 +38,14 @@ typedef struct { short ptr_s; } Set; struct { - char min_c, max_c; + char min_c; + char max_c; char ptr_c; int step; } CharRange; struct { - int min_n, max_n; + int min_n; + int max_n; short padlength; int ptr_n; int step; @@ -50,7 +54,7 @@ typedef struct { } URLPattern; typedef struct { - char* literal[10]; + char *literal[10]; URLPattern pattern[9]; size_t size; size_t urllen; @@ -60,8 +64,9 @@ typedef struct { } URLGlob; int glob_url(URLGlob**, char*, int *, FILE *); -char* glob_next_url(URLGlob*); -char* glob_match_url(char*, URLGlob *); +int glob_next_url(char **, URLGlob *); +int glob_match_url(char **, char*, URLGlob *); void glob_cleanup(URLGlob* glob); -#endif +#endif /* HEADER_CURL_TOOL_URLGLOB_H */ + diff --git a/src/curlutil.c b/src/tool_util.c index bca2db7aa..79c998295 100644 --- a/src/curlutil.c +++ b/src/tool_util.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,14 +19,15 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "setup.h" -#include "curlutil.h" +#include "tool_util.h" + +#include "memdebug.h" /* keep this as LAST include */ #if defined(WIN32) && !defined(MSDOS) -struct timeval cutil_tvnow(void) +struct timeval tool_tvnow(void) { /* ** GetTickCount() is available on _all_ Windows versions from W95 up @@ -42,7 +43,7 @@ struct timeval cutil_tvnow(void) #elif defined(HAVE_CLOCK_GETTIME_MONOTONIC) -struct timeval cutil_tvnow(void) +struct timeval tool_tvnow(void) { /* ** clock_gettime() is granted to be increased monotonically when the @@ -76,7 +77,7 @@ struct timeval cutil_tvnow(void) #elif defined(HAVE_GETTIMEOFDAY) -struct timeval cutil_tvnow(void) +struct timeval tool_tvnow(void) { /* ** gettimeofday() is not granted to be increased monotonically, due to @@ -90,7 +91,7 @@ struct timeval cutil_tvnow(void) #else -struct timeval cutil_tvnow(void) +struct timeval tool_tvnow(void) { /* ** time() returns the value of time in seconds since the Epoch. @@ -109,25 +110,25 @@ struct timeval cutil_tvnow(void) * * Returns: the time difference in number of milliseconds. */ -long cutil_tvdiff(struct timeval newer, struct timeval older) +long tool_tvdiff(struct timeval newer, struct timeval older) { return (newer.tv_sec-older.tv_sec)*1000+ (newer.tv_usec-older.tv_usec)/1000; } /* - * Same as cutil_tvdiff but with full usec resolution. + * Same as tool_tvdiff but with full usec resolution. * * Returns: the time difference in seconds with subsecond resolution. */ -double cutil_tvdiff_secs(struct timeval newer, struct timeval older) +double tool_tvdiff_secs(struct timeval newer, struct timeval older) { return (double)(newer.tv_sec-older.tv_sec)+ (double)(newer.tv_usec-older.tv_usec)/1000000.0; } /* return the number of seconds in the given input timeval struct */ -long cutil_tvlong(struct timeval t1) +long tool_tvlong(struct timeval t1) { return t1.tv_sec; } diff --git a/src/curlutil.h b/src/tool_util.h index a993a775e..7c2a2978a 100644 --- a/src/curlutil.h +++ b/src/tool_util.h @@ -1,5 +1,5 @@ -#ifndef __CURL_SRC_UTIL_H -#define __CURL_SRC_UTIL_H +#ifndef HEADER_CURL_TOOL_UTIL_H +#define HEADER_CURL_TOOL_UTIL_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2007, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,11 +21,9 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "setup.h" - -struct timeval cutil_tvnow(void); +struct timeval tool_tvnow(void); /* * Make sure that the first argument (t1) is the more recent time and t2 is @@ -33,17 +31,26 @@ struct timeval cutil_tvnow(void); * * Returns: the time difference in number of milliseconds. */ -long cutil_tvdiff(struct timeval t1, struct timeval t2); +long tool_tvdiff(struct timeval t1, struct timeval t2); /* - * Same as cutil_tvdiff but with full usec resolution. + * Same as tool_tvdiff but with full usec resolution. * * Returns: the time difference in seconds with subsecond resolution. */ -double cutil_tvdiff_secs(struct timeval t1, struct timeval t2); +double tool_tvdiff_secs(struct timeval t1, struct timeval t2); + +long tool_tvlong(struct timeval t1); -long cutil_tvlong(struct timeval t1); +#undef tvnow +#undef tvdiff +#undef tvdiff_secs +#undef tvlong +#define tvnow() tool_tvnow() +#define tvdiff(a,b) tool_tvdiff((a), (b)) +#define tvdiff_secs(a,b) tool_tvdiff_secs((a), (b)) +#define tvlong(a) tool_tvlong((a)) -#endif /* __CURL_SRC_UTIL_H */ +#endif /* HEADER_CURL_TOOL_UTIL_H */ diff --git a/src/version.h b/src/tool_version.h index ce83b8579..569526bfe 100644 --- a/src/version.h +++ b/src/tool_version.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_VERSION_H -#define HEADER_CURL_VERSION_H +#ifndef HEADER_CURL_TOOL_VERSION_H +#define HEADER_CURL_TOOL_VERSION_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,7 +21,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include <curl/curlver.h> #define CURL_NAME "curl" @@ -32,4 +31,4 @@ #define CURL_VERSION_PATCH LIBCURL_VERSION_PATCH #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " -#endif /* HEADER_CURL_VERSION_H */ +#endif /* HEADER_CURL_TOOL_VERSION_H */ diff --git a/src/os-specific.c b/src/tool_vms.c index ac07c4cec..b1ecfe551 100644 --- a/src/os-specific.c +++ b/src/tool_vms.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,20 +21,22 @@ ***************************************************************************/ #include "setup.h" +#ifdef __VMS + +#if defined(__DECC) && !defined(__VAX) && \ + defined(__CRTL_VER) && (__CRTL_VER >= 70301000) +#include <unixlib.h> +#endif + #include <curl/curl.h> #define ENABLE_CURLX_PRINTF #include "curlx.h" -#include "os-specific.h" - -#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG) -# include "memdebug.h" -#endif - -#ifdef __VMS - #include "curlmsg_vms.h" +#include "tool_vms.h" + +#include "memdebug.h" /* keep this as LAST include */ void decc$__posix_exit(int __status); void decc$exit(int __status); @@ -121,8 +123,6 @@ void vms_special_exit(int code, int vms_show) * requiring the user to define the corresponding logical names. */ -#include <unixlib.h> - /* Structure to hold a DECC$* feature name and its desired value. */ typedef struct { char *name; diff --git a/src/os-specific.h b/src/tool_vms.h index 93cac743c..56db34ba1 100644 --- a/src/os-specific.h +++ b/src/tool_vms.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_OS_SPECIFIC_H -#define HEADER_CURL_OS_SPECIFIC_H +#ifndef HEADER_CURL_TOOL_VMS_H +#define HEADER_CURL_TOOL_VMS_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,7 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" #ifdef __VMS @@ -35,4 +36,5 @@ void vms_special_exit(int code, int vms_show); #endif /* __VMS */ -#endif /* HEADER_CURL_OS_SPECIFIC_H */ +#endif /* HEADER_CURL_TOOL_VMS_H */ + diff --git a/src/writeenv.c b/src/tool_writeenv.c index e3edbec75..232ab697c 100644 --- a/src/writeenv.c +++ b/src/tool_writeenv.c @@ -19,24 +19,22 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "setup.h" #ifdef USE_ENVIRONMENT -#include <curl/curl.h> -#include "writeenv.h" - #ifdef __riscos__ -#include <kernel.h> +# include <kernel.h> #endif +#include <curl/curl.h> + #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> -#if defined(CURLDEBUG) && defined(CURLTOOLDEBUG) -#include "memdebug.h" -#endif +#include "tool_writeenv.h" + +#include "memdebug.h" /* keep this as LAST include */ static const struct { diff --git a/src/tool_writeenv.h b/src/tool_writeenv.h new file mode 100644 index 000000000..74fdc97d9 --- /dev/null +++ b/src/tool_writeenv.h @@ -0,0 +1,35 @@ +#ifndef HEADER_CURL_TOOL_WRITEENV_H +#define HEADER_CURL_TOOL_WRITEENV_H +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "setup.h" + +#ifdef USE_ENVIRONMENT + +void ourWriteEnv(CURL *curl); + +#else +# define ourWriteEnv(x) Curl_nop_stmt +#endif + +#endif /* HEADER_CURL_TOOL_WRITEENV_H */ + diff --git a/src/writeout.c b/src/tool_writeout.c index e044a9d8e..1ea1c9881 100644 --- a/src/writeout.c +++ b/src/tool_writeout.c @@ -19,25 +19,16 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "setup.h" -#include <stdio.h> -#include <string.h> - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_SELECT_H -#include <sys/select.h> -#endif - #include <curl/curl.h> #define _MPRINTF_REPLACE /* we want curl-functions instead of native ones */ #include <curl/mprintf.h> -#include "writeout.h" +#include "tool_writeout.h" + +#include "memdebug.h" /* keep this as LAST include */ typedef enum { VAR_NONE, /* must be the first */ @@ -102,7 +93,7 @@ static const struct variable replacements[]={ void ourWriteOut(CURL *curl, const char *writeinfo) { FILE *stream = stdout; - const char *ptr=writeinfo; + const char *ptr = writeinfo; char *stringp; long longinfo; double doubleinfo; @@ -112,7 +103,7 @@ void ourWriteOut(CURL *curl, const char *writeinfo) if('%' == ptr[1]) { /* an escaped %-letter */ fputc('%', stream); - ptr+=2; + ptr += 2; } else { /* this is meant as a variable to output */ @@ -121,10 +112,10 @@ void ourWriteOut(CURL *curl, const char *writeinfo) int i; if(('{' == ptr[1]) && ((end = strchr(ptr, '}')) != NULL)) { bool match = FALSE; - ptr+=2; /* pass the % and the { */ - keepit=*end; - *end=0; /* zero terminate */ - for(i=0; replacements[i].name; i++) { + ptr += 2; /* pass the % and the { */ + keepit = *end; + *end = 0; /* zero terminate */ + for(i = 0; replacements[i].name; i++) { if(curl_strequal(ptr, replacements[i].name)) { match = TRUE; switch(replacements[i].id) { @@ -257,17 +248,17 @@ void ourWriteOut(CURL *curl, const char *writeinfo) break; } } - if(FALSE == match) { + if(!match) { fprintf(stderr, "curl: unknown --write-out variable: '%s'\n", ptr); } - ptr=end+1; /* pass the end */ + ptr = end + 1; /* pass the end */ *end = keepit; } else { /* illegal syntax, then just output the characters that are used */ fputc('%', stream); fputc(ptr[1], stream); - ptr+=2; + ptr += 2; } } } @@ -288,7 +279,7 @@ void ourWriteOut(CURL *curl, const char *writeinfo) fputc(ptr[1], stream); break; } - ptr+=2; + ptr += 2; } else { fputc(*ptr, stream); diff --git a/src/writeout.h b/src/tool_writeout.h index 1b221026e..815cfcfff 100644 --- a/src/writeout.h +++ b/src/tool_writeout.h @@ -1,5 +1,5 @@ -#ifndef HEADER_CURL_WRITEOUT_H -#define HEADER_CURL_WRITEOUT_H +#ifndef HEADER_CURL_TOOL_WRITEOUT_H +#define HEADER_CURL_TOOL_WRITEOUT_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,7 +21,8 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" void ourWriteOut(CURL *curl, const char *out); -#endif /* HEADER_CURL_WRITEOUT_H */ +#endif /* HEADER_CURL_TOOL_WRITEOUT_H */ diff --git a/src/xattr.c b/src/tool_xattr.c index 61d6697bb..1f3883fa6 100644 --- a/src/xattr.c +++ b/src/tool_xattr.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -19,16 +19,19 @@ * KIND, either express or implied. * ***************************************************************************/ - -/* client-local setup.h */ #include "setup.h" + +#ifdef HAVE_FSETXATTR +# include <sys/xattr.h> /* header from libc, not from libattr */ +#endif + #include <curl/curl.h> -#include "xattr.h" + +#include "tool_xattr.h" + +#include "memdebug.h" /* keep this as LAST include */ #ifdef HAVE_FSETXATTR -#include <sys/types.h> -#include <string.h> -#include <sys/xattr.h> /* include header from libc, not from libattr */ /* mapping table of curl metadata to extended attribute names */ static const struct xattr_mapping { @@ -39,8 +42,8 @@ static const struct xattr_mapping { * http://freedesktop.org/wiki/CommonExtendedAttributes */ { "user.xdg.origin.url", CURLINFO_EFFECTIVE_URL }, - { "user.mime_type", CURLINFO_CONTENT_TYPE }, - { NULL, CURLINFO_NONE } /* last element, abort loop here */ + { "user.mime_type", CURLINFO_CONTENT_TYPE }, + { NULL, CURLINFO_NONE } /* last element, abort loop here */ }; /* store metadata from the curl request alongside the downloaded @@ -56,9 +59,9 @@ int fwrite_xattr(CURL *curl, int fd) CURLcode rc = curl_easy_getinfo(curl, mappings[i].info, &value); if(rc == CURLE_OK && value) { #ifdef HAVE_FSETXATTR_6 - err = fsetxattr( fd, mappings[i].attr, value, strlen(value), 0, 0 ); + err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0, 0); #elif defined(HAVE_FSETXATTR_5) - err = fsetxattr( fd, mappings[i].attr, value, strlen(value), 0 ); + err = fsetxattr(fd, mappings[i].attr, value, strlen(value), 0); #endif } i++; diff --git a/src/xattr.h b/src/tool_xattr.h index fea98f188..14c8c944b 100644 --- a/src/xattr.h +++ b/src/tool_xattr.h @@ -1,5 +1,5 @@ -#ifndef __XATTR_H -#define __XATTR_H +#ifndef HEADER_CURL_TOOL_XATTR_H +#define HEADER_CURL_TOOL_XATTR_H /*************************************************************************** * _ _ ____ _ * Project ___| | | | _ \| | @@ -7,7 +7,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -21,6 +21,8 @@ * KIND, either express or implied. * ***************************************************************************/ +#include "setup.h" + int fwrite_xattr(CURL *curl, int fd); -#endif +#endif /* HEADER_CURL_TOOL_XATTR_H */ diff --git a/src/vc6curlsrc.dsp b/src/vc6curlsrc.dsp index 1fb1d7bf9..4711703bc 100644 --- a/src/vc6curlsrc.dsp +++ b/src/vc6curlsrc.dsp @@ -139,83 +139,179 @@ LINK32=link.exe # PROP Default_Filter ""
# Begin Source File
-SOURCE=.\curlutil.c
+SOURCE=.\hugehelp.c
# End Source File
# Begin Source File
-SOURCE=.\getpass.c
+SOURCE=..\lib\nonblock.c
# End Source File
# Begin Source File
-SOURCE=.\homedir.c
+SOURCE=..\lib\rawstr.c
# End Source File
# Begin Source File
-SOURCE=.\hugehelp.c
+SOURCE=..\lib\strtoofft.c
# End Source File
# Begin Source File
-SOURCE=.\main.c
+SOURCE=.\tool_binmode.c
# End Source File
# Begin Source File
-SOURCE=.\os-specific.c
+SOURCE=.\tool_bname.c
# End Source File
# Begin Source File
-SOURCE=..\lib\nonblock.c
+SOURCE=.\tool_cb_dbg.c
# End Source File
# Begin Source File
-SOURCE=..\lib\rawstr.c
+SOURCE=.\tool_cb_hdr.c
# End Source File
# Begin Source File
-SOURCE=..\lib\strtoofft.c
+SOURCE=.\tool_cb_prg.c
# End Source File
# Begin Source File
-SOURCE=.\urlglob.c
+SOURCE=.\tool_cb_rea.c
# End Source File
# Begin Source File
-SOURCE=.\writeenv.c
+SOURCE=.\tool_cb_see.c
# End Source File
# Begin Source File
-SOURCE=.\writeout.c
+SOURCE=.\tool_cb_skt.c
# End Source File
# Begin Source File
-SOURCE=.\xattr.c
+SOURCE=.\tool_cb_wrt.c
# End Source File
-# End Group
-# Begin Group "Header Files"
+# Begin Source File
-# PROP Default_Filter ""
+SOURCE=.\tool_cfgable.c
+# End Source File
# Begin Source File
-SOURCE=".\config-win32.h"
+SOURCE=.\tool_convert.c
# End Source File
# Begin Source File
-SOURCE=.\curlutil.h
+SOURCE=.\tool_dirhie.c
# End Source File
# Begin Source File
-SOURCE=.\getpass.h
+SOURCE=.\tool_doswin.c
# End Source File
# Begin Source File
-SOURCE=.\homedir.h
+SOURCE=.\tool_easysrc.c
# End Source File
# Begin Source File
-SOURCE=.\hugehelp.h
+SOURCE=.\tool_formparse.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.c
# End Source File
# Begin Source File
-SOURCE=.\os-specific.h
+SOURCE=.\tool_panykey.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_vms.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeenv.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_writeout.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_xattr.c
+# End Source File
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=".\config-win32.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\hugehelp.h
# End Source File
# Begin Source File
@@ -235,23 +331,159 @@ SOURCE=..\lib\strtoofft.h # End Source File
# Begin Source File
-SOURCE=.\urlglob.h
+SOURCE=.\tool_binmode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_bname.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_dbg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_hdr.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_prg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_rea.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_see.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_skt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cb_wrt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_cfgable.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_convert.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_dirhie.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_doswin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_easysrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_formparse.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getparam.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_getpass.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_help.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_helpers.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_homedir.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_libinfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_main.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_mfiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_msgs.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operate.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_operhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_panykey.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_paramhlp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_parsecfg.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sdecls.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_setopt.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_sleep.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_urlglob.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_util.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\tool_version.h
# End Source File
# Begin Source File
-SOURCE=.\version.h
+SOURCE=.\tool_vms.h
# End Source File
# Begin Source File
-SOURCE=.\writeenv.h
+SOURCE=.\tool_writeenv.h
# End Source File
# Begin Source File
-SOURCE=.\writeout.h
+SOURCE=.\tool_writeout.h
# End Source File
# Begin Source File
-SOURCE=.\xattr.h
+SOURCE=.\tool_xattr.h
# End Source File
# End Group
# Begin Group "Resource Files"
diff --git a/tests/FILEFORMAT b/tests/FILEFORMAT index 74fecacdd..72af82325 100644 --- a/tests/FILEFORMAT +++ b/tests/FILEFORMAT @@ -158,7 +158,8 @@ rtsp-ipv6 imap pop3 smtp -http+tls-srp +httptls+srp +httptls+srp-ipv6 Give only one per line. This subsection is mandatory. </server> @@ -176,13 +177,14 @@ idn ipv6 large_file libz -netrc_debug NSS NTLM OpenSSL SSL socks unittest +debug +TLS-SRP as well as each protocol that curl supports. A protocol only needs to be specified if it is different from the server (useful when the server @@ -228,7 +230,8 @@ command is run. They are cleared again after the command has been run. Variables are first substituted as in the <command> section. </setenv> -<command [option="no-output"] [timeout="secs"] [delay="secs"] [type="perl"]> +<command [option="no-output/no-include"] [timeout="secs"] [delay="secs"] + [type="perl"]> command line to run, there's a bunch of %variables that get replaced accordingly. @@ -248,6 +251,9 @@ Set option="no-output" to prevent the test script to slap on the --output argument that directs the output to a file. The --output is also not added if the verify/stdout section is used. +Set option="no-include" to prevent the test script to slap on the --include +argument. + Set timeout="secs" to override default server logs advisor read lock timeout. This timeout is used by the test harness, once that the command has completed execution, to wait for the test server to write out server side log files and diff --git a/tests/README b/tests/README index 4d8e70c78..f0248e632 100644 --- a/tests/README +++ b/tests/README @@ -6,13 +6,44 @@ The cURL Test Suite -Requires: + 1. Running + 1.1 Requires to run + 1.2 Port numbers used by test servers + 1.3 Test servers + 1.4 Run + 1.5 Shell startup scripts + 1.6 Memory test + 1.7 Debug + 1.8 Logs + 1.9 Test input files + 1.10 Code coverage + 1.11 Remote testing + + 2. Numbering + 2.1 Test case numbering + + 3. Write tests + 3.1 test data + 3.2 curl tests + 3.3 libcurl tests + 3.4 unit tests + + 4. TODO + 4.1 More protocols + 4.2 SOCKS auth + +============================================================================== + +1. Running + + 1.1 Requires to run + perl (and a unix-style shell) diff (when a test fails, a diff is shown) stunnel (for HTTPS and FTPS tests) OpenSSH or SunSSH (for SCP, SFTP and SOCKS4/5 tests) -Ports used by default: + 1.2 Port numbers used by test servers - TCP/8990 for HTTP - TCP/8991 for HTTPS @@ -28,25 +59,36 @@ Ports used by default: - TCP/9001 for POP3 - TCP/9002 for IMAP - TCP/9003 for SMTP + - TCP/9004 for SMTP IPv6 + - TCP/9005 for RTSP + - TCP/9006 for RTSP IPv6 + - TCP/9007 for GOPHER + - TCP/9008 for GOPHER IPv6 + - TCP/9008 for HTTPS server with TLS-SRP support + + 1.3 Test servers The test suite runs simple FTP, POP3, IMAP, SMTP, HTTP and TFTP stand-alone - servers on these ports to which it makes requests. For SSL tests, it runs - stunnel to handle encryption to the regular servers. For SSH, it runs a - standard OpenSSH server. For SOCKS4/5 tests SSH is used to perform the SOCKS - functionality and requires a SSH client and server. + servers on the ports listed above to which it makes requests. For SSL tests, + it runs stunnel to handle encryption to the regular servers. For SSH, it + runs a standard OpenSSH server. For SOCKS4/5 tests SSH is used to perform + the SOCKS functionality and requires a SSH client and server. - The base port number shown above can be changed using runtests' -b option - to allow running more than one instance of the test suite simultaneously - on one machine. + The base port number (8990), which all the individual port numbers are + indexed from, can be set explicitly using runtests.pl' -b option to allow + running more than one instance of the test suite simultaneously on one + machine, or just move the servers in case you have local services on any of + those ports. + + 1.4 Run -Run: 'make test'. This builds the test suite support code and invokes the 'runtests.pl' perl script to run all the tests. Edit the top variables of that script in case you have some specific needs, or run the script manually (after the support code has been built). The script breaks on the first test that doesn't do OK. Use -a to prevent - the script from abort on the first error. Run the script with -v for more + the script from aborting on the first error. Run the script with -v for more verbose output. Use -d to run the test servers with debug output enabled as well. Specifying -k keeps all the log files generated by the test intact. @@ -56,7 +98,8 @@ Run: 3 to 9. Any test numbers starting with ! are disabled, as are any test numbers found in the file data/DISABLED (one per line). -Shell startup scripts: + 1.5 Shell startup scripts + Tests which use the ssh test server, SCP/SFTP/SOCKS tests, might be badly influenced by the output of system wide or user specific shell startup scripts, .bashrc, .profile, /etc/csh.cshrc, .login, /etc/bashrc, etc. which @@ -71,44 +114,45 @@ Shell startup scripts: output of a shell startup script. Locate, cleanup or adjust the shell script. -Memory: + 1.6 Memory test + The test script will check that all allocated memory is freed properly IF curl has been built with the CURLDEBUG define set. The script will - automatically detect if that is the case, and it will use the ../memanalyze - script to analyze the memory debugging output. + automatically detect if that is the case, and it will use the + 'memanalyze.pl' script to analyze the memory debugging output. + + Also, if you run tests on a machine where valgrind is found, the script will + use valgrind to run the test with (unless you use -n) to further verify + correctness. - The -t option will enable torture testing mode, which runs each test - many times but causes a different memory allocation to fail on each - successive run. This tests the out of memory error handling code to - ensure that memory leaks do not occur even in those situations. + runtests.pl's -t option will enable torture testing mode, which runs each + test many times and makes each different memory allocation fail on each + successive run. This tests the out of memory error handling code to ensure + that memory leaks do not occur even in those situations. + + 1.7 Debug -Debug: If a test case fails, you can conveniently get the script to invoke the debugger (gdb) for you with the server running and the exact same command line parameters that failed. Just invoke 'runtests.pl <test number> -g' and then just type 'run' in the debugger to perform the command through the debugger. - If a test case causes a core dump, analyze it by running gdb like: - - # gdb ../curl/src core + 1.8 Logs - ... and get a stack trace with the gdb command: + All logs are generated in the logs/ subdirectory (it is emptied first in the + runtests.pl script). Use runtests.pl -k to force it to keep the temporary + files after the test run since successful runs will clean it up otherwise. - (gdb) where + 1.9 Test input files -Logs: - All logs are generated in the logs/ subdirectory (it is emptied first - in the runtests.pl script). Use runtests.pl -k to keep the temporary files - after the test run. - -Data: All test cases are put in the data/ subdirectory. Each test is stored in the file named according to the test number. See FILEFORMAT for the description of the test case files. -Code coverage: + 1.10 Code coverage + gcc provides a tool that can determine the code coverage figures for the test suite. To use it, configure curl with CFLAGS='-fprofile-arcs -ftest-coverage -g -O0'. Make sure you run the normal @@ -125,38 +169,83 @@ Code coverage: The text mode tool gcov may also be used, but it doesn't handle object files in more than one directory very well. -Remote testing: + 1.11 Remote testing + The runtests.pl script provides some hooks to allow curl to be tested on a machine where perl can not be run. The test framework in this case runs on a workstation where perl is available, while curl itself is run on a remote system using ssh or some other remote execution method. See the comments at the beginning of runtests.pl for details. -TEST CASE NUMBERS - - So far, we've used this system: - - 1 - 99 HTTP - 100 - 199 FTP* - 200 - 299 FILE* - 300 - 399 HTTPS - 400 - 499 FTPS - 500 - 599 libcurl source code tests, not using the curl command tool - 600 - 699 SCP/SFTP - 700 - 799 SOCKS4 (even numbers) and SOCK5 (odd numbers) - 800 - 899 POP3, IMAP, SMTP - 1000 - 1299 miscellaneous* - 1300 - 1399 unit tests* - 1400 - 1999 miscellaneous* - 2000 - x multiple sequential protocols per test case* - - Since 30-apr-2003, there's nothing in the system that requires us to keep - within these number series, and those sections marked with * actually - contain tests for a variety of protocols. Each test case now specifies - its own server requirements, independent of test number. - -TODO: - - * Add tests for TELNET, LDAP, DICT... - * SOCKS4/5 test deficiencies - no proxy authentication tests as SSH (the - test mechanism) doesn't support them +2. Numbering + + 2.1 Test case numbering + + 1 - 99 HTTP + 100 - 199 FTP* + 200 - 299 FILE* + 300 - 399 HTTPS + 400 - 499 FTPS + 500 - 599 libcurl source code tests, not using the curl command tool + 600 - 699 SCP/SFTP + 700 - 799 SOCKS4 (even numbers) and SOCK5 (odd numbers) + 800 - 899 POP3, IMAP, SMTP + 1000 - 1299 miscellaneous* + 1300 - 1399 unit tests* + 1400 - 1999 miscellaneous* + 2000 - x multiple sequential protocols per test case* + + Since 30-apr-2003, there's nothing in the system that requires us to keep + within these number series, and those sections marked with * actually + contain tests for a variety of protocols. Each test case now specifies its + own server requirements, independent of test number. + +3. Write tests + + Here's a quick description on writing test cases. We basically have three + kinds of tests: the ones that test the curl tool, the ones that build small + applications and test libcurl directly and the unit tests that test + individual (possibly internal) functions. + + 3.1 test data + + Each test has a master file that controls all the test data. What to read, + what the protocol exchange should look like, what exit code to expect and + what command line arguments to use etc. + + These files are tests/data/test[num] where [num] is described in section 2 + of this document, and the XML-like file format of them is described in the + separate tests/FILEFORMAT document. + + 3.2 curl tests + + A test case that runs the curl tool and verifies that it gets the correct + data, it sends the correct data, it uses the correct protocol primitives + etc. + + 3.3 libcurl tests + + The libcurl tests are identical to the curl ones, except that they use a + specific and dedicated custom-built program to run instead of "curl". This + tool is built from source code placed in tests/libtest and if you want to + make a new libcurl test that is where you add your code. + + 3.4 unit tests + + Unit tests are tests in the 13xx sequence and they are placed in tests/unit. + There's a tests/unit/README describing the specific set of checks and macros + that may be used when writing tests that verify behaviors of specific + individual functions. + + The unit tests depend on curl being built with debug enabled. + +4. TODO + + 4.1 More protocols + + Add tests for TELNET, LDAP, DICT... + + 4.2 SOCKS auth + + SOCKS4/5 test deficiencies - no proxy authentication tests as SSH (the + test mechanism) doesn't support them diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 363c40628..8471736ca 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -53,9 +53,11 @@ test605 test606 test607 test608 test609 test610 test611 test612 test613 \ test614 test615 test616 test617 test618 test619 test620 test621 test622 \ test623 test624 test625 test626 test627 test628 test629 test630 test631 \ test632 test633 test634 test635 test636 test637 test700 test701 test702 \ -test703 test704 test705 test706 test707 test708 test800 test801 test802 \ +test703 test704 test705 test706 test707 test708 test709 test710 \ +test800 test801 test802 \ test803 test804 test805 test806 test807 test808 test809 test810 test811 \ -test812 test813 test1000 test1001 test1002 test1003 test1004 test1005 \ +test812 test813 test814 \ +test1000 test1001 test1002 test1003 test1004 test1005 \ test1006 test1007 test1008 test1009 test1010 test1011 test1012 test1013 \ test1014 test1015 test1016 test1017 test1018 test1019 test1020 test1021 \ test1022 test1023 test1024 test1025 test1026 test1027 test1028 test1029 \ @@ -71,9 +73,12 @@ test1094 test1095 test1096 test1097 test1098 test1099 test1100 test1101 \ test1102 test1103 test1104 test1105 test1106 test1107 test1108 test1109 \ test1110 test1111 test1112 test1113 test1114 test1115 test1116 test1117 \ test1118 test1119 test1120 test1121 test1122 test1123 test1124 test1125 \ -test1126 test1127 test1128 test1200 test1201 test1202 test1203 test1300 \ -test1301 test1302 test1303 test1304 test1305 test1306 test1307 test1308 \ -test1309 test2000 test2001 test2002 test2003 test2004 +test1126 test1127 test1128 test1129 test1130 test1131 \ +test1200 test1201 test1202 test1203 test1204 \ +test1300 test1301 test1302 test1303 test1304 test1305 \ +test1306 test1307 test1308 test1309 test1310 test1311 test1312 test1313 \ +test1314 \ +test2000 test2001 test2002 test2003 test2004 EXTRA_DIST = $(TESTCASES) DISABLED diff --git a/tests/data/test1129 b/tests/data/test1129 new file mode 100644 index 000000000..f47141cd3 --- /dev/null +++ b/tests/data/test1129 @@ -0,0 +1,97 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP POST +Expect: 100-continue +</keywords> +</info> + +# +# Server-side +<reply> +<data nocheck="yes"> +HTTP/1.1 404 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</data> + +<data1> +HTTP/1.1 404 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</data1> + +# we use skip to make the test server never read the full payload off +# the socket and instead return the response at once +<servercmd> +skip: 1025 +</servercmd> +</reply> + +# +# Client-side +<client> +# 1025 x 'x' +<file name="log/file1129"> +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +</file> +<server> +http +</server> + <name> +HTTP POST expect 100-continue with a 404 + </name> + <command option="no-output"> +-d @log/file1129 http://%HOSTIP:%HTTPPORT/1129 http://%HOSTIP:%HTTPPORT/11290001 +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<stdout> +HTTP/1.1 404 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +HTTP/1.1 404 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</stdout> +<strip> +^User-Agent:.* +</strip> +<protocol> +POST /1129 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 1025
+Content-Type: application/x-www-form-urlencoded
+Expect: 100-continue
+
+POST /11290001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 1025
+Content-Type: application/x-www-form-urlencoded
+Expect: 100-continue
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test1130 b/tests/data/test1130 new file mode 100644 index 000000000..eb1e59f5b --- /dev/null +++ b/tests/data/test1130 @@ -0,0 +1,97 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP POST +Expect: 100-continue +</keywords> +</info> + +# +# Server-side +<reply> +<data nocheck="yes"> +HTTP/1.1 404 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</data> + +<data1> +HTTP/1.1 404 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</data1> + +# we use skip to make the test server never read the full payload off +# the socket and instead return the response at once +<servercmd> +skip: 100 +</servercmd> +</reply> + +# +# Client-side +<client> +# 100 x 'x' +<file name="log/file1130"> +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +</file> +<server> +http +</server> + <name> +HTTP POST forced expect 100-continue with a 404 + </name> + <command option="no-output"> +-d @log/file1130 http://%HOSTIP:%HTTPPORT/1130 http://%HOSTIP:%HTTPPORT/11300001 -H "Expect: 100-continue" +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<stdout> +HTTP/1.1 404 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +HTTP/1.1 404 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Content-Type: text/html + +-foo- +</stdout> +<strip> +^User-Agent:.* +</strip> +<protocol> +POST /1130 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Expect: 100-continue
+Content-Length: 100
+Content-Type: application/x-www-form-urlencoded
+
+POST /11300001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Expect: 100-continue
+Content-Length: 100
+Content-Type: application/x-www-form-urlencoded
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test1131 b/tests/data/test1131 new file mode 100644 index 000000000..96843af54 --- /dev/null +++ b/tests/data/test1131 @@ -0,0 +1,95 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP PUT +Expect: 100-continue +</keywords> +</info> + +# +# Server-side +<reply> +<data nocheck="yes"> +HTTP/1.1 400 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 9 +Content-Type: text/html + +FAILURE1 +</data> + +<data1> +HTTP/1.1 400 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 9 +Content-Type: text/html + +FAILURE2 +</data1> + +# we use skip to make the test server never read the full payload off +# the socket and instead return the response at once +<servercmd> +skip: 100 +</servercmd> +</reply> + +# +# Client-side +<client> +# 100 x 'x' +<file name="log/file1131"> +XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX +</file> +<server> +http +</server> + <name> +HTTP PUT expect 100-continue with a 400 + </name> + <command option="no-output"> +-T log/file1131 http://%HOSTIP:%HTTPPORT/1131 -T log/file1131 http://%HOSTIP:%HTTPPORT/11310001 +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<stdout> +HTTP/1.1 400 NOOOOOOOOO +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 9 +Content-Type: text/html + +FAILURE1 +HTTP/1.1 400 NEITHER +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 9 +Content-Type: text/html + +FAILURE2 +</stdout> +<strip> +^User-Agent:.* +</strip> +<protocol> +PUT /1131 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 100
+Expect: 100-continue
+
+PUT /11310001 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 100
+Expect: 100-continue
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test1204 b/tests/data/test1204 new file mode 100644 index 000000000..02502fb8e --- /dev/null +++ b/tests/data/test1204 @@ -0,0 +1,79 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +HTTP Basic auth +--anyauth +</keywords> +</info> +# Server-side +<reply> +<data> +HTTP/1.1 401 Authorization Required swsbounce
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2
+WWW-Authenticate: X-MobileMe-AuthToken realm="Newcastle", Basic realm="fun fun fun"
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 26
+
+This is not the real page +</data> + +# This is supposed to be returned when the server gets the second request +<data1> +HTTP/1.1 200 OK
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 23
+
+This IS the real page! +</data1> + +<datacheck> +HTTP/1.1 401 Authorization Required swsbounce
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2
+WWW-Authenticate: X-MobileMe-AuthToken realm="Newcastle", Basic realm="fun fun fun"
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 26
+
+HTTP/1.1 200 OK
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2
+Content-Type: text/html; charset=iso-8859-1
+Content-Length: 23
+
+This IS the real page! +</datacheck> + +</reply> + +# Client-side +<client> +<server> +http +</server> + <name> +HTTP with WWW-Authenticate and multiple auths in a single line + </name> + <command> +http://%HOSTIP:%HTTPPORT/1204 -u testuser:testpass --anyauth +</command> +</client> + +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /1204 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+GET /1204 HTTP/1.1
+Authorization: Basic dGVzdHVzZXI6dGVzdHBhc3M=
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test130 b/tests/data/test130 index fbcf5251b..dcc46fc8f 100644 --- a/tests/data/test130 +++ b/tests/data/test130 @@ -37,9 +37,9 @@ ftp FTP (optional .netrc; no user/pass) dir list PASV </name> <command> ---netrc-optional --netrc-file log/netrc ftp://%HOSTIP:%FTPPORT/ +--netrc-optional --netrc-file log/netrc130 ftp://%HOSTIP:%FTPPORT/ </command> -<file name="log/netrc" > +<file name="log/netrc130" > # the following two lines were created while testing curl machine %HOSTIP login user1 password passwd1 machine %HOSTIP login user2 password passwd2 diff --git a/tests/data/test1304 b/tests/data/test1304 index f438a6929..d518de9e4 100644 --- a/tests/data/test1304 +++ b/tests/data/test1304 @@ -21,7 +21,7 @@ netrc parsing unit tests <tool> unit1304 </tool> -<file name="log/netrc"> +<file name="log/netrc1304"> machine example.com login admin password passwd machine curl.example.com login none password none </file> diff --git a/tests/data/test131 b/tests/data/test131 index ad7f9e22a..86501c627 100644 --- a/tests/data/test131 +++ b/tests/data/test131 @@ -38,9 +38,9 @@ ftp FTP (optional .netrc; user/no pass) dir list PASV </name> <command> ---netrc-optional --netrc-file log/netrc ftp://user2@%HOSTIP:%FTPPORT/ +--netrc-optional --netrc-file log/netrc131 ftp://user2@%HOSTIP:%FTPPORT/ </command> -<file name="log/netrc" > +<file name="log/netrc131" > # the following two lines were created while testing curl machine %HOSTIP login user1 password passwd1 machine %HOSTIP login user2 password passwd2 diff --git a/tests/data/test1310 b/tests/data/test1310 new file mode 100644 index 000000000..840f3c5fa --- /dev/null +++ b/tests/data/test1310 @@ -0,0 +1,125 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +HTTP NTLM auth +</keywords> +</info> +# Server-side +<reply> + +<!-- no <data> in this test since we have NTLM from the start + +This is supposed to be returned when the server gets a first +Authorization: NTLM line passed-in from the client --> + +<data1001> +HTTP/1.1 401 Now gimme that second request of crap +Server: Microsoft-IIS/5.0 +Content-Type: text/html; charset=iso-8859-1 +Content-Length: 34 +WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== + +This is not the real page either! +</data1001> + +# This is supposed to be returned when the server gets the second +# Authorization: NTLM line passed-in from the client +<data1002> +HTTP/1.1 200 Things are fine in server land swsclose +Server: Microsoft-IIS/5.0 +Content-Type: text/html; charset=iso-8859-1 +Content-Length: 32 + +Finally, this is the real page! +</data1002> + +<datacheck> +HTTP/1.1 401 Now gimme that second request of crap +Server: Microsoft-IIS/5.0 +Content-Type: text/html; charset=iso-8859-1 +Content-Length: 34 +WWW-Authenticate: NTLM TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== + +HTTP/1.1 200 Things are fine in server land swsclose +Server: Microsoft-IIS/5.0 +Content-Type: text/html; charset=iso-8859-1 +Content-Length: 32 + +Finally, this is the real page! +</datacheck> + +</reply> + +# Client-side +<client> +<features> +NTLM_WB +debug +</features> +<server> +http +</server> + <name> +HTTP with NTLM delegation to winbind helper + </name> + <setenv> +# we force our own host name, in order to make the test machine independent +CURL_GETHOSTNAME=curlhost +# we try to use the LD_PRELOAD hack, if not a debug build +LD_PRELOAD=%PWD/libtest/.libs/libhostname.so +# set path to fake_auth instead of real ntlm_auth to generate NTLM type1 and type 3 messages +CURL_NTLM_WB_FILE=%PWD/server/fake_ntlm +# set source directory so fake_ntlm can find the test files +CURL_NTLM_AUTH_SRCDIR=%SRCDIR +# set the test number +CURL_NTLM_AUTH_TESTNUM=1310 + </setenv> + <command> +http://%HOSTIP:%HTTPPORT/1310 -u testuser:anypasswd --ntlm-wb +</command> +<precheck> +chkhostname curlhost +</precheck> +</client> + +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /1310 HTTP/1.1
+Authorization: NTLM TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA
+User-Agent: curl/7.10.6-pre1 (i686-pc-linux-gnu) libcurl/7.10.6-pre1 OpenSSL/0.9.7a ipv6 zlib/1.1.3
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+GET /1310 HTTP/1.1
+Authorization: NTLM TlRMTVNTUAADAAAAGAAYAE8AAAAYABgAZwAAAAAAAABAAAAACAAIAEAAAAAHAAcASAAAAAAAAAAAAAAAggEAAHRlc3R1c2VyVU5LTk9XTlpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOQ==
+User-Agent: curl/7.10.6-pre1 (i686-pc-linux-gnu) libcurl/7.10.6-pre1 OpenSSL/0.9.7a ipv6 zlib/1.1.3
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +</verify> +# Input and output (type 1 message) for fake_ntlm +<ntlm_auth_type1> +<input> +YR +</input> +<output> +YR TlRMTVNTUAABAAAABoIIAAAAAAAAAAAAAAAAAAAAAAAAAAAAMAAAAAAAAAAwAAAA +</output> +</ntlm_auth_type1> +# Input and output (type 3 message) for fake_ntlm +<ntlm_auth_type3> +<input> +TT TlRMTVNTUAACAAAAAgACADAAAAAGgoEAc51AYVDgyNcAAAAAAAAAAG4AbgAyAAAAQ0MCAAQAQwBDAAEAEgBFAEwASQBTAEEAQgBFAFQASAAEABgAYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAwAsAGUAbABpAHMAYQBiAGUAdABoAC4AYwBjAC4AaQBjAGUAZABlAHYALgBuAHUAAAAAAA== +</input> +<output> +KK TlRMTVNTUAADAAAAGAAYAE8AAAAYABgAZwAAAAAAAABAAAAACAAIAEAAAAAHAAcASAAAAAAAAAAAAAAAggEAAHRlc3R1c2VyVU5LTk9XTlpkQwKRCZFMhjj0tw47wEjKHRHlvzfxQamFcheMuv8v+xeqphEO5V41xRd7R9deOQ== +</output> +</ntlm_auth_type3> +</testcase> diff --git a/tests/data/test1311 b/tests/data/test1311 new file mode 100644 index 000000000..e47647c38 --- /dev/null +++ b/tests/data/test1311 @@ -0,0 +1,64 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +-J +</keywords> +</info> + +# +<reply> +<data nocheck="yes"> +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Connection: close +Content-Type: text/html +Content-Disposition: filename=name1311; charset=funny; option=strange + +12345 +</data> +</reply> + +# +# Client-side +<client> +# this relies on the debug feature to allow us to set directory to store the +# -J output in +<features> +debug +</features> +<server> +http +</server> +<name> +HTTP GET with -J and Content-Disposition +</name> +<setenv> +CURL_TESTDIR=%PWD/log +</setenv> +<command option="no-output,no-include"> +http://%HOSTIP:%HTTPPORT/1311 -J -O +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /1311 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +<file name="log/name1311"> +12345 +</file> + +</verify> +</testcase> diff --git a/tests/data/test1312 b/tests/data/test1312 new file mode 100644 index 000000000..92144015a --- /dev/null +++ b/tests/data/test1312 @@ -0,0 +1,64 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +-J +</keywords> +</info> + +# +<reply> +<data nocheck="yes"> +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Connection: close +Content-Type: text/html +Content-Disposition: inline; filename="name1312;weird" + +12345 +</data> +</reply> + +# +# Client-side +<client> +# this relies on the debug feature to allow us to set directory to store the +# -J output in +<features> +debug +</features> +<server> +http +</server> +<name> +HTTP GET with -J, Content-Disposition and ; in filename +</name> +<setenv> +CURL_TESTDIR=%PWD/log +</setenv> +<command option="no-output,no-include"> +http://%HOSTIP:%HTTPPORT/1312 -J -O +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /1312 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +<file name="log/name1312;weird"> +12345 +</file> + +</verify> +</testcase> diff --git a/tests/data/test1313 b/tests/data/test1313 new file mode 100644 index 000000000..2331ae9ee --- /dev/null +++ b/tests/data/test1313 @@ -0,0 +1,64 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +-J +</keywords> +</info> + +# +<reply> +<data nocheck="yes"> +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Content-Length: 6 +Connection: close +Content-Type: text/html +Content-Disposition: inline; filename='name1313 + +12345 +</data> +</reply> + +# +# Client-side +<client> +# this relies on the debug feature to allow us to set directory to store the +# -J output in +<features> +debug +</features> +<server> +http +</server> +<name> +HTTP GET with -J, Content-Disposition, uneven quotes +</name> +<setenv> +CURL_TESTDIR=%PWD/log +</setenv> +<command option="no-output,no-include"> +http://%HOSTIP:%HTTPPORT/1313 -J -O +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /1313 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +<file name="log/name1313"> +12345 +</file> + +</verify> +</testcase> diff --git a/tests/data/test1314 b/tests/data/test1314 new file mode 100644 index 000000000..078ada64a --- /dev/null +++ b/tests/data/test1314 @@ -0,0 +1,79 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +HTTP proxy +followlocation +</keywords> +</info> + +# Server-side +<reply> +<data> +HTTP/1.1 301 This is a weirdo text message swsbounce +Server: test-server/fake +Location: //somewhere.example.com/reply/1314 +Content-Length: 32 +Connection: close + +Redirect to the same URL again! +</data> + +<data1> +HTTP/1.1 200 okidoki +Server: test-server/fake +Content-Length: 4 +Connection: close + +moo +</data1> + +<datacheck> +HTTP/1.1 301 This is a weirdo text message swsbounce +Server: test-server/fake +Location: //somewhere.example.com/reply/1314 +Content-Length: 32 +Connection: close + +HTTP/1.1 200 okidoki +Server: test-server/fake +Content-Length: 4 +Connection: close + +moo +</datacheck> +</reply> + +# Client-side +<client> +<server> +http +</server> + <name> +HTTP Location: following a // prefixed url + </name> + <command> +http://firstplace.example.com/want/1314 -L -x http://%HOSTIP:%HTTPPORT +</command> +</client> + +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent: curl/.* +</strip> +<protocol> +GET http://firstplace.example.com/want/1314 HTTP/1.1
+Host: firstplace.example.com
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+GET http://somewhere.example.com/reply/1314 HTTP/1.1
+Host: somewhere.example.com
+Accept: */*
+Proxy-Connection: Keep-Alive
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test132 b/tests/data/test132 index 8d9e3ed60..ed96953bb 100644 --- a/tests/data/test132 +++ b/tests/data/test132 @@ -37,9 +37,9 @@ ftp FTP (optional .netrc; user/passwd supplied) dir list PASV </name> <command> ---netrc-optional --netrc-file log/netrc ftp://mary:mark@%HOSTIP:%FTPPORT/ +--netrc-optional --netrc-file log/netrc132 ftp://mary:mark@%HOSTIP:%FTPPORT/ </command> -<file name="log/netrc" > +<file name="log/netrc132" > # the following two lines were created while testing curl machine %HOSTIP login user1 password passwd1 machine %HOSTIP login user2 password passwd2 diff --git a/tests/data/test133 b/tests/data/test133 index a15cfc371..085092d01 100644 --- a/tests/data/test133 +++ b/tests/data/test133 @@ -37,9 +37,9 @@ ftp FTP (compulsory .netrc; ignored user/passwd) dir list PASV </name> <command> --n --netrc-file log/netrc ftp://mary:mark@%HOSTIP:%FTPPORT/ +-n --netrc-file log/netrc133 ftp://mary:mark@%HOSTIP:%FTPPORT/ </command> -<file name="log/netrc" > +<file name="log/netrc133" > # the following two lines were created while testing curl machine %HOSTIP login user1 password passwd1 machine %HOSTIP login user2 password passwd2 diff --git a/tests/data/test134 b/tests/data/test134 index 83035849e..8a3ba6204 100644 --- a/tests/data/test134 +++ b/tests/data/test134 @@ -37,9 +37,9 @@ ftp FTP (optional .netrc; programmatic user/passwd) dir list PASV </name> <command> ---netrc-optional --netrc-file log/netrc -u romulus:rhemus ftp://mary:mark@%HOSTIP:%FTPPORT/ +--netrc-optional --netrc-file log/netrc134 -u romulus:rhemus ftp://mary:mark@%HOSTIP:%FTPPORT/ </command> -<file name="log/netrc" > +<file name="log/netrc134" > # the following two lines were created while testing curl machine %HOSTIP login user1 password passwd1 machine %HOSTIP login user2 password passwd2 diff --git a/tests/data/test257 b/tests/data/test257 index cc3b7f00a..45642d571 100644 --- a/tests/data/test257 +++ b/tests/data/test257 @@ -71,11 +71,11 @@ http HTTP Location: following with --netrc-optional </name> <command> -http://supersite.com/want/257 -L -x http://%HOSTIP:%HTTPPORT --netrc-optional --netrc-file log/netrc +http://supersite.com/want/257 -L -x http://%HOSTIP:%HTTPPORT --netrc-optional --netrc-file log/netrc257 </command> # netrc auth for two out of three sites: -<file name="log/netrc"> +<file name="log/netrc257"> machine supersite.com login user1 password passwd1 machine anotherone.com login user2 password passwd2 </file> diff --git a/tests/data/test31 b/tests/data/test31 index d06bc1180..5afe81df6 100644 --- a/tests/data/test31 +++ b/tests/data/test31 @@ -18,6 +18,28 @@ Content-Type: text/html Funny-head: yesyes
Set-Cookie: foobar=name; domain=anything.com; path=/ ; secure
Set-Cookie:ismatch=this ; domain=127.0.0.1; path=/silly/
+Set-Cookie: sec1value=secure1 ; domain=127.0.0.1; path=/secure1/ ; secure
+Set-Cookie: sec2value=secure2 ; domain=127.0.0.1; path=/secure2/ ; secure=
+Set-Cookie: sec3value=secure3 ; domain=127.0.0.1; path=/secure3/ ; secure=
+Set-Cookie: sec4value=secure4 ; secure=; domain=127.0.0.1; path=/secure4/ ; +Set-Cookie: sec5value=secure5 ; secure; domain=127.0.0.1; path=/secure5/ ; +Set-Cookie: sec6value=secure6 ; secure ; domain=127.0.0.1; path=/secure6/ ; +Set-Cookie: sec7value=secure7 ; secure ; domain=127.0.0.1; path=/secure7/ ; +Set-Cookie: sec8value=secure8 ; secure= ; domain=127.0.0.1; path=/secure8/ ; +Set-Cookie: secure=very1 ; secure=; domain=127.0.0.1; path=/secure9/; +Set-Cookie: httpo1=value1 ; domain=127.0.0.1; path=/p1/; httponly +Set-Cookie: httpo2=value2 ; domain=127.0.0.1; path=/p2/; httponly= +Set-Cookie: httpo3=value3 ; httponly; domain=127.0.0.1; path=/p3/; +Set-Cookie: httpo4=value4 ; httponly=; domain=127.0.0.1; path=/p4/; +Set-Cookie: httponly=myvalue1 ; domain=127.0.0.1; path=/p4/; httponly +Set-Cookie: httpandsec=myvalue2 ; domain=127.0.0.1; path=/p4/; httponly; secure +Set-Cookie: httpandsec2=myvalue3; domain=127.0.0.1; path=/p4/; httponly=; secure +Set-Cookie: httpandsec3=myvalue4 ; domain=127.0.0.1; path=/p4/; httponly; secure= +Set-Cookie: httpandsec4=myvalue5 ; domain=127.0.0.1; path=/p4/; httponly=; secure= +Set-Cookie: httpandsec5=myvalue6 ; domain=127.0.0.1; path=/p4/; secure; httponly= +Set-Cookie: httpandsec6=myvalue7 ; domain=127.0.0.1; path=/p4/; secure=; httponly= +Set-Cookie: httpandsec7=myvalue8 ; domain=127.0.0.1; path=/p4/; secure; httponly +Set-Cookie: httpandsec8=myvalue9; domain=127.0.0.1; path=/p4/; secure=; httponly
Set-Cookie: partmatch=present; domain=127.0.0.1 ; path=/;
Set-Cookie:eat=this; domain=moo.foo.moo;
Set-Cookie: eat=this-too; domain=.foo.moo;
@@ -69,6 +91,28 @@ Accept: */* # This file was generated by libcurl! Edit at your own risk. .127.0.0.1 TRUE /silly/ FALSE 0 ismatch this +.127.0.0.1 TRUE /secure1/ TRUE 0 sec1value secure1 +.127.0.0.1 TRUE /secure2/ TRUE 0 sec2value secure2 +.127.0.0.1 TRUE /secure3/ TRUE 0 sec3value secure3 +.127.0.0.1 TRUE /secure4/ TRUE 0 sec4value secure4 +.127.0.0.1 TRUE /secure5/ TRUE 0 sec5value secure5 +.127.0.0.1 TRUE /secure6/ TRUE 0 sec6value secure6 +.127.0.0.1 TRUE /secure7/ TRUE 0 sec7value secure7 +.127.0.0.1 TRUE /secure8/ TRUE 0 sec8value secure8 +.127.0.0.1 TRUE /secure9/ TRUE 0 secure very1 +#HttpOnly_.127.0.0.1 TRUE /p1/ FALSE 0 httpo1 value1 +#HttpOnly_.127.0.0.1 TRUE /p2/ FALSE 0 httpo2 value2 +#HttpOnly_.127.0.0.1 TRUE /p3/ FALSE 0 httpo3 value3 +#HttpOnly_.127.0.0.1 TRUE /p4/ FALSE 0 httpo4 value4 +#HttpOnly_.127.0.0.1 TRUE /p4/ FALSE 0 httponly myvalue1 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec myvalue2 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec2 myvalue3 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec3 myvalue4 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec4 myvalue5 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec5 myvalue6 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec6 myvalue7 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec7 myvalue8 +#HttpOnly_.127.0.0.1 TRUE /p4/ TRUE 0 httpandsec8 myvalue9 .127.0.0.1 TRUE / FALSE 0 partmatch present 127.0.0.1 FALSE /we/want/ FALSE 2054030187 nodomain value #HttpOnly_127.0.0.1 FALSE /silly/ FALSE 0 magic yessir diff --git a/tests/data/test320 b/tests/data/test320 index bfef00cb2..899bec597 100644 --- a/tests/data/test320 +++ b/tests/data/test320 @@ -41,7 +41,7 @@ Accept: */* # Client-side <client> <server> -http+tls-srp +httptls+srp </server> <features> TLS-SRP diff --git a/tests/data/test321 b/tests/data/test321 index 84c19bc85..ccdfb86d0 100644 --- a/tests/data/test321 +++ b/tests/data/test321 @@ -10,7 +10,7 @@ FAILURE # Client-side <client> <server> -http+tls-srp +httptls+srp </server> <features> TLS-SRP diff --git a/tests/data/test322 b/tests/data/test322 index f44deb54b..f35345ead 100644 --- a/tests/data/test322 +++ b/tests/data/test322 @@ -10,7 +10,7 @@ FAILURE # Client-side <client> <server> -http+tls-srp +httptls+srp </server> <features> TLS-SRP diff --git a/tests/data/test324 b/tests/data/test324 index df150ab3c..bc1c48fea 100644 --- a/tests/data/test324 +++ b/tests/data/test324 @@ -10,7 +10,7 @@ FAILURE # Client-side <client> <server> -http+tls-srp +httptls+srp </server> <features> TLS-SRP diff --git a/tests/data/test4 b/tests/data/test4 index ce6bfc8f0..df69d3274 100644 --- a/tests/data/test4 +++ b/tests/data/test4 @@ -30,7 +30,7 @@ http Replaced internal and added custom HTTP headers </name> <command> - -H "extra-header: here" -H "Accept: replaced" http://%HOSTIP:%HTTPPORT/4 + -H "extra-header: here" -H "Accept: replaced" -H "X-Custom-Header;" -H "X-Test: foo; " -H "X-Test:" -H "X-Test2: foo;" -H "X-Test3: " -H "X-Test4; " -H "X-Test5;ignored" http://%HOSTIP:%HTTPPORT/4 </command> </client> @@ -45,6 +45,9 @@ GET /4 HTTP/1.1 Host: %HOSTIP:%HTTPPORT
extra-header: here
Accept: replaced
+X-Custom-Header:
+X-Test: foo;
+X-Test2: foo;
</protocol> </verify> diff --git a/tests/data/test504 b/tests/data/test504 index 573ab51c7..2d3a3dd0d 100644 --- a/tests/data/test504 +++ b/tests/data/test504 @@ -35,9 +35,10 @@ http://%HOSTIP:%HTTPSPORT/504 %HOSTIP:55555 </client> # Verify data after the test has been "shot" +# TEST_ERR_SUCCESS is errorcode 120 <verify> <errorcode> -100 +120 </errorcode> </verify> </testcase> diff --git a/tests/data/test538 b/tests/data/test538 index f33b2a654..d2fecd353 100644 --- a/tests/data/test538 +++ b/tests/data/test538 @@ -32,11 +32,10 @@ ftp://%HOSTIP:%FTPPORT/538 </client> # Verify data after the test has been "shot" +# TEST_ERR_SUCCESS is errorcode 120 <verify> -# ok, the error code here is supposed to be 100 for the fine case since -# that's just how lib504.c is written <errorcode> -100 +120 </errorcode> <protocol> USER anonymous
diff --git a/tests/data/test554 b/tests/data/test554 index 7fdc353fc..9d9bbcca7 100644 --- a/tests/data/test554 +++ b/tests/data/test554 @@ -45,7 +45,7 @@ s/boundary=----------------------------[a-z0-9]*/boundary=---------------------- POST /554 HTTP/1.1
Host: %HOSTIP:%HTTPPORT
Accept: */*
-Content-Length: 561
+Content-Length: 732
Expect: 100-continue
Content-Type: multipart/form-data; boundary=----------------------------
@@ -67,6 +67,11 @@ postit2.c Content-Disposition: form-data; name="submit"
send
+------------------------------
+Content-Disposition: form-data; name="somename"; filename="somefile.txt"
+Content-Type: application/octet-stream
+
+blah blah
--------------------------------
</protocol> </verify> diff --git a/tests/data/test569 b/tests/data/test569 index 5cd4797fe..c4c62a4c3 100644 --- a/tests/data/test569 +++ b/tests/data/test569 @@ -51,6 +51,7 @@ Curl-Private: swsclose CSeq: 6 </data6> +</reply> # Client-Side <client> diff --git a/tests/data/test572 b/tests/data/test572 index c06e531fc..83ae646e2 100644 --- a/tests/data/test572 +++ b/tests/data/test572 @@ -28,10 +28,11 @@ Cseq: 2 scale=enormous speed=ludicrous + </data2> <data3> -RTSP/1.0 200 OK +RTSP/1.0 204 OK Server: RTSPD/libcurl-test Session: getparams-test Cseq: 3 diff --git a/tests/data/test573 b/tests/data/test573 index 909ae3cf7..54ff8fb94 100644 --- a/tests/data/test573 +++ b/tests/data/test573 @@ -1,7 +1,8 @@ <testcase> <info> <keywords> -FILE +HTTP +multi </keywords> </info> # diff --git a/tests/data/test583 b/tests/data/test583 index 2129ee729..8fca7d23c 100644 --- a/tests/data/test583 +++ b/tests/data/test583 @@ -35,9 +35,8 @@ sftp://localhost:%SSHPORT%PWD/log/upload583.txt %USER: # Verify data after the test has been "shot" <verify> -<strip> -</strip> -<protocol> -</protocol> +<errorcode> +0 +</errorcode> </verify> </testcase> diff --git a/tests/data/test587 b/tests/data/test587 new file mode 100644 index 000000000..6e1239a6a --- /dev/null +++ b/tests/data/test587 @@ -0,0 +1,51 @@ +<testcase> +# +# Server-side +<reply> +<data> +</data> +</reply> + +# Client-side +<client> +<server> +http +</server> +# tool is what to use instead of 'curl' +<tool> +lib587 +</tool> + + <name> +HTTP multi-part formpost with aborted read callback + </name> + <command> +http://%HOSTIP:%HTTPPORT/587 +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strippart> +s/^------------------------------[a-z0-9]*/------------------------------/ +s/boundary=----------------------------[a-z0-9]*/boundary=----------------------------/ +</strippart> +<protocol> +POST /587 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+Content-Length: 732
+Expect: 100-continue
+Content-Type: multipart/form-data; boundary=----------------------------
+
+------------------------------
+Content-Disposition: form-data; name="sendfile"; filename="postit2.c"
+
+</protocol> +# CURLE_ABORTED_BY_CALLBACK (42) +<errorcode> +42 +</errorcode> +</verify> +</testcase> diff --git a/tests/data/test709 b/tests/data/test709 new file mode 100644 index 000000000..6620f89a7 --- /dev/null +++ b/tests/data/test709 @@ -0,0 +1,60 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +SOCKS5 +</keywords> +</info> + +# +# Server-side +<reply> +<data> +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- +</data> +</reply> + +# +# Client-side +<client> +<server> +http +socks5 +</server> +<setenv> +http_proxy=socks5://%HOSTIP:%SOCKSPORT +</setenv> + <name> +HTTP GET via SOCKS5 set in environment + </name> + <command> +http://%HOSTIP:%HTTPPORT/709 +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /709 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test710 b/tests/data/test710 new file mode 100644 index 000000000..884eb50a0 --- /dev/null +++ b/tests/data/test710 @@ -0,0 +1,57 @@ +<testcase> +<info> +<keywords> +HTTP +HTTP GET +SOCKS5 +</keywords> +</info> + +# +# Server-side +<reply> +<data> +HTTP/1.1 200 OK +Date: Thu, 09 Nov 2010 14:49:00 GMT +Server: test-server/fake +Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT +ETag: "21025-dc7-39462498" +Accept-Ranges: bytes +Content-Length: 6 +Connection: close +Content-Type: text/html +Funny-head: yesyes + +-foo- +</data> +</reply> + +# +# Client-side +<client> +<server> +http +socks5 +</server> + <name> +HTTP GET via SOCKS5 set with --proxy + </name> + <command> +http://%HOSTIP:%HTTPPORT/710 --proxy socks5://%HOSTIP:%SOCKSPORT +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<strip> +^User-Agent:.* +</strip> +<protocol> +GET /710 HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+Accept: */*
+
+</protocol> +</verify> +</testcase> diff --git a/tests/data/test814 b/tests/data/test814 new file mode 100644 index 000000000..1fc060777 --- /dev/null +++ b/tests/data/test814 @@ -0,0 +1,52 @@ +<testcase> +<info> +<keywords> +SMTP +</keywords> +</info> + +# +# Server-side +<reply> +</reply> + +# +# Client-side +<client> +<server> +smtp +</server> + <name> +SMTP without --mail-from + </name> +<stdin> +From: different +To: another + +body +</stdin> + <command> +smtp://%HOSTIP:%SMTPPORT/user --mail-rcpt 814@foo -T - +</command> +</client> + +# +# Verify data after the test has been "shot" +<verify> +<protocol> +EHLO user
+MAIL FROM:<>
+RCPT TO:<814@foo>
+DATA
+QUIT
+</protocol> +<upload> +From: different +To: another + +body +
+.
+</upload> +</verify> +</testcase> diff --git a/tests/getpart.pm b/tests/getpart.pm index 4d47736b6..83e56ca92 100644 --- a/tests/getpart.pm +++ b/tests/getpart.pm @@ -63,6 +63,10 @@ sub getpartattr { } last; } + # detect end of section when part wasn't found + elsif((1 ==$inside) && ($_ =~ /^ *\<\/$section\>/)) { + last; + } elsif((2 ==$inside) && ($_ =~ /^ *\<\/$part/)) { $inside--; } diff --git a/tests/libtest/Makefile.inc b/tests/libtest/Makefile.inc index 98e33c1f1..86b3b29ab 100644 --- a/tests/libtest/Makefile.inc +++ b/tests/libtest/Makefile.inc @@ -15,7 +15,7 @@ noinst_PROGRAMS = chkhostname \ lib579 lib529 lib530 lib532 lib533 lib536 lib537 lib540 lib541 lib542 \ lib543 lib544 lib545 lib547 lib548 lib549 lib552 lib553 lib554 lib555 \ lib556 lib539 lib557 lib560 lib562 lib564 lib565 lib566 lib567 lib568 \ - lib569 lib570 lib571 lib572 lib573 lib582 lib583 lib585 + lib569 lib570 lib571 lib572 lib573 lib582 lib583 lib585 lib587 chkhostname_SOURCES = chkhostname.c $(top_srcdir)/lib/curl_gethostname.c chkhostname_LDADD = @CURL_NETWORK_LIBS@ @@ -26,7 +26,7 @@ lib500_SOURCES = lib500.c $(SUPPORTFILES) lib501_SOURCES = lib501.c $(SUPPORTFILES) -lib502_SOURCES = lib502.c $(SUPPORTFILES) $(TESTUTIL) +lib502_SOURCES = lib502.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib503_SOURCES = lib503.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) @@ -56,7 +56,7 @@ lib516_SOURCES = lib516.c $(SUPPORTFILES) lib517_SOURCES = lib517.c $(SUPPORTFILES) -lib518_SOURCES = lib518.c $(SUPPORTFILES) +lib518_SOURCES = lib518.c $(SUPPORTFILES) $(WARNLESS) lib519_SOURCES = lib519.c $(SUPPORTFILES) @@ -89,11 +89,11 @@ lib533_SOURCES = lib533.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib536_SOURCES = lib536.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) -lib537_SOURCES = lib537.c $(SUPPORTFILES) +lib537_SOURCES = lib537.c $(SUPPORTFILES) $(WARNLESS) lib539_SOURCES = lib539.c $(SUPPORTFILES) -lib540_SOURCES = lib540.c $(SUPPORTFILES) $(WARNLESS) +lib540_SOURCES = lib540.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib541_SOURCES = lib541.c $(SUPPORTFILES) @@ -113,7 +113,7 @@ lib548_CPPFLAGS = $(AM_CPPFLAGS) -DLIB548 lib549_SOURCES = lib549.c $(SUPPORTFILES) -lib555_SOURCES = lib555.c $(SUPPORTFILES) $(TESTUTIL) +lib555_SOURCES = lib555.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib552_SOURCES = lib552.c $(SUPPORTFILES) @@ -125,11 +125,11 @@ lib556_SOURCES = lib556.c $(SUPPORTFILES) lib557_SOURCES = lib557.c $(SUPPORTFILES) -lib560_SOURCES = lib560.c $(SUPPORTFILES) $(WARNLESS) +lib560_SOURCES = lib560.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib574_SOURCES = lib574.c $(SUPPORTFILES) -lib575_SOURCES = lib575.c $(SUPPORTFILES) $(WARNLESS) +lib575_SOURCES = lib575.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib576_SOURCES = lib576.c $(SUPPORTFILES) @@ -154,7 +154,7 @@ lib571_SOURCES = lib571.c $(SUPPORTFILES) lib572_SOURCES = lib572.c $(SUPPORTFILES) -lib573_SOURCES = lib573.c $(SUPPORTFILES) $(TESTUTIL) +lib573_SOURCES = lib573.c $(SUPPORTFILES) $(TESTUTIL) $(WARNLESS) lib578_SOURCES = lib578.c $(SUPPORTFILES) @@ -166,3 +166,6 @@ lib583_SOURCES = lib583.c $(SUPPORTFILES) lib585_SOURCES = lib500.c $(SUPPORTFILES) lib585_CPPFLAGS = $(AM_CPPFLAGS) -DLIB585 + +lib587_SOURCES = lib554.c $(SUPPORTFILES) +lib587_CPPFLAGS = $(AM_CPPFLAGS) -DLIB587 diff --git a/tests/libtest/first.c b/tests/libtest/first.c index 205d3943f..57e6ddd79 100644 --- a/tests/libtest/first.c +++ b/tests/libtest/first.c @@ -30,19 +30,25 @@ # include "memdebug.h" #endif -int select_test (int num_fds, fd_set *rd, fd_set *wr, fd_set *exc, - struct timeval *tv) +int select_wrapper(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, + struct timeval *tv) { + if(nfds < 0) { + SET_SOCKERRNO(EINVAL); + return -1; + } #ifdef USE_WINSOCK - /* Winsock doesn't like no socket set in 'rd', 'wr' or 'exc'. This is - * case when 'num_fds <= 0. So sleep. + /* + * Winsock select() requires that at least one of the three fd_set + * pointers is not NULL and points to a non-empty fdset. IOW Winsock + * select() can not be used to sleep without a single fd_set. */ - if (num_fds <= 0) { + if(!nfds) { Sleep(1000*tv->tv_sec + tv->tv_usec/1000); return 0; } #endif - return select(num_fds, rd, wr, exc, tv); + return select(nfds, rd, wr, exc, tv); } char *libtest_arg2=NULL; @@ -50,28 +56,31 @@ char *libtest_arg3=NULL; int test_argc; char **test_argv; +struct timeval tv_test_start; /* for test timing */ + #ifdef UNITTESTS int unitfail; /* for unittests */ #endif -int main(int argc, char **argv) -{ - char *URL; - #ifdef CURLDEBUG - /* this sends all memory debug messages to a logfile named memdump */ - char *env = curl_getenv("CURL_MEMDEBUG"); +static void memory_tracking_init(void) +{ + char *env; + /* if CURL_MEMDEBUG is set, this starts memory tracking message logging */ + env = curl_getenv("CURL_MEMDEBUG"); if(env) { /* use the value as file name */ - char *s = strdup(env); + char fname[CURL_MT_LOGFNAME_BUFSIZE]; + if(strlen(env) >= CURL_MT_LOGFNAME_BUFSIZE) + env[CURL_MT_LOGFNAME_BUFSIZE-1] = '\0'; + strcpy(fname, env); curl_free(env); - curl_memdebug(s); - free(s); - /* this weird strdup() and stuff here is to make the curl_free() get - called before the memdebug() as otherwise the memdebug tracing will - with tracing a free() without an alloc! */ + curl_memdebug(fname); + /* this weird stuff here is to make curl_free() get called + before curl_memdebug() as otherwise memory tracking will + log a free() without an alloc! */ } - /* this enables the fail-on-alloc-number-N functionality */ + /* if CURL_MEMLIMIT is set, this enables fail-on-alloc-number-N feature */ env = curl_getenv("CURL_MEMLIMIT"); if(env) { char *endptr; @@ -80,8 +89,17 @@ int main(int argc, char **argv) curl_memlimit(num); curl_free(env); } +} +#else +# define memory_tracking_init() Curl_nop_stmt #endif +int main(int argc, char **argv) +{ + char *URL; + + memory_tracking_init(); + /* * Setup proper locale from environment. This is needed to enable locale- * specific behaviour by the C library in order to test for undesired side diff --git a/tests/libtest/lib500.c b/tests/libtest/lib500.c index 8ebeb1292..51680fc31 100644 --- a/tests/libtest/lib500.c +++ b/tests/libtest/lib500.c @@ -52,7 +52,7 @@ static void setupcallbacks(CURL *curl) } #else -#define setupcallbacks(x) +#define setupcallbacks(x) Curl_nop_stmt #endif diff --git a/tests/libtest/lib502.c b/tests/libtest/lib502.c index 9ade12afb..554583ae2 100644 --- a/tests/libtest/lib502.c +++ b/tests/libtest/lib502.c @@ -22,10 +22,10 @@ #include "test.h" #include "testutil.h" +#include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 /* * Get a single URL without select(). @@ -33,71 +33,57 @@ int test(char *URL) { - CURL *c; + CURL *c = NULL; CURLM *m = NULL; int res = 0; - int running=1; - struct timeval mp_start; - char mp_timedout = FALSE; + int running; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - if ((c = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); - test_setopt(c, CURLOPT_URL, URL); + easy_init(c); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(c, CURLOPT_URL, URL); - if ((res = (int)curl_multi_add_handle(m, c)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (running) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - fprintf(stderr, "nothing left running.\n"); - break; - } - } + multi_add_handle(m, c); + + for(;;) { + struct timeval timeout; + fd_set fdread, fdwrite, fdexcep; + int maxfd = -99; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000L; /* 100 ms */ + + multi_perform(m, &running); - if (mp_timedout) { - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); + + if(!running) + break; /* done */ + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + multi_fdset(m, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); } test_cleanup: - if(m) { - curl_multi_remove_handle(m, c); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + + curl_multi_remove_handle(m, c); + curl_multi_cleanup(m); curl_easy_cleanup(c); curl_global_cleanup(); diff --git a/tests/libtest/lib503.c b/tests/libtest/lib503.c index 25a641548..f3f96aaa5 100644 --- a/tests/libtest/lib503.c +++ b/tests/libtest/lib503.c @@ -21,14 +21,11 @@ ***************************************************************************/ #include "test.h" -#include <sys/types.h> - #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 /* * Source code in here hugely as reported in bug report 651460 by @@ -40,123 +37,62 @@ int test(char *URL) { - CURL *c; + CURL *c = NULL; CURLM *m = NULL; int res = 0; int running; - char done = FALSE; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - if ((c = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - test_setopt(c, CURLOPT_PROXY, libtest_arg2); /* set in first.c */ - test_setopt(c, CURLOPT_URL, URL); - test_setopt(c, CURLOPT_USERPWD, "test:ing"); - test_setopt(c, CURLOPT_PROXYUSERPWD, "test:ing"); - test_setopt(c, CURLOPT_HTTPPROXYTUNNEL, 1L); - test_setopt(c, CURLOPT_HEADER, 1L); - - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); - if ((res = (int)curl_multi_add_handle(m, c)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(c); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + easy_setopt(c, CURLOPT_PROXY, libtest_arg2); /* set in first.c */ + easy_setopt(c, CURLOPT_URL, URL); + easy_setopt(c, CURLOPT_USERPWD, "test:ing"); + easy_setopt(c, CURLOPT_PROXYUSERPWD, "test:ing"); + easy_setopt(c, CURLOPT_HTTPPROXYTUNNEL, 1L); + easy_setopt(c, CURLOPT_HEADER, 1L); - while(!done) { - fd_set rd, wr, exc; - int max_fd; + multi_init(m); + + multi_add_handle(m, c); + + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - done = TRUE; - break; - } - } - if (mp_timedout || done) - break; - - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; - } + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) + break; /* done */ FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 89; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 95; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } test_cleanup: - if(m) { - curl_multi_remove_handle(m, c); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + + curl_multi_remove_handle(m, c); + curl_multi_cleanup(m); curl_easy_cleanup(c); curl_global_cleanup(); diff --git a/tests/libtest/lib504.c b/tests/libtest/lib504.c index f45ac256b..358fc98dc 100644 --- a/tests/libtest/lib504.c +++ b/tests/libtest/lib504.c @@ -21,14 +21,11 @@ ***************************************************************************/ #include "test.h" -#include <sys/types.h> - #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 /* * Source code in here hugely as reported in bug report 651464 by @@ -39,85 +36,41 @@ */ int test(char *URL) { - CURL *c; + CURL *c = NULL; int res = 0; CURLM *m = NULL; fd_set rd, wr, exc; - CURLMcode ret; - char done = FALSE; int running; - int max_fd; - int rc; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - if ((c = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); + + global_init(CURL_GLOBAL_ALL); + + easy_init(c); /* The point here is that there must not be anything running on the given proxy port */ if (libtest_arg2) - test_setopt(c, CURLOPT_PROXY, libtest_arg2); - test_setopt(c, CURLOPT_URL, URL); - test_setopt(c, CURLOPT_VERBOSE, 1L); - - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(c, CURLOPT_PROXY, libtest_arg2); + easy_setopt(c, CURLOPT_URL, URL); + easy_setopt(c, CURLOPT_VERBOSE, 1L); - if ((ret = curl_multi_add_handle(m, c)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", ret); - curl_multi_cleanup(m); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, c); - while (!done) { + for(;;) { struct timeval interval; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - fprintf(stderr, "curl_multi_perform()\n"); - ret = CURLM_CALL_MULTI_PERFORM; + multi_perform(m, &running); - while (ret == CURLM_CALL_MULTI_PERFORM) { - ret = curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - } - if (mp_timedout) - break; + abort_on_test_timeout(); if(!running) { /* This is where this code is expected to reach */ @@ -125,47 +78,34 @@ int test(char *URL) CURLMsg *msg = curl_multi_info_read(m, &numleft); fprintf(stderr, "Expected: not running\n"); if(msg && !numleft) - res = 100; /* this is where we should be */ + res = TEST_ERR_SUCCESS; /* this is where we should be */ else - res = 99; /* not correct */ - break; - } - fprintf(stderr, "running == %d, ret == %d\n", running, ret); - - if (ret != CURLM_OK) { - res = 2; - break; + res = TEST_ERR_FAILURE; /* not correct */ + break; /* done */ } + fprintf(stderr, "running == %d\n", running); FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; fprintf(stderr, "curl_multi_fdset()\n"); - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 3; - break; - } - rc = select_test(max_fd+1, &rd, &wr, &exc, &interval); - fprintf(stderr, "select returned %d\n", rc); - } - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + multi_fdset(m, &rd, &wr, &exc, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &rd, &wr, &exc, &interval); + + abort_on_test_timeout(); } test_cleanup: - if(m) { - curl_multi_remove_handle(m, c); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + + curl_multi_remove_handle(m, c); + curl_multi_cleanup(m); curl_easy_cleanup(c); curl_global_cleanup(); diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index 0a255d673..394131ebe 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -24,12 +24,6 @@ #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> #endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif diff --git a/tests/libtest/lib506.c b/tests/libtest/lib506.c index 6476b9546..4477eaa50 100644 --- a/tests/libtest/lib506.c +++ b/tests/libtest/lib506.c @@ -20,9 +20,6 @@ * ***************************************************************************/ #include "test.h" -#include <stdlib.h> -#include <ctype.h> -#include <errno.h> #include <curl/mprintf.h> diff --git a/tests/libtest/lib507.c b/tests/libtest/lib507.c index c5a009d8c..87c21defb 100644 --- a/tests/libtest/lib507.c +++ b/tests/libtest/lib507.c @@ -25,75 +25,40 @@ #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 int test(char *URL) { - CURL* curls; - CURLM* multi; + CURL* curls = NULL; + CURLM* multi = NULL; int still_running; int i = -1; int res = 0; CURLMsg *msg; - CURLMcode ret; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - if ((multi = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - if ((curls = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_multi_cleanup(multi); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); - test_setopt(curls, CURLOPT_URL, URL); - test_setopt(curls, CURLOPT_HEADER, 1L); + multi_init(multi); - if ((ret = curl_multi_add_handle(multi, curls)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", ret); - curl_easy_cleanup(curls); - curl_multi_cleanup(multi); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(curls); - mp_timedout = FALSE; - mp_start = tutil_tvnow(); + easy_setopt(curls, CURLOPT_URL, URL); + easy_setopt(curls, CURLOPT_HEADER, 1L); - do { - ret = curl_multi_perform(multi, &still_running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - } while (ret == CURLM_CALL_MULTI_PERFORM); + multi_add_handle(multi, curls); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_perform(multi, &still_running); - while ((!ml_timedout) && (!mp_timedout) && (still_running)) { + abort_on_test_timeout(); + + while(still_running) { struct timeval timeout; - int rc; fd_set fdread; fd_set fdwrite; fd_set fdexcep; - int maxfd; + int maxfd = -99; FD_ZERO(&fdread); FD_ZERO(&fdwrite); @@ -101,49 +66,29 @@ int test(char *URL) timeout.tv_sec = 1; timeout.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - - curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); - rc = select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - switch(rc) { - case -1: - break; - case 0: - default: - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - do { - ret = curl_multi_perform(multi, &still_running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - } while (ret == CURLM_CALL_MULTI_PERFORM); - break; - } - } - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - i = TEST_ERR_RUNS_FOREVER; - } - else { - msg = curl_multi_info_read(multi, &still_running); - if(msg) - /* this should now contain a result code from the easy handle, - get it */ - i = msg->data.result; + multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); + + multi_perform(multi, &still_running); + + abort_on_test_timeout(); } + msg = curl_multi_info_read(multi, &still_running); + if(msg) + /* this should now contain a result code from the easy handle, + get it */ + i = msg->data.result; + test_cleanup: + /* undocumented cleanup sequence - type UA */ + curl_multi_cleanup(multi); curl_easy_cleanup(curls); curl_global_cleanup(); diff --git a/tests/libtest/lib518.c b/tests/libtest/lib518.c index c483d7ade..23f7f17c6 100644 --- a/tests/libtest/lib518.c +++ b/tests/libtest/lib518.c @@ -21,9 +21,6 @@ ***************************************************************************/ #include "test.h" -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> #endif @@ -33,10 +30,8 @@ #ifdef HAVE_LIMITS_H #include <limits.h> #endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif +#include "warnless.h" #include "memdebug.h" #ifndef FD_SETSIZE diff --git a/tests/libtest/lib525.c b/tests/libtest/lib525.c index f034050eb..ca128cb9c 100644 --- a/tests/libtest/lib525.c +++ b/tests/libtest/lib525.c @@ -21,45 +21,45 @@ ***************************************************************************/ #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 int test(char *URL) { int res = 0; - CURL *curl; - FILE *hd_src ; + CURL *curl = NULL; + FILE *hd_src = NULL; int hd ; int error; struct_stat file_info; - int running; - char done=FALSE; CURLM *m = NULL; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; + int running; + + start_test_timing(); - if (!libtest_arg2) { + if(!libtest_arg2) { +#ifdef LIB529 + /* test 529 */ + fprintf(stderr, "Usage: lib529 [url] [uploadfile]\n"); +#else + /* test 525 */ fprintf(stderr, "Usage: lib525 [url] [uploadfile]\n"); - return -1; +#endif + return TEST_ERR_USAGE; } hd_src = fopen(libtest_arg2, "rb"); if(NULL == hd_src) { error = ERRNO; - fprintf(stderr, "fopen() failed with error: %d %s\n", + fprintf(stderr, "fopen() failed with error: %d (%s)\n", error, strerror(error)); - fprintf(stderr, "Error opening file: %s\n", libtest_arg2); - return TEST_ERR_MAJOR_BAD; + fprintf(stderr, "Error opening file: (%s)\n", libtest_arg2); + return TEST_ERR_FOPEN; } /* get the file size of the local file */ @@ -67,40 +67,35 @@ int test(char *URL) if(hd == -1) { /* can't open file, bail out */ error = ERRNO; - fprintf(stderr, "fstat() failed with error: %d %s\n", + fprintf(stderr, "fstat() failed with error: %d (%s)\n", error, strerror(error)); - fprintf(stderr, "ERROR: cannot open file %s\n", libtest_arg2); + fprintf(stderr, "ERROR: cannot open file (%s)\n", libtest_arg2); fclose(hd_src); - return -1; + return TEST_ERR_FSTAT; } - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); + res_global_init(CURL_GLOBAL_ALL); + if(res) { fclose(hd_src); - return TEST_ERR_MAJOR_BAD; + return res; } - if ((curl = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - fclose(hd_src); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(curl); /* enable uploading */ - test_setopt(curl, CURLOPT_UPLOAD, 1L); + easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* specify target */ - test_setopt(curl,CURLOPT_URL, URL); + easy_setopt(curl,CURLOPT_URL, URL); /* go verbose */ - test_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); /* use active FTP */ - test_setopt(curl, CURLOPT_FTPPORT, "-"); + easy_setopt(curl, CURLOPT_FTPPORT, "-"); /* now specify which file to upload */ - test_setopt(curl, CURLOPT_READDATA, hd_src); + easy_setopt(curl, CURLOPT_READDATA, hd_src); /* NOTE: if you want this code to work on Windows with libcurl as a DLL, you MUST also provide a read callback with CURLOPT_READFUNCTION. Failing to @@ -111,114 +106,60 @@ int test(char *URL) 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. */ - test_setopt(curl, CURLOPT_INFILESIZE_LARGE, - (curl_off_t)file_info.st_size); - - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(curl); - curl_global_cleanup(); - fclose(hd_src); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); - if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(curl); - curl_global_cleanup(); - fclose(hd_src); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, curl); - while (!done) { - fd_set rd, wr, exc; - int max_fd; + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - done = TRUE; - break; - } - } - if (mp_timedout || done) - break; - - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; - } + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) + break; /* done */ FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 189; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 195; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } test_cleanup: #ifdef LIB529 /* test 529 */ - if(m) { - curl_multi_remove_handle(m, curl); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + curl_multi_remove_handle(m, curl); + curl_multi_cleanup(m); curl_easy_cleanup(curl); + curl_global_cleanup(); #else /* test 525 */ - if(m) - curl_multi_remove_handle(m, curl); + /* proper cleanup sequence - type PB */ + curl_multi_remove_handle(m, curl); curl_easy_cleanup(curl); - if(m) - curl_multi_cleanup(m); + curl_multi_cleanup(m); + curl_global_cleanup(); #endif - fclose(hd_src); /* close the local file */ + /* close the local file */ + fclose(hd_src); - curl_global_cleanup(); return res; } diff --git a/tests/libtest/lib526.c b/tests/libtest/lib526.c index a0085ec3c..9db04dba7 100644 --- a/tests/libtest/lib526.c +++ b/tests/libtest/lib526.c @@ -40,16 +40,13 @@ #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 #define NUM_HANDLES 4 @@ -58,192 +55,130 @@ int test(char *URL) int res = 0; CURL *curl[NUM_HANDLES]; int running; - char done=FALSE; CURLM *m = NULL; - int current=0; - int i, j; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + int current = 0; + int i; + + for(i=0; i < NUM_HANDLES; i++) + curl[i] = NULL; + + start_test_timing(); + + global_init(CURL_GLOBAL_ALL); /* get NUM_HANDLES easy handles */ for(i=0; i < NUM_HANDLES; i++) { - curl[i] = curl_easy_init(); - if(!curl[i]) { - fprintf(stderr, "curl_easy_init() failed " - "on handle #%d\n", i); - for (j=i-1; j >= 0; j--) { - curl_easy_cleanup(curl[j]); - } - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } - res = curl_easy_setopt(curl[i], CURLOPT_URL, URL); - if(res) { - fprintf(stderr, "curl_easy_setopt() failed " - "on handle #%d\n", i); - for (j=i; j >= 0; j--) { - curl_easy_cleanup(curl[j]); - } - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } - + easy_init(curl[i]); + /* specify target */ + easy_setopt(curl[i], CURLOPT_URL, URL); /* go verbose */ - res = curl_easy_setopt(curl[i], CURLOPT_VERBOSE, 1L); - if(res) { - fprintf(stderr, "curl_easy_setopt() failed " - "on handle #%d\n", i); - for (j=i; j >= 0; j--) { - curl_easy_cleanup(curl[j]); - } - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } + easy_setopt(curl[i], CURLOPT_VERBOSE, 1L); } - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - for(i=0; i < NUM_HANDLES; i++) { - curl_easy_cleanup(curl[i]); - } - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - if ((res = (int)curl_multi_add_handle(m, curl[current])) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - for(i=0; i < NUM_HANDLES; i++) { - curl_easy_cleanup(curl[i]); - } - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } - - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, curl[current]); fprintf(stderr, "Start at URL 0\n"); - while (!done) { - fd_set rd, wr, exc; - int max_fd; + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) { #ifdef LIB527 - /* NOTE: this code does not remove the handle from the multi handle - here, which would be the nice, sane and documented way of working. - This however tests that the API survives this abuse gracefully. */ - curl_easy_cleanup(curl[current]); + /* NOTE: this code does not remove the handle from the multi handle + here, which would be the nice, sane and documented way of working. + This however tests that the API survives this abuse gracefully. */ + curl_easy_cleanup(curl[current]); + curl[current] = NULL; #endif - if(++current < NUM_HANDLES) { - fprintf(stderr, "Advancing to URL %d\n", current); + if(++current < NUM_HANDLES) { + fprintf(stderr, "Advancing to URL %d\n", current); #ifdef LIB532 - /* first remove the only handle we use */ - curl_multi_remove_handle(m, curl[0]); - - /* make us re-use the same handle all the time, and try resetting - the handle first too */ - curl_easy_reset(curl[0]); - test_setopt(curl[0], CURLOPT_URL, URL); - test_setopt(curl[0], CURLOPT_VERBOSE, 1L); - - /* re-add it */ - res = (int)curl_multi_add_handle(m, curl[0]); + /* first remove the only handle we use */ + curl_multi_remove_handle(m, curl[0]); + + /* make us re-use the same handle all the time, and try resetting + the handle first too */ + curl_easy_reset(curl[0]); + easy_setopt(curl[0], CURLOPT_URL, URL); + /* go verbose */ + easy_setopt(curl[0], CURLOPT_VERBOSE, 1L); + + /* re-add it */ + multi_add_handle(m, curl[0]); #else - res = (int)curl_multi_add_handle(m, curl[current]); + multi_add_handle(m, curl[current]); #endif - if(res) { - fprintf(stderr, "add handle failed: %d.\n", res); - res = 243; - break; - } - } - else - done = TRUE; /* bail out */ - break; } - } - if (mp_timedout || done) - break; - - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; + else { + break; /* done */ + } } FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 189; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 195; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } -#ifdef LIB532 test_cleanup: -#endif -#ifndef LIB527 - /* get NUM_HANDLES easy handles */ +#if defined(LIB526) + + /* test 526 and 528 */ + /* proper cleanup sequence - type PB */ + for(i=0; i < NUM_HANDLES; i++) { -#ifdef LIB526 - if(m) - curl_multi_remove_handle(m, curl[i]); -#endif + curl_multi_remove_handle(m, curl[i]); curl_easy_cleanup(curl[i]); } -#endif - if(m) - curl_multi_cleanup(m); + curl_multi_cleanup(m); + curl_global_cleanup(); +#elif defined(LIB527) + + /* test 527 */ + + /* Upon non-failure test flow the easy's have already been cleanup'ed. In + case there is a failure we arrive here with easy's that have not been + cleanup'ed yet, in this case we have to cleanup them or otherwise these + will be leaked, let's use undocumented cleanup sequence - type UB */ + + if(res) + for(i=0; i < NUM_HANDLES; i++) + curl_easy_cleanup(curl[i]); + + curl_multi_cleanup(m); curl_global_cleanup(); + +#elif defined(LIB532) + + /* test 532 */ + /* undocumented cleanup sequence - type UB */ + + for(i=0; i < NUM_HANDLES; i++) + curl_easy_cleanup(curl[i]); + curl_multi_cleanup(m); + curl_global_cleanup(); + +#endif + return res; } diff --git a/tests/libtest/lib530.c b/tests/libtest/lib530.c index add64ea31..ad84ff8a5 100644 --- a/tests/libtest/lib530.c +++ b/tests/libtest/lib530.c @@ -21,22 +21,11 @@ ***************************************************************************/ #include "test.h" -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif - #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 #define NUM_HANDLES 4 @@ -45,173 +34,71 @@ int test(char *URL) int res = 0; CURL *curl[NUM_HANDLES]; int running; - char done=FALSE; - CURLM *m; - int i, j; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; + CURLM *m = NULL; + int i; char target_url[256]; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + for(i=0; i < NUM_HANDLES; i++) + curl[i] = NULL; - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); + + global_init(CURL_GLOBAL_ALL); + + multi_init(m); /* get NUM_HANDLES easy handles */ for(i=0; i < NUM_HANDLES; i++) { - curl[i] = curl_easy_init(); - if(!curl[i]) { - fprintf(stderr, "curl_easy_init() failed " - "on handle #%d\n", i); - for (j=i-1; j >= 0; j--) { - curl_multi_remove_handle(m, curl[j]); - curl_easy_cleanup(curl[j]); - } - curl_multi_cleanup(m); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } + /* get an easy handle */ + easy_init(curl[i]); + /* specify target */ sprintf(target_url, "%s%04i", URL, i + 1); target_url[sizeof(target_url) - 1] = '\0'; - - res = curl_easy_setopt(curl[i], CURLOPT_URL, target_url); - if(res) { - fprintf(stderr, "curl_easy_setopt() failed " - "on handle #%d\n", i); - for (j=i; j >= 0; j--) { - curl_multi_remove_handle(m, curl[j]); - curl_easy_cleanup(curl[j]); - } - curl_multi_cleanup(m); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } - + easy_setopt(curl[i], CURLOPT_URL, target_url); /* go verbose */ - res = curl_easy_setopt(curl[i], CURLOPT_VERBOSE, 1L); - if(res) { - fprintf(stderr, "curl_easy_setopt() failed " - "on handle #%d\n", i); - for (j=i; j >= 0; j--) { - curl_multi_remove_handle(m, curl[j]); - curl_easy_cleanup(curl[j]); - } - curl_multi_cleanup(m); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } - + easy_setopt(curl[i], CURLOPT_VERBOSE, 1L); /* include headers */ - res = curl_easy_setopt(curl[i], CURLOPT_HEADER, 1L); - if(res) { - fprintf(stderr, "curl_easy_setopt() failed " - "on handle #%d\n", i); - for (j=i; j >= 0; j--) { - curl_multi_remove_handle(m, curl[j]); - curl_easy_cleanup(curl[j]); - } - curl_multi_cleanup(m); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } - + easy_setopt(curl[i], CURLOPT_HEADER, 1L); /* add handle to multi */ - if ((res = (int)curl_multi_add_handle(m, curl[i])) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "on handle #%d with code %d\n", i, res); - curl_easy_cleanup(curl[i]); - for (j=i-1; j >= 0; j--) { - curl_multi_remove_handle(m, curl[j]); - curl_easy_cleanup(curl[j]); - } - curl_multi_cleanup(m); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD + i; - } + multi_add_handle(m, curl[i]); } - curl_multi_setopt(m, CURLMOPT_PIPELINING, 1L); - - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_setopt(m, CURLMOPT_PIPELINING, 1L); fprintf(stderr, "Start at URL 0\n"); - while (!done) { - fd_set rd, wr, exc; - int max_fd; + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - done = TRUE; /* bail out */ - break; - } - } - if (mp_timedout || done) - break; - - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; - } + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) + break; /* done */ FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 189; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 195; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } -/* test_cleanup: */ +test_cleanup: + + /* proper cleanup sequence - type PB */ - /* cleanup NUM_HANDLES easy handles */ for(i=0; i < NUM_HANDLES; i++) { curl_multi_remove_handle(m, curl[i]); curl_easy_cleanup(curl[i]); diff --git a/tests/libtest/lib533.c b/tests/libtest/lib533.c index 606eba75c..fdc18a1eb 100644 --- a/tests/libtest/lib533.c +++ b/tests/libtest/lib533.c @@ -23,156 +23,89 @@ #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 int test(char *URL) { int res = 0; - CURL *curl; + CURL *curl = NULL; int running; - char done=FALSE; CURLM *m = NULL; int current=0; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - if ((curl = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - test_setopt(curl, CURLOPT_URL, URL); - test_setopt(curl, CURLOPT_VERBOSE, 1); - test_setopt(curl, CURLOPT_FAILONERROR, 1); + global_init(CURL_GLOBAL_ALL); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(curl); - if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + multi_init(m); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, curl); fprintf(stderr, "Start at URL 0\n"); - while (!done) { - fd_set rd, wr, exc; - int max_fd; + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - if(!current++) { - fprintf(stderr, "Advancing to URL 1\n"); - /* remove the handle we use */ - curl_multi_remove_handle(m, curl); - - /* make us re-use the same handle all the time, and try resetting - the handle first too */ - curl_easy_reset(curl); - test_setopt(curl, CURLOPT_URL, libtest_arg2); - test_setopt(curl, CURLOPT_VERBOSE, 1); - test_setopt(curl, CURLOPT_FAILONERROR, 1); - - /* re-add it */ - res = (int)curl_multi_add_handle(m, curl); - if(res) { - fprintf(stderr, "add handle failed: %d.\n", res); - res = 243; - break; - } - } - else - done = TRUE; /* bail out */ - break; - } - } - if (mp_timedout || done) - break; + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) { + if(!current++) { + fprintf(stderr, "Advancing to URL 1\n"); + /* remove the handle we use */ + curl_multi_remove_handle(m, curl); - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; + /* make us re-use the same handle all the time, and try resetting + the handle first too */ + curl_easy_reset(curl); + easy_setopt(curl, CURLOPT_URL, libtest_arg2); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_FAILONERROR, 1L); + + /* re-add it */ + multi_add_handle(m, curl); + } + else + break; /* done */ } FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 189; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 195; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } test_cleanup: + /* undocumented cleanup sequence - type UB */ + curl_easy_cleanup(curl); - if(m) - curl_multi_cleanup(m); + curl_multi_cleanup(m); curl_global_cleanup(); return res; diff --git a/tests/libtest/lib536.c b/tests/libtest/lib536.c index dca880cea..e3ae402b7 100644 --- a/tests/libtest/lib536.c +++ b/tests/libtest/lib536.c @@ -21,128 +21,117 @@ ***************************************************************************/ #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 -static CURLMcode perform(CURLM * multi) +static int perform(CURLM *multi) { int handles; - CURLMcode code; fd_set fdread, fdwrite, fdexcep; - struct timeval mp_start; - char mp_timedout = FALSE; - - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - for (;;) { - static struct timeval timeout = /* 100 ms */ { 0, 100000L }; - int maxfd = -1; - - code = curl_multi_perform(multi, &handles); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (handles <= 0) - return CURLM_OK; - - switch (code) { - case CURLM_OK: - break; - case CURLM_CALL_MULTI_PERFORM: - continue; - default: - return code; - } + int res = 0; + + for(;;) { + struct timeval interval; + int maxfd = -99; + + interval.tv_sec = 0; + interval.tv_usec = 100000L; /* 100 ms */ + + res_multi_perform(multi, &handles); + if(res) + return res; + + res_test_timedout(); + if(res) + return res; + + if(!handles) + break; /* done */ FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); - curl_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); - /* In a real-world program you OF COURSE check the return code of the - function calls. On success, the value of maxfd is guaranteed to be - greater or equal than -1. We call select(maxfd + 1, ...), specially in - case of (maxfd == -1), we call select(0, ...), which is basically equal - to sleep. */ + res_multi_fdset(multi, &fdread, &fdwrite, &fdexcep, &maxfd); + if(res) + return res; + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - if (select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout) == -1) - return (CURLMcode) ~CURLM_OK; + res_select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &interval); + if(res) + return res; + + res_test_timedout(); + if(res) + return res; } - /* We only reach this point if (mp_timedout) */ - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - return (CURLMcode) ~CURLM_OK; + return 0; /* success */ } int test(char *URL) { - CURLM *multi; - CURL *easy; + CURLM *multi = NULL; + CURL *easy = NULL; int res = 0; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - if ((multi = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); - if ((easy = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_multi_cleanup(multi); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(multi); - curl_multi_setopt(multi, CURLMOPT_PIPELINING, 1L); + easy_init(easy); - test_setopt(easy, CURLOPT_WRITEFUNCTION, fwrite); - test_setopt(easy, CURLOPT_FAILONERROR, 1L); - test_setopt(easy, CURLOPT_URL, URL); + multi_setopt(multi, CURLMOPT_PIPELINING, 1L); - if (curl_multi_add_handle(multi, easy) != CURLM_OK) { - printf("curl_multi_add_handle() failed\n"); - res = TEST_ERR_MAJOR_BAD; - } else { - if (perform(multi) != CURLM_OK) - printf("retrieve 1 failed\n"); + easy_setopt(easy, CURLOPT_WRITEFUNCTION, fwrite); + easy_setopt(easy, CURLOPT_FAILONERROR, 1L); + easy_setopt(easy, CURLOPT_URL, URL); - curl_multi_remove_handle(multi, easy); + res_multi_add_handle(multi, easy); + if(res) { + printf("curl_multi_add_handle() 1 failed\n"); + goto test_cleanup; } + + res = perform(multi); + if(res) { + printf("retrieve 1 failed\n"); + goto test_cleanup; + } + + curl_multi_remove_handle(multi, easy); + curl_easy_reset(easy); - test_setopt(easy, CURLOPT_FAILONERROR, 1L); - test_setopt(easy, CURLOPT_URL, libtest_arg2); + easy_setopt(easy, CURLOPT_FAILONERROR, 1L); + easy_setopt(easy, CURLOPT_URL, libtest_arg2); - if (curl_multi_add_handle(multi, easy) != CURLM_OK) { + res_multi_add_handle(multi, easy); + if(res) { printf("curl_multi_add_handle() 2 failed\n"); - res = TEST_ERR_MAJOR_BAD; - } else { - if (perform(multi) != CURLM_OK) - printf("retrieve 2 failed\n"); + goto test_cleanup; + } - curl_multi_remove_handle(multi, easy); + res = perform(multi); + if(res) { + printf("retrieve 2 failed\n"); + goto test_cleanup; } + curl_multi_remove_handle(multi, easy); + test_cleanup: + /* undocumented cleanup sequence - type UB */ + curl_easy_cleanup(easy); curl_multi_cleanup(multi); curl_global_cleanup(); diff --git a/tests/libtest/lib537.c b/tests/libtest/lib537.c index 97119129b..24d252235 100644 --- a/tests/libtest/lib537.c +++ b/tests/libtest/lib537.c @@ -21,9 +21,6 @@ ***************************************************************************/ #include "test.h" -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif #ifdef HAVE_SYS_RESOURCE_H #include <sys/resource.h> #endif @@ -33,10 +30,8 @@ #ifdef HAVE_LIMITS_H #include <limits.h> #endif -#ifdef HAVE_STRING_H -#include <string.h> -#endif +#include "warnless.h" #include "memdebug.h" #if !defined(HAVE_POLL_FINE) && \ diff --git a/tests/libtest/lib540.c b/tests/libtest/lib540.c index 55457dd46..21d14872b 100644 --- a/tests/libtest/lib540.c +++ b/tests/libtest/lib540.c @@ -30,84 +30,111 @@ #include "test.h" +#include "testutil.h" #include "warnless.h" #include "memdebug.h" +#define TEST_HANG_TIMEOUT 60 * 1000 + #define PROXY libtest_arg2 #define PROXYUSERPWD libtest_arg3 #define HOST test_argv[4] -static int init(CURLM *cm, const char* url, const char* userpwd, +#define NUM_HANDLES 2 + +CURL *eh[NUM_HANDLES]; + +static int init(int num, CURLM *cm, const char* url, const char* userpwd, struct curl_slist *headers) { - CURL *eh; - int res; + int res = 0; - if ((eh = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - return 1; /* failure */ - } + res_easy_init(eh[num]); + if(res) + goto init_failed; - res = curl_easy_setopt(eh, CURLOPT_URL, url); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_PROXY, PROXY); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_PROXYUSERPWD, userpwd); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_VERBOSE, 1L); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_HEADER, 1L); - if(res) return 1; - res = curl_easy_setopt(eh, CURLOPT_HTTPHEADER, headers); /* custom Host: */ - if(res) return 1; - - if ((res = (int)curl_multi_add_handle(cm, eh)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - return 1; /* failure */ - } + res_easy_setopt(eh[num], CURLOPT_URL, url); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_PROXY, PROXY); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_PROXYUSERPWD, userpwd); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_PROXYAUTH, (long)CURLAUTH_ANY); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_VERBOSE, 1L); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_HEADER, 1L); + if(res) + goto init_failed; + + res_easy_setopt(eh[num], CURLOPT_HTTPHEADER, headers); /* custom Host: */ + if(res) + goto init_failed; + + res_multi_add_handle(cm, eh[num]); + if(res) + goto init_failed; return 0; /* success */ + +init_failed: + + curl_easy_cleanup(eh[num]); + eh[num] = NULL; + + return res; /* failure */ } -static int loop(CURLM *cm, const char* url, const char* userpwd, +static int loop(int num, CURLM *cm, const char* url, const char* userpwd, struct curl_slist *headers) { CURLMsg *msg; - CURLMcode code; long L; - int M, Q, U = -1; + int Q, U = -1; fd_set R, W, E; struct timeval T; + int res = 0; - if(init(cm, url, userpwd, headers)) - return 1; /* failure */ + res = init(num, cm, url, userpwd, headers); + if(res) + return res; while (U) { - do { - code = curl_multi_perform(cm, &U); - } while (code == CURLM_CALL_MULTI_PERFORM); + int M = -99; + + res_multi_perform(cm, &U); + if(res) + return res; + + res_test_timedout(); + if(res) + return res; if (U) { FD_ZERO(&R); FD_ZERO(&W); FD_ZERO(&E); - if (curl_multi_fdset(cm, &R, &W, &E, &M)) { - fprintf(stderr, "E: curl_multi_fdset\n"); - return 1; /* failure */ - } + res_multi_fdset(cm, &R, &W, &E, &M); + if(res) + return res; - /* In a real-world program you OF COURSE check the return that maxfd is - bigger than -1 so that the call to select() below makes sense! */ + /* At this point, M is guaranteed to be greater or equal than -1. */ - if (curl_multi_timeout(cm, &L)) { - fprintf(stderr, "E: curl_multi_timeout\n"); - return 1; /* failure */ - } + res_multi_timeout(cm, &L); + if(res) + return res; if(L != -1) { T.tv_sec = L/1000; @@ -118,24 +145,33 @@ static int loop(CURLM *cm, const char* url, const char* userpwd, T.tv_usec = 0; } - if (0 > select(M+1, &R, &W, &E, &T)) { - fprintf(stderr, "E: select\n"); - return 1; /* failure */ - } + res_select_test(M+1, &R, &W, &E, &T); + if(res) + return res; } - while ((msg = curl_multi_info_read(cm, &Q))) { - if (msg->msg == CURLMSG_DONE) { + while((msg = curl_multi_info_read(cm, &Q)) != NULL) { + if(msg->msg == CURLMSG_DONE) { + int i; CURL *e = msg->easy_handle; fprintf(stderr, "R: %d - %s\n", (int)msg->data.result, curl_easy_strerror(msg->data.result)); curl_multi_remove_handle(cm, e); curl_easy_cleanup(e); + for(i=0; i < NUM_HANDLES; i++) { + if(eh[i] == e) { + eh[i] = NULL; + break; + } + } } - else { + else fprintf(stderr, "E: CURLMsg (%d)\n", (int)msg->msg); - } } + + res_test_timedout(); + if(res) + return res; } return 0; /* success */ @@ -146,7 +182,13 @@ int test(char *URL) CURLM *cm = NULL; struct curl_slist *headers = NULL; char buffer[246]; /* naively fixed-size */ - int res; + int res = 0; + int i; + + for(i=0; i < NUM_HANDLES; i++) + eh[i] = NULL; + + start_test_timing(); if(test_argc < 4) return 99; @@ -160,30 +202,37 @@ int test(char *URL) return TEST_ERR_MAJOR_BAD; } - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); + res_global_init(CURL_GLOBAL_ALL); + if(res) { curl_slist_free_all(headers); - return TEST_ERR_MAJOR_BAD; + return res; } - if ((cm = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_slist_free_all(headers); + res_multi_init(cm); + if(res) { curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; + curl_slist_free_all(headers); + return res; } - res = loop(cm, URL, PROXYUSERPWD, headers); + res = loop(0, cm, URL, PROXYUSERPWD, headers); if(res) goto test_cleanup; fprintf(stderr, "lib540: now we do the request again\n"); - res = loop(cm, URL, PROXYUSERPWD, headers); + + res = loop(1, cm, URL, PROXYUSERPWD, headers); test_cleanup: - curl_multi_cleanup(cm); + /* proper cleanup sequence - type PB */ + for(i=0; i < NUM_HANDLES; i++) { + curl_multi_remove_handle(cm, eh[i]); + curl_easy_cleanup(eh[i]); + } + + curl_multi_cleanup(cm); curl_global_cleanup(); curl_slist_free_all(headers); diff --git a/tests/libtest/lib541.c b/tests/libtest/lib541.c index 6af7bc5cf..5fe8dd8ad 100644 --- a/tests/libtest/lib541.c +++ b/tests/libtest/lib541.c @@ -21,23 +21,10 @@ ***************************************************************************/ #include "test.h" -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - #include "memdebug.h" /* diff --git a/tests/libtest/lib542.c b/tests/libtest/lib542.c index efe8ea24e..84f493f3e 100644 --- a/tests/libtest/lib542.c +++ b/tests/libtest/lib542.c @@ -21,23 +21,10 @@ ***************************************************************************/ #include "test.h" -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - #include "memdebug.h" /* diff --git a/tests/libtest/lib554.c b/tests/libtest/lib554.c index ed8d13f05..d20429d91 100644 --- a/tests/libtest/lib554.c +++ b/tests/libtest/lib554.c @@ -40,6 +40,14 @@ struct WriteThis { static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) { +#ifdef LIB587 + (void)ptr; + (void)size; + (void)nmemb; + (void)userp; + return CURL_READFUNC_ABORT; +#else + struct WriteThis *pooh = (struct WriteThis *)userp; if(size*nmemb < 1) @@ -53,6 +61,7 @@ static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp) } return 0; /* no more data left to deliver */ +#endif } int test(char *URL) @@ -136,6 +145,16 @@ int test(char *URL) if(formrc) printf("curl_formadd(3) = %d\n", (int)formrc); + formrc = curl_formadd(&formpost, &lastptr, + CURLFORM_COPYNAME, "somename", + CURLFORM_BUFFER, "somefile.txt", + CURLFORM_BUFFERPTR, "blah blah", + CURLFORM_BUFFERLENGTH, 9, + CURLFORM_END); + + if(formrc) + printf("curl_formadd(4) = %d\n", (int)formrc); + if ((curl = curl_easy_init()) == NULL) { fprintf(stderr, "curl_easy_init() failed\n"); curl_formfree(formpost); diff --git a/tests/libtest/lib555.c b/tests/libtest/lib555.c index c67501521..49a81bf57 100644 --- a/tests/libtest/lib555.c +++ b/tests/libtest/lib555.c @@ -30,9 +30,10 @@ #include "test.h" #include "testutil.h" +#include "warnless.h" #include "memdebug.h" -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 #define UPLOADTHIS "this is the blurb we want to upload\n" @@ -74,95 +75,82 @@ static curlioerr ioctlcallback(CURL *handle, int test(char *URL) { - int res; - CURL *curl; + int res = 0; + CURL *curl = NULL; int counter=0; CURLM *m = NULL; int running=1; - struct timeval mp_start; - char mp_timedout = FALSE; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - if ((curl = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); + + easy_init(curl); - test_setopt(curl, CURLOPT_URL, URL); - test_setopt(curl, CURLOPT_VERBOSE, 1L); - test_setopt(curl, CURLOPT_HEADER, 1L); + easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_HEADER, 1L); /* read the POST data from a callback */ - test_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctlcallback); - test_setopt(curl, CURLOPT_IOCTLDATA, &counter); - test_setopt(curl, CURLOPT_READFUNCTION, readcallback); - test_setopt(curl, CURLOPT_READDATA, &counter); + easy_setopt(curl, CURLOPT_IOCTLFUNCTION, ioctlcallback); + easy_setopt(curl, CURLOPT_IOCTLDATA, &counter); + easy_setopt(curl, CURLOPT_READFUNCTION, readcallback); + easy_setopt(curl, CURLOPT_READDATA, &counter); /* We CANNOT do the POST fine without setting the size (or choose chunked)! */ - test_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(UPLOADTHIS)); + easy_setopt(curl, CURLOPT_POSTFIELDSIZE, strlen(UPLOADTHIS)); - test_setopt(curl, CURLOPT_POST, 1L); + easy_setopt(curl, CURLOPT_POST, 1L); #ifdef CURL_DOES_CONVERSIONS /* Convert the POST data to ASCII. */ - test_setopt(curl, CURLOPT_TRANSFERTEXT, 1L); + easy_setopt(curl, CURLOPT_TRANSFERTEXT, 1L); #endif - test_setopt(curl, CURLOPT_PROXY, libtest_arg2); - test_setopt(curl, CURLOPT_PROXYUSERPWD, libtest_arg3); - test_setopt(curl, CURLOPT_PROXYAUTH, + easy_setopt(curl, CURLOPT_PROXY, libtest_arg2); + easy_setopt(curl, CURLOPT_PROXYUSERPWD, libtest_arg3); + easy_setopt(curl, CURLOPT_PROXYAUTH, (long) (CURLAUTH_NTLM | CURLAUTH_DIGEST | CURLAUTH_BASIC) ); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } - - mp_timedout = FALSE; - mp_start = tutil_tvnow(); + multi_add_handle(m, curl); while (running) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } + struct timeval timeout; + fd_set fdread, fdwrite, fdexcep; + int maxfd = -99; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000L; /* 100 ms */ + + multi_perform(m, &running); + + abort_on_test_timeout(); + #ifdef TPF sleep(1); /* avoid ctl-10 dump */ #endif - if (running <= 0) { - fprintf(stderr, "nothing left running.\n"); - break; - } - } - if (mp_timedout) { - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + if(!running) + break; /* done */ + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + multi_fdset(m, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); } test_cleanup: - if(m) { - curl_multi_remove_handle(m, curl); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + + curl_multi_remove_handle(m, curl); + curl_multi_cleanup(m); curl_easy_cleanup(curl); curl_global_cleanup(); diff --git a/tests/libtest/lib560.c b/tests/libtest/lib560.c index e375be535..e8be1c7bd 100644 --- a/tests/libtest/lib560.c +++ b/tests/libtest/lib560.c @@ -21,7 +21,11 @@ ***************************************************************************/ #include "test.h" +#include "testutil.h" #include "warnless.h" +#include "memdebug.h" + +#define TEST_HANG_TIMEOUT 60 * 1000 /* * Simply download a HTTPS file! @@ -35,46 +39,44 @@ */ int test(char *URL) { - CURL *http_handle; + CURL *http_handle = NULL; CURLM *multi_handle = NULL; - CURLMcode code; - int res; + int res = 0; int still_running; /* keep number of running handles */ - http_handle = curl_easy_init(); - if (!http_handle) - return TEST_ERR_MAJOR_BAD; + start_test_timing(); + + /* + ** curl_global_init called indirectly from curl_easy_init. + */ + + easy_init(http_handle); /* set options */ - test_setopt(http_handle, CURLOPT_URL, URL); - test_setopt(http_handle, CURLOPT_HEADER, 1L); - test_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, 0L); - test_setopt(http_handle, CURLOPT_SSL_VERIFYHOST, 0L); + easy_setopt(http_handle, CURLOPT_URL, URL); + easy_setopt(http_handle, CURLOPT_HEADER, 1L); + easy_setopt(http_handle, CURLOPT_SSL_VERIFYPEER, 0L); + easy_setopt(http_handle, CURLOPT_SSL_VERIFYHOST, 0L); /* init a multi stack */ - multi_handle = curl_multi_init(); - if (!multi_handle) { - curl_easy_cleanup(http_handle); - return TEST_ERR_MAJOR_BAD; - } + multi_init(multi_handle); /* add the individual transfers */ - curl_multi_add_handle(multi_handle, http_handle); + multi_add_handle(multi_handle, http_handle); /* we start some action by calling perform right away */ - do { - code = curl_multi_perform(multi_handle, &still_running); - } while(code == CURLM_CALL_MULTI_PERFORM); + multi_perform(multi_handle, &still_running); + + abort_on_test_timeout(); while(still_running) { struct timeval timeout; - int rc; /* select() return code */ fd_set fdread; fd_set fdwrite; fd_set fdexcep; - int maxfd; + int maxfd = -99; FD_ZERO(&fdread); FD_ZERO(&fdwrite); @@ -85,33 +87,25 @@ int test(char *URL) timeout.tv_usec = 0; /* get file descriptors from the transfers */ - curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); - - /* In a real-world program you OF COURSE check the return code of the - function calls, *and* you make sure that maxfd is bigger than -1 so - that the call to select() below makes sense! */ - - rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); - - switch(rc) { - case -1: - /* select error */ - break; - case 0: - default: - /* timeout or readable/writable sockets */ - do { - code = curl_multi_perform(multi_handle, &still_running); - } while(code == CURLM_CALL_MULTI_PERFORM); - break; - } + multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); + + /* timeout or readable/writable sockets */ + multi_perform(multi_handle, &still_running); + + abort_on_test_timeout(); } test_cleanup: - if(multi_handle) - curl_multi_cleanup(multi_handle); + /* undocumented cleanup sequence - type UA */ + curl_multi_cleanup(multi_handle); curl_easy_cleanup(http_handle); curl_global_cleanup(); diff --git a/tests/libtest/lib562.c b/tests/libtest/lib562.c index 657a2d3cd..a5f0ea534 100644 --- a/tests/libtest/lib562.c +++ b/tests/libtest/lib562.c @@ -19,26 +19,12 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" -#ifdef HAVE_SYS_SOCKET_H -#include <sys/socket.h> -#endif -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_SYS_STAT_H -#include <sys/stat.h> -#endif #ifdef HAVE_FCNTL_H #include <fcntl.h> #endif -#ifdef HAVE_UNISTD_H -#include <unistd.h> -#endif - #include "memdebug.h" /* diff --git a/tests/libtest/lib564.c b/tests/libtest/lib564.c index d831d21e1..ed00e1bf6 100644 --- a/tests/libtest/lib564.c +++ b/tests/libtest/lib564.c @@ -19,138 +19,74 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 int test(char *URL) { int res = 0; - CURL *curl; + CURL *curl = NULL; int running; - char done=FALSE; CURLM *m = NULL; - struct timeval ml_start; - struct timeval mp_start; - char ml_timedout = FALSE; - char mp_timedout = FALSE; - - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } - if ((curl = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - test_setopt(curl, CURLOPT_URL, URL); - test_setopt(curl, CURLOPT_VERBOSE, 1); - test_setopt(curl, CURLOPT_PROXY, libtest_arg2); - test_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); + global_init(CURL_GLOBAL_ALL); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(curl); - if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(curl); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_PROXY, libtest_arg2); + easy_setopt(curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); + + multi_init(m); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, curl); fprintf(stderr, "Start at URL 0\n"); - while (!done) { - fd_set rd, wr, exc; - int max_fd; + for(;;) { struct timeval interval; + fd_set rd, wr, exc; + int maxfd = -99; interval.tv_sec = 1; interval.tv_usec = 0; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - mp_timedout = FALSE; - mp_start = tutil_tvnow(); - - while (res == CURLM_CALL_MULTI_PERFORM) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - done = TRUE; /* bail out */ - break; - } - } - if (mp_timedout || done) - break; - - if (res != CURLM_OK) { - fprintf(stderr, "not okay???\n"); - break; - } + multi_perform(m, &running); + + abort_on_test_timeout(); + + if(!running) + break; /* done */ FD_ZERO(&rd); FD_ZERO(&wr); FD_ZERO(&exc); - max_fd = 0; - if (curl_multi_fdset(m, &rd, &wr, &exc, &max_fd) != CURLM_OK) { - fprintf(stderr, "unexpected failured of fdset.\n"); - res = 189; - break; - } + multi_fdset(m, &rd, &wr, &exc, &maxfd); - if (select_test(max_fd+1, &rd, &wr, &exc, &interval) == -1) { - fprintf(stderr, "bad select??\n"); - res = 195; - break; - } + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ - res = CURLM_CALL_MULTI_PERFORM; - } + select_test(maxfd+1, &rd, &wr, &exc, &interval); - if (ml_timedout || mp_timedout) { - if (ml_timedout) fprintf(stderr, "ml_timedout\n"); - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); } test_cleanup: + /* undocumented cleanup sequence - type UB */ + curl_easy_cleanup(curl); - if(m) - curl_multi_cleanup(m); + curl_multi_cleanup(m); curl_global_cleanup(); return res; diff --git a/tests/libtest/lib566.c b/tests/libtest/lib566.c index 4aa6d98e9..ba839d65f 100644 --- a/tests/libtest/lib566.c +++ b/tests/libtest/lib566.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include "memdebug.h" diff --git a/tests/libtest/lib567.c b/tests/libtest/lib567.c index 7466e7475..573529cd8 100644 --- a/tests/libtest/lib567.c +++ b/tests/libtest/lib567.c @@ -19,8 +19,8 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" + #include "memdebug.h" /* diff --git a/tests/libtest/lib568.c b/tests/libtest/lib568.c index df0cd88d1..4b15821f2 100644 --- a/tests/libtest/lib568.c +++ b/tests/libtest/lib568.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #ifdef HAVE_SYS_STAT_H diff --git a/tests/libtest/lib569.c b/tests/libtest/lib569.c index 366e4c344..a434d7459 100644 --- a/tests/libtest/lib569.c +++ b/tests/libtest/lib569.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include <curl/mprintf.h> diff --git a/tests/libtest/lib570.c b/tests/libtest/lib570.c index 29d30dbef..a9fac9915 100644 --- a/tests/libtest/lib570.c +++ b/tests/libtest/lib570.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include <curl/mprintf.h> diff --git a/tests/libtest/lib571.c b/tests/libtest/lib571.c index 1b2bf7b74..c5f7240d0 100644 --- a/tests/libtest/lib571.c +++ b/tests/libtest/lib571.c @@ -19,12 +19,8 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" -#ifdef HAVE_SYS_SOCKET_H -# include <sys/socket.h> -#endif #ifdef HAVE_NETINET_IN_H # include <netinet/in.h> #endif diff --git a/tests/libtest/lib572.c b/tests/libtest/lib572.c index b54877cd4..3df4d036a 100644 --- a/tests/libtest/lib572.c +++ b/tests/libtest/lib572.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #ifdef HAVE_SYS_STAT_H diff --git a/tests/libtest/lib573.c b/tests/libtest/lib573.c index 466185844..943f6e8c8 100644 --- a/tests/libtest/lib573.c +++ b/tests/libtest/lib573.c @@ -19,14 +19,13 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include "testutil.h" +#include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 90 * 1000 -#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 /* * Get a single URL without select(). @@ -34,65 +33,51 @@ int test(char *URL) { - CURL *c; + CURL *c = NULL; CURLM *m = NULL; int res = 0; - int running=1; + int running = 1; double connect_time = 0.0; - struct timeval mp_start; - char mp_timedout = FALSE; - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); - return TEST_ERR_MAJOR_BAD; - } + start_test_timing(); - if ((c = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + global_init(CURL_GLOBAL_ALL); - test_setopt(c, CURLOPT_HEADER, 1L); - test_setopt(c, CURLOPT_URL, URL); + easy_init(c); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_setopt(c, CURLOPT_HEADER, 1L); + easy_setopt(c, CURLOPT_URL, URL); - if ((res = (int)curl_multi_add_handle(m, c)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(c); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); - mp_timedout = FALSE; - mp_start = tutil_tvnow(); + multi_add_handle(m, c); while (running) { - res = (int)curl_multi_perform(m, &running); - if (tutil_tvdiff(tutil_tvnow(), mp_start) > - MULTI_PERFORM_HANG_TIMEOUT) { - mp_timedout = TRUE; - break; - } - if (running <= 0) { - fprintf(stderr, "nothing left running.\n"); - break; - } - } + struct timeval timeout; + fd_set fdread, fdwrite, fdexcep; + int maxfd = -99; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000L; /* 100 ms */ + + multi_perform(m, &running); - if (mp_timedout) { - if (mp_timedout) fprintf(stderr, "mp_timedout\n"); - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; + abort_on_test_timeout(); + + if(!running) + break; /* done */ + + FD_ZERO(&fdread); + FD_ZERO(&fdwrite); + FD_ZERO(&fdexcep); + + multi_fdset(m, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); } curl_easy_getinfo(c, CURLINFO_CONNECT_TIME, &connect_time); @@ -103,10 +88,10 @@ int test(char *URL) test_cleanup: - if(m) { - curl_multi_remove_handle(m, c); - curl_multi_cleanup(m); - } + /* proper cleanup sequence - type PA */ + + curl_multi_remove_handle(m, c); + curl_multi_cleanup(m); curl_easy_cleanup(c); curl_global_cleanup(); diff --git a/tests/libtest/lib574.c b/tests/libtest/lib574.c index 8c5781609..afb2bceae 100644 --- a/tests/libtest/lib574.c +++ b/tests/libtest/lib574.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include "memdebug.h" diff --git a/tests/libtest/lib575.c b/tests/libtest/lib575.c index 4d0b16576..942df68c5 100644 --- a/tests/libtest/lib575.c +++ b/tests/libtest/lib575.c @@ -19,17 +19,16 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" +#define TEST_HANG_TIMEOUT 60 * 1000 + /* 3x download! * 1. normal * 2. dup handle @@ -38,26 +37,21 @@ int test(char *URL) { - CURLMcode m; - CURL *handle = NULL, *duphandle; + CURL *handle = NULL; + CURL *duphandle = NULL; CURLM *mhandle = NULL; int res = 0; int still_running = 0; - if(curl_global_init(CURL_GLOBAL_ALL)) { - fprintf(stderr, "curl_global_init() failed\n"); - goto test_cleanup; - } + start_test_timing(); - handle = curl_easy_init(); - if(!handle) { - res = CURLE_OUT_OF_MEMORY; - goto test_cleanup; - } + global_init(CURL_GLOBAL_ALL); - test_setopt(handle, CURLOPT_URL, URL); - test_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); - test_setopt(handle, CURLOPT_VERBOSE, 1L); + easy_init(handle); + + easy_setopt(handle, CURLOPT_URL, URL); + easy_setopt(handle, CURLOPT_WILDCARDMATCH, 1L); + easy_setopt(handle, CURLOPT_VERBOSE, 1L); res = curl_easy_perform(handle); if(res) @@ -73,51 +67,48 @@ int test(char *URL) curl_easy_cleanup(handle); handle = duphandle; - mhandle = curl_multi_init(); - if(!mhandle) { - fprintf(stderr, "curl_multi_init() failed\n"); - goto test_cleanup; - } + multi_init(mhandle); - curl_multi_add_handle(mhandle, handle); + multi_add_handle(mhandle, handle); - while(CURLM_CALL_MULTI_PERFORM == - curl_multi_perform(mhandle, &still_running)); + multi_perform(mhandle, &still_running); + + abort_on_test_timeout(); while(still_running) { - static struct timeval timeout = /* 100 ms */ { 0, 100000L }; - int rc; + struct timeval timeout; fd_set fdread; fd_set fdwrite; fd_set fdexcep; - int max_fdset = -1; + int maxfd = -99; + + timeout.tv_sec = 0; + timeout.tv_usec = 100000L; /* 100 ms */ + FD_ZERO(&fdread); FD_ZERO(&fdwrite); FD_ZERO(&fdexcep); - m = curl_multi_fdset(mhandle, &fdread, &fdwrite, &fdexcep, &max_fdset); - if(m != CURLM_OK) { - fprintf(stderr, "curl_multi_fdset() error\n"); - goto test_cleanup; - } - /* We call select(max_fdset + 1, ...), specially in case of (maxfd == -1), - * we call select(0, ...), which is basically equal to sleep. */ - rc = select(max_fdset + 1, &fdread, &fdwrite, &fdexcep, &timeout); - if(rc == -1) { - fprintf(stderr, "select() error\n"); - goto test_cleanup; - } - else { - while(CURLM_CALL_MULTI_PERFORM == - curl_multi_perform(mhandle, &still_running)); - } + multi_fdset(mhandle, &fdread, &fdwrite, &fdexcep, &maxfd); + + /* At this point, maxfd is guaranteed to be greater or equal than -1. */ + + select_test(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout); + + abort_on_test_timeout(); + + multi_perform(mhandle, &still_running); + + abort_on_test_timeout(); } test_cleanup: - if(mhandle) - curl_multi_cleanup(mhandle); - if(handle) - curl_easy_cleanup(handle); + + /* undocumented cleanup sequence - type UA */ + + curl_multi_cleanup(mhandle); + curl_easy_cleanup(handle); curl_global_cleanup(); + return res; } diff --git a/tests/libtest/lib576.c b/tests/libtest/lib576.c index 48841b59d..61bb61325 100644 --- a/tests/libtest/lib576.c +++ b/tests/libtest/lib576.c @@ -19,8 +19,8 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" + #include "testutil.h" #include "memdebug.h" diff --git a/tests/libtest/lib578.c b/tests/libtest/lib578.c index 51ead8722..a39b31772 100644 --- a/tests/libtest/lib578.c +++ b/tests/libtest/lib578.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include "memdebug.h" diff --git a/tests/libtest/lib579.c b/tests/libtest/lib579.c index ad8ba7e97..56193a181 100644 --- a/tests/libtest/lib579.c +++ b/tests/libtest/lib579.c @@ -19,7 +19,6 @@ * KIND, either express or implied. * ***************************************************************************/ - #include "test.h" #include "memdebug.h" diff --git a/tests/libtest/lib582.c b/tests/libtest/lib582.c index 3b7f1afee..25b70609c 100644 --- a/tests/libtest/lib582.c +++ b/tests/libtest/lib582.c @@ -21,20 +21,19 @@ ***************************************************************************/ #include "test.h" -#include <sys/types.h> -#include <sys/stat.h> #include <fcntl.h> #include "testutil.h" #include "warnless.h" #include "memdebug.h" -#define MAIN_LOOP_HANG_TIMEOUT 4 * 1000 +#define TEST_HANG_TIMEOUT 60 * 1000 struct Sockets { - curl_socket_t* sockets; - int count; + curl_socket_t *sockets; + int count; /* number of sockets actually stored in array */ + int max_count; /* max number of sockets that fit in allocated array */ }; struct ReadWriteSockets @@ -54,8 +53,9 @@ static void removeFd(struct Sockets* sockets, curl_socket_t fd, int mention) for (i = 0; i < sockets->count; ++i) { if (sockets->sockets[i] == fd) { - memmove(&sockets->sockets[i], &sockets->sockets[i + 1], - sizeof(curl_socket_t) * (sockets->count - i - 1)); + if (i < sockets->count - 1) + memmove(&sockets->sockets[i], &sockets->sockets[i + 1], + sizeof(curl_socket_t) * (sockets->count - (i + 1))); --sockets->count; } } @@ -72,8 +72,29 @@ static void addFd(struct Sockets* sockets, curl_socket_t fd, const char *what) */ fprintf(stderr, "Add socket fd %d for %s\n", (int) fd, what); removeFd(sockets, fd, 0); - sockets->sockets = realloc(sockets->sockets, - sizeof(curl_socket_t) * (sockets->count + 1)); + /* + * Allocate array storage when required. + */ + if(!sockets->sockets) { + sockets->sockets = malloc(sizeof(curl_socket_t) * 20U); + if(!sockets->sockets) + return; + sockets->max_count = 20; + } + else if(sockets->count + 1 > sockets->max_count) { + curl_socket_t *oldptr = sockets->sockets; + sockets->sockets = realloc(oldptr, sizeof(curl_socket_t) * + (sockets->max_count + 20)); + if(!sockets->sockets) { + /* cleanup in test_cleanup */ + sockets->sockets = oldptr; + return; + } + sockets->max_count += 20; + } + /* + * Add file descriptor to array. + */ sockets->sockets[sockets->count] = fd; ++sockets->count; } @@ -177,13 +198,12 @@ static void updateFdSet(struct Sockets* sockets, fd_set* fdset, } } -static void notifyCurl(CURL* curl, curl_socket_t s, int evBitmask, - const char* info) +static void notifyCurl(CURLM *curl, curl_socket_t s, int evBitmask, + const char *info) { int numhandles = 0; CURLMcode result = curl_multi_socket_action(curl, s, evBitmask, &numhandles); - if (result != CURLM_OK && result != CURLM_CALL_MULTI_PERFORM) - { + if (result != CURLM_OK) { fprintf(stderr, "Curl error on %s: %i (%s)\n", info, result, curl_multi_strerror(result)); } @@ -192,14 +212,12 @@ static void notifyCurl(CURL* curl, curl_socket_t s, int evBitmask, /** * Invoke curl when a file descriptor is set. */ -static void checkFdSet(CURL* curl, struct Sockets* sockets, fd_set* fdset, - int evBitmask, const char* name) +static void checkFdSet(CURLM *curl, struct Sockets *sockets, fd_set *fdset, + int evBitmask, const char *name) { int i; - for (i = 0; i < sockets->count; ++i) - { - if (FD_ISSET(sockets->sockets[i], fdset)) - { + for (i = 0; i < sockets->count; ++i) { + if (FD_ISSET(sockets->sockets[i], fdset)) { notifyCurl(curl, sockets->sockets[i], evBitmask, name); } } @@ -208,30 +226,30 @@ static void checkFdSet(CURL* curl, struct Sockets* sockets, fd_set* fdset, int test(char *URL) { int res = 0; - CURL *curl; - FILE *hd_src ; + CURL *curl = NULL; + FILE *hd_src = NULL; int hd ; int error; struct_stat file_info; CURLM *m = NULL; - struct timeval ml_start; - char ml_timedout = FALSE; - struct ReadWriteSockets sockets = {{0, 0}, {0, 0}}; + struct ReadWriteSockets sockets = {{NULL, 0, 0}, {NULL, 0, 0}}; struct timeval timeout = {-1, 0}; int success = 0; + start_test_timing(); + if (!libtest_arg3) { fprintf(stderr, "Usage: lib582 [url] [filename] [username]\n"); - return -1; + return TEST_ERR_USAGE; } hd_src = fopen(libtest_arg2, "rb"); if(NULL == hd_src) { error = ERRNO; - fprintf(stderr, "fopen() failed with error: %d %s\n", + fprintf(stderr, "fopen() failed with error: %d (%s)\n", error, strerror(error)); - fprintf(stderr, "Error opening file: %s\n", libtest_arg2); - return TEST_ERR_MAJOR_BAD; + fprintf(stderr, "Error opening file: (%s)\n", libtest_arg2); + return TEST_ERR_FOPEN; } /* get the file size of the local file */ @@ -239,71 +257,49 @@ int test(char *URL) if(hd == -1) { /* can't open file, bail out */ error = ERRNO; - fprintf(stderr, "fstat() failed with error: %d %s\n", + fprintf(stderr, "fstat() failed with error: %d (%s)\n", error, strerror(error)); - fprintf(stderr, "ERROR: cannot open file %s\n", libtest_arg2); + fprintf(stderr, "ERROR: cannot open file (%s)\n", libtest_arg2); fclose(hd_src); - return -1; + return TEST_ERR_FSTAT; } fprintf(stderr, "Set to upload %d bytes\n", (int)file_info.st_size); - if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { - fprintf(stderr, "curl_global_init() failed\n"); + res_global_init(CURL_GLOBAL_ALL); + if(res) { fclose(hd_src); - return TEST_ERR_MAJOR_BAD; + return res; } - if ((curl = curl_easy_init()) == NULL) { - fprintf(stderr, "curl_easy_init() failed\n"); - fclose(hd_src); - curl_global_cleanup(); - return TEST_ERR_MAJOR_BAD; - } + easy_init(curl); /* enable uploading */ - test_setopt(curl, CURLOPT_UPLOAD, 1L); + easy_setopt(curl, CURLOPT_UPLOAD, 1L); /* specify target */ - test_setopt(curl,CURLOPT_URL, URL); + easy_setopt(curl,CURLOPT_URL, URL); /* go verbose */ - test_setopt(curl, CURLOPT_VERBOSE, 1L); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); /* now specify which file to upload */ - test_setopt(curl, CURLOPT_READDATA, hd_src); + easy_setopt(curl, CURLOPT_READDATA, hd_src); - test_setopt(curl, CURLOPT_USERPWD, libtest_arg3); - test_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub"); - test_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key"); + easy_setopt(curl, CURLOPT_USERPWD, libtest_arg3); + easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub"); + easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key"); - test_setopt(curl, CURLOPT_INFILESIZE_LARGE, - (curl_off_t)file_info.st_size); + easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); - if ((m = curl_multi_init()) == NULL) { - fprintf(stderr, "curl_multi_init() failed\n"); - curl_easy_cleanup(curl); - curl_global_cleanup(); - fclose(hd_src); - return TEST_ERR_MAJOR_BAD; - } - test_multi_setopt(m, CURLMOPT_SOCKETFUNCTION, curlSocketCallback); - test_multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets); - - test_multi_setopt(m, CURLMOPT_TIMERFUNCTION, curlTimerCallback); - test_multi_setopt(m, CURLMOPT_TIMERDATA, &timeout); - - if ((res = (int)curl_multi_add_handle(m, curl)) != CURLM_OK) { - fprintf(stderr, "curl_multi_add_handle() failed, " - "with code %d\n", res); - curl_multi_cleanup(m); - curl_easy_cleanup(curl); - curl_global_cleanup(); - fclose(hd_src); - return TEST_ERR_MAJOR_BAD; - } + multi_init(m); + + multi_setopt(m, CURLMOPT_SOCKETFUNCTION, curlSocketCallback); + multi_setopt(m, CURLMOPT_SOCKETDATA, &sockets); + + multi_setopt(m, CURLMOPT_TIMERFUNCTION, curlTimerCallback); + multi_setopt(m, CURLMOPT_TIMERDATA, &timeout); - ml_timedout = FALSE; - ml_start = tutil_tvnow(); + multi_add_handle(m, curl); while (!checkForCompletion(m, &success)) { @@ -311,12 +307,6 @@ int test(char *URL) curl_socket_t maxFd = 0; struct timeval tv = {10, 0}; - if (tutil_tvdiff(tutil_tvnow(), ml_start) > - MAIN_LOOP_HANG_TIMEOUT) { - ml_timedout = TRUE; - break; - } - FD_ZERO(&readSet); FD_ZERO(&writeSet); updateFdSet(&sockets.read, &readSet, &maxFd); @@ -345,6 +335,8 @@ int test(char *URL) /* Curl's timer has elapsed. */ notifyCurl(m, CURL_SOCKET_TIMEOUT, 0, "timeout"); } + + abort_on_test_timeout(); } if (!success) @@ -352,28 +344,24 @@ int test(char *URL) fprintf(stderr, "Error uploading file.\n"); res = TEST_ERR_MAJOR_BAD; } - else if (ml_timedout) { - fprintf(stderr, "ABORTING TEST, since it seems " - "that it would have run forever.\n"); - res = TEST_ERR_RUNS_FOREVER; - } test_cleanup: - if(m) - curl_multi_remove_handle(m, curl); + /* proper cleanup sequence - type PB */ + + curl_multi_remove_handle(m, curl); curl_easy_cleanup(curl); - if(m) { - fprintf(stderr, "Now multi-cleanup!\n"); - curl_multi_cleanup(m); - } + curl_multi_cleanup(m); + curl_global_cleanup(); + + /* close the local file */ + fclose(hd_src); - fclose(hd_src); /* close the local file */ - if (sockets.read.sockets != 0) + /* free local memory */ + if(sockets.read.sockets) free(sockets.read.sockets); - if (sockets.write.sockets != 0) + if(sockets.write.sockets) free(sockets.write.sockets); - curl_global_cleanup(); return res; } diff --git a/tests/libtest/lib583.c b/tests/libtest/lib583.c index f1270e1d3..ad5a5cea7 100644 --- a/tests/libtest/lib583.c +++ b/tests/libtest/lib583.c @@ -26,48 +26,59 @@ #include "test.h" -#include <unistd.h> #include <sys/stat.h> +#include "memdebug.h" + int test(char *URL) { - CURLMcode retVal; int stillRunning; - CURLM* multiHandle; - CURL* curl; - int res; + CURLM* multiHandle = NULL; + CURL* curl = NULL; + int res = 0; + + global_init(CURL_GLOBAL_ALL); + + multi_init(multiHandle); + + easy_init(curl); - curl_global_init(CURL_GLOBAL_ALL); + easy_setopt(curl, CURLOPT_USERPWD, libtest_arg2); + easy_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub"); + easy_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key"); - multiHandle = curl_multi_init(); - curl = curl_easy_init(); + easy_setopt(curl, CURLOPT_UPLOAD, 1L); + easy_setopt(curl, CURLOPT_VERBOSE, 1L); - test_setopt(curl, CURLOPT_USERPWD, libtest_arg2); - test_setopt(curl, CURLOPT_SSH_PUBLIC_KEYFILE, "curl_client_key.pub"); - test_setopt(curl, CURLOPT_SSH_PRIVATE_KEYFILE, "curl_client_key"); + easy_setopt(curl, CURLOPT_URL, URL); + easy_setopt(curl, CURLOPT_INFILESIZE, (long)5); - curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); + multi_add_handle(multiHandle, curl); - curl_easy_setopt(curl, CURLOPT_URL, URL); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, (long)5); + /* this tests if removing an easy handle immediately after multi + perform has been called succeeds or not. */ - curl_multi_add_handle(multiHandle, curl); - retVal = curl_multi_perform(multiHandle, &stillRunning); - if (retVal != CURLM_OK) - fprintf(stderr, "curl_multi_perform() failed!n"); + fprintf(stderr, "curl_multi_perform()...\n"); - fprintf(stderr, "curl_multi_remove_handle()!\n"); - retVal = curl_multi_remove_handle(multiHandle, curl); - if (retVal == CURLM_OK) - fprintf(stderr, "curl_multi_remove_handle() was successful!\n"); + multi_perform(multiHandle, &stillRunning); + + fprintf(stderr, "curl_multi_perform() succeeded\n"); + + fprintf(stderr, "curl_multi_remove_handle()...\n"); + res = (int) curl_multi_remove_handle(multiHandle, curl); + if(res) + fprintf(stderr, "curl_multi_remove_handle() failed, " + "with code %d\n", res); else - fprintf(stderr, "curl_multi_remove_handle() failed\n"); + fprintf(stderr, "curl_multi_remove_handle() succeeded\n"); test_cleanup: + /* undocumented cleanup sequence - type UB */ + curl_easy_cleanup(curl); curl_multi_cleanup(multiHandle); + curl_global_cleanup(); return res; } diff --git a/tests/libtest/lib586.c b/tests/libtest/lib586.c new file mode 100644 index 000000000..2cf04fe85 --- /dev/null +++ b/tests/libtest/lib586.c @@ -0,0 +1,246 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ +#include "test.h" + +#include <curl/mprintf.h> + +#include "memdebug.h" + +#define THREADS 2 + +/* struct containing data of a thread */ +struct Tdata { + CURLSH *share; + char *url; +}; + +struct userdata { + char *text; + int counter; +}; + +/* lock callback */ +static void my_lock(CURL *handle, curl_lock_data data, curl_lock_access laccess, + void *useptr ) +{ + const char *what; + struct userdata *user = (struct userdata *)useptr; + + (void)handle; + (void)laccess; + + switch ( data ) { + case CURL_LOCK_DATA_SHARE: + what = "share"; + break; + case CURL_LOCK_DATA_DNS: + what = "dns"; + break; + case CURL_LOCK_DATA_COOKIE: + what = "cookie"; + break; + case CURL_LOCK_DATA_SSL_SESSION: + what = "ssl_session"; + break; + default: + fprintf(stderr, "lock: no such data: %d\n", (int)data); + return; + } + printf("lock: %-6s [%s]: %d\n", what, user->text, user->counter); + user->counter++; +} + +/* unlock callback */ +static void my_unlock(CURL *handle, curl_lock_data data, void *useptr ) +{ + const char *what; + struct userdata *user = (struct userdata *)useptr; + (void)handle; + switch ( data ) { + case CURL_LOCK_DATA_SHARE: + what = "share"; + break; + case CURL_LOCK_DATA_DNS: + what = "dns"; + break; + case CURL_LOCK_DATA_COOKIE: + what = "cookie"; + break; + case CURL_LOCK_DATA_SSL_SESSION: + what = "ssl_session"; + break; + default: + fprintf(stderr, "unlock: no such data: %d\n", (int)data); + return; + } + printf("unlock: %-6s [%s]: %d\n", what, user->text, user->counter); + user->counter++; +} + +/* the dummy thread function */ +static void *fire(void *ptr) +{ + CURLcode code; + struct Tdata *tdata = (struct Tdata*)ptr; + CURL *curl; + int i=0; + + if ((curl = curl_easy_init()) == NULL) { + fprintf(stderr, "curl_easy_init() failed\n"); + return NULL; + } + + curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); + curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); + curl_easy_setopt(curl, CURLOPT_URL, tdata->url); + printf( "CURLOPT_SHARE\n" ); + curl_easy_setopt(curl, CURLOPT_SHARE, tdata->share); + + printf( "PERFORM\n" ); + code = curl_easy_perform(curl); + if( code != CURLE_OK ) { + fprintf(stderr, "perform url '%s' repeat %d failed, curlcode %d\n", + tdata->url, i, (int)code); + } + + printf( "CLEANUP\n" ); + curl_easy_cleanup(curl); + + return NULL; +} + +/* test function */ +int test(char *URL) +{ + int res; + CURLSHcode scode = CURLSHE_OK; + char *url; + struct Tdata tdata; + CURL *curl; + CURLSH *share; + int i; + struct userdata user; + + user.text = (char *)"Pigs in space"; + user.counter = 0; + + printf( "GLOBAL_INIT\n" ); + if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { + fprintf(stderr, "curl_global_init() failed\n"); + return TEST_ERR_MAJOR_BAD; + } + + /* prepare share */ + printf( "SHARE_INIT\n" ); + if ((share = curl_share_init()) == NULL) { + fprintf(stderr, "curl_share_init() failed\n"); + curl_global_cleanup(); + return TEST_ERR_MAJOR_BAD; + } + + if ( CURLSHE_OK == scode ) { + printf( "CURLSHOPT_LOCKFUNC\n" ); + scode = curl_share_setopt( share, CURLSHOPT_LOCKFUNC, my_lock); + } + if ( CURLSHE_OK == scode ) { + printf( "CURLSHOPT_UNLOCKFUNC\n" ); + scode = curl_share_setopt( share, CURLSHOPT_UNLOCKFUNC, my_unlock); + } + if ( CURLSHE_OK == scode ) { + printf( "CURLSHOPT_USERDATA\n" ); + scode = curl_share_setopt( share, CURLSHOPT_USERDATA, &user); + } + if ( CURLSHE_OK == scode ) { + printf( "CURL_LOCK_DATA_SSL_SESSION\n" ); + scode = curl_share_setopt( share, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION); + } + + if ( CURLSHE_OK != scode ) { + fprintf(stderr, "curl_share_setopt() failed\n"); + curl_share_cleanup(share); + curl_global_cleanup(); + return TEST_ERR_MAJOR_BAD; + } + + + res = 0; + + /* start treads */ + for (i=1; i<=THREADS; i++ ) { + + /* set thread data */ + tdata.url = URL; + tdata.share = share; + + /* simulate thread, direct call of "thread" function */ + printf( "*** run %d\n",i ); + fire( &tdata ); + } + + + /* fetch a another one */ + printf( "*** run %d\n", i ); + if ((curl = curl_easy_init()) == NULL) { + fprintf(stderr, "curl_easy_init() failed\n"); + curl_share_cleanup(share); + curl_global_cleanup(); + return TEST_ERR_MAJOR_BAD; + } + + url = URL; + test_setopt( curl, CURLOPT_URL, url ); + printf( "CURLOPT_SHARE\n" ); + test_setopt( curl, CURLOPT_SHARE, share ); + + printf( "PERFORM\n" ); + curl_easy_perform( curl ); + + /* try to free share, expect to fail because share is in use*/ + printf( "try SHARE_CLEANUP...\n" ); + scode = curl_share_cleanup( share ); + if ( scode==CURLSHE_OK ) + { + fprintf(stderr, "curl_share_cleanup succeed but error expected\n"); + share = NULL; + } else { + printf( "SHARE_CLEANUP failed, correct\n" ); + } + +test_cleanup: + + /* clean up last handle */ + printf( "CLEANUP\n" ); + curl_easy_cleanup( curl ); + + /* free share */ + printf( "SHARE_CLEANUP\n" ); + scode = curl_share_cleanup( share ); + if ( scode!=CURLSHE_OK ) + fprintf(stderr, "curl_share_cleanup failed, code errno %d\n", + (int)scode); + + printf( "GLOBAL_CLEANUP\n" ); + curl_global_cleanup(); + + return res; +} + diff --git a/tests/libtest/test.h b/tests/libtest/test.h index 33d7bed83..81c435d1f 100644 --- a/tests/libtest/test.h +++ b/tests/libtest/test.h @@ -33,7 +33,6 @@ #include <stdio.h> #include <string.h> #include <stdlib.h> -#include <errno.h> #ifdef HAVE_SYS_SOCKET_H #include <sys/socket.h> @@ -51,9 +50,6 @@ # include "select.h" #endif -#define TEST_ERR_MAJOR_BAD 100 -#define TEST_ERR_RUNS_FOREVER 99 - #define test_setopt(A,B,C) \ if((res = curl_easy_setopt((A),(B),(C))) != CURLE_OK) goto test_cleanup @@ -67,8 +63,10 @@ extern char *libtest_arg3; /* set by first.c to the argv[3] or NULL */ extern int test_argc; extern char **test_argv; -extern int select_test(int num_fds, fd_set *rd, fd_set *wr, fd_set *exc, - struct timeval *tv); +extern struct timeval tv_test_start; /* for test timing */ + +extern int select_wrapper(int nfds, fd_set *rd, fd_set *wr, fd_set *exc, + struct timeval *tv); extern int test(char *URL); /* the actual test function provided by each individual libXXX.c file */ @@ -76,3 +74,331 @@ extern int test(char *URL); /* the actual test function provided by each #ifdef UNITTESTS extern int unitfail; #endif + +/* +** TEST_ERR_* values must be greater than CURL_LAST CURLcode in order +** to avoid confusion with any CURLcode or CURLMcode. These TEST_ERR_* +** codes are returned to signal test specific situations and should +** not get mixed with CURLcode or CURLMcode values. +** +** For portability reasons TEST_ERR_* values should be less than 127. +*/ + +#define TEST_ERR_MAJOR_BAD 126 +#define TEST_ERR_RUNS_FOREVER 125 +#define TEST_ERR_EASY_INIT 124 +#define TEST_ERR_MULTI_INIT 123 +#define TEST_ERR_NUM_HANDLES 122 +#define TEST_ERR_SELECT 121 +#define TEST_ERR_SUCCESS 120 +#define TEST_ERR_FAILURE 119 +#define TEST_ERR_USAGE 118 +#define TEST_ERR_FOPEN 117 +#define TEST_ERR_FSTAT 116 + +/* +** Macros for test source code readability/maintainability. +** +** All of the following macros require that an int data type 'res' variable +** exists in scope where macro is used, and that it has been initialized to +** zero before the macro is used. +** +** exe_* and chk_* macros are helper macros not intended to be used from +** outside of this header file. Arguments 'Y' and 'Z' of these represent +** source code file and line number, while Arguments 'A', 'B', etc, are +** the arguments used to actually call a libcurl function. +** +** All easy_* and multi_* macros call a libcurl function and evaluate if +** the function has succeeded or failed. When the function succeeds 'res' +** variable is not set nor cleared and program continues normal flow. On +** the other hand if function fails 'res' variable is set and a jump to +** label 'test_cleanup' is performed. +** +** Every easy_* and multi_* macros have a res_easy_* and res_multi_* macro +** counterpart that operates in tha same way with the exception that no +** jump takes place in case of failure. res_easy_* and res_multi_* macros +** should be immediately followed by checking if 'res' variable has been +** set. +** +** 'res' variable when set will hold a CURLcode, CURLMcode, or any of the +** TEST_ERR_* values defined above. It is advisable to return this value +** as test result. +*/ + +/* ---------------------------------------------------------------- */ + +#define exe_easy_init(A,Y,Z) do { \ + if(((A) = curl_easy_init()) == NULL) { \ + fprintf(stderr, "%s:%d curl_easy_init() failed\n", (Y), (Z)); \ + res = TEST_ERR_EASY_INIT; \ + } \ +} WHILE_FALSE + +#define res_easy_init(A) \ + exe_easy_init((A),(__FILE__),(__LINE__)) + +#define chk_easy_init(A,Y,Z) do { \ + exe_easy_init((A),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define easy_init(A) \ + chk_easy_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_init(A,Y,Z) do { \ + if(((A) = curl_multi_init()) == NULL) { \ + fprintf(stderr, "%s:%d curl_multi_init() failed\n", (Y), (Z)); \ + res = TEST_ERR_MULTI_INIT; \ + } \ +} WHILE_FALSE + +#define res_multi_init(A) \ + exe_multi_init((A),(__FILE__),(__LINE__)) + +#define chk_multi_init(A,Y,Z) do { \ + exe_multi_init((A),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_init(A) \ + chk_multi_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_easy_setopt(A,B,C,Y,Z) do { \ + CURLcode ec; \ + if((ec = curl_easy_setopt((A),(B),(C))) != CURLE_OK) { \ + fprintf(stderr, "%s:%d curl_easy_setopt() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_easy_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_easy_setopt(A,B,C) \ + exe_easy_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +#define chk_easy_setopt(A,B,C,Y,Z) do { \ + exe_easy_setopt((A),(B),(C),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define easy_setopt(A,B,C) \ + chk_easy_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_setopt(A,B,C,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_setopt((A),(B),(C))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_setopt() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_setopt(A,B,C) \ + exe_multi_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +#define chk_multi_setopt(A,B,C,Y,Z) do { \ + exe_multi_setopt((A),(B),(C),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_setopt(A,B,C) \ + chk_multi_setopt((A),(B),(C),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_add_handle(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_add_handle((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_add_handle() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_add_handle(A,B) \ + exe_multi_add_handle((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_add_handle(A,B,Y,Z) do { \ + exe_multi_add_handle((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_add_handle(A,B) \ + chk_multi_add_handle((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_perform(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_perform((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_perform() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ + else if(*((B)) < 0) { \ + fprintf(stderr, "%s:%d curl_multi_perform() succeeded, " \ + "but returned invalid running_handles value (%d)\n", \ + (Y), (Z), (int)*((B))); \ + res = TEST_ERR_NUM_HANDLES; \ + } \ +} WHILE_FALSE + +#define res_multi_perform(A,B) \ + exe_multi_perform((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_perform(A,B,Y,Z) do { \ + exe_multi_perform((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_perform(A,B) \ + chk_multi_perform((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_fdset(A,B,C,D,E,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_fdset((A),(B),(C),(D),(E))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_fdset() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ + else if(*((E)) < -1) { \ + fprintf(stderr, "%s:%d curl_multi_fdset() succeeded, " \ + "but returned invalid max_fd value (%d)\n", \ + (Y), (Z), (int)*((E))); \ + res = TEST_ERR_NUM_HANDLES; \ + } \ +} WHILE_FALSE + +#define res_multi_fdset(A,B,C,D,E) \ + exe_multi_fdset((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +#define chk_multi_fdset(A,B,C,D,E,Y,Z) do { \ + exe_multi_fdset((A),(B),(C),(D),(E),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_fdset(A,B,C,D,E) \ + chk_multi_fdset((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_multi_timeout(A,B,Y,Z) do { \ + CURLMcode ec; \ + if((ec = curl_multi_timeout((A),(B))) != CURLM_OK) { \ + fprintf(stderr, "%s:%d curl_multi_timeout() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_multi_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_multi_timeout(A,B) \ + exe_multi_timeout((A),(B),(__FILE__),(__LINE__)) + +#define chk_multi_timeout(A,B,Y,Z) do { \ + exe_multi_timeout((A),(B),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define multi_timeout(A,B) \ + chk_multi_timeout((A),(B),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_select_test(A,B,C,D,E,Y,Z) do { \ + int ec; \ + if(select_wrapper((A),(B),(C),(D),(E)) == -1 ) { \ + ec = SOCKERRNO; \ + fprintf(stderr, "%s:%d select() failed, with " \ + "errno %d (%s)\n", \ + (Y), (Z), ec, strerror(ec)); \ + res = TEST_ERR_SELECT; \ + } \ +} WHILE_FALSE + +#define res_select_test(A,B,C,D,E) \ + exe_select_test((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +#define chk_select_test(A,B,C,D,E,Y,Z) do { \ + exe_select_test((A),(B),(C),(D),(E),(Y),(Z)); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define select_test(A,B,C,D,E) \ + chk_select_test((A),(B),(C),(D),(E),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define start_test_timing() do { \ + tv_test_start = tutil_tvnow(); \ +} WHILE_FALSE + +#define exe_test_timedout(Y,Z) do { \ + if(tutil_tvdiff(tutil_tvnow(), tv_test_start) > TEST_HANG_TIMEOUT) { \ + fprintf(stderr, "%s:%d ABORTING TEST, since it seems " \ + "that it would have run forever.\n", (Y), (Z)); \ + res = TEST_ERR_RUNS_FOREVER; \ + } \ +} WHILE_FALSE + +#define res_test_timedout() \ + exe_test_timedout((__FILE__),(__LINE__)) + +#define chk_test_timedout(Y,Z) do { \ + exe_test_timedout(Y,Z); \ + if(res) \ + goto test_cleanup; \ +} WHILE_FALSE + +#define abort_on_test_timeout() \ + chk_test_timedout((__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ + +#define exe_global_init(A,Y,Z) do { \ + CURLcode ec; \ + if((ec = curl_global_init((A))) != CURLE_OK) { \ + fprintf(stderr, "%s:%d curl_global_init() failed, " \ + "with code %d (%s)\n", \ + (Y), (Z), (int)ec, curl_easy_strerror(ec)); \ + res = (int)ec; \ + } \ +} WHILE_FALSE + +#define res_global_init(A) \ + exe_global_init((A),(__FILE__),(__LINE__)) + +#define chk_global_init(A,Y,Z) do { \ + exe_global_init((A),(Y),(Z)); \ + if(res) \ + return res; \ +} WHILE_FALSE + +/* global_init() is different than other macros. In case of + failure it 'return's instead of going to 'test_cleanup'. */ + +#define global_init(A) \ + chk_global_init((A),(__FILE__),(__LINE__)) + +/* ---------------------------------------------------------------- */ diff --git a/tests/memanalyze.pl b/tests/memanalyze.pl index 2650590a6..bf5393365 100755 --- a/tests/memanalyze.pl +++ b/tests/memanalyze.pl @@ -236,6 +236,14 @@ while(<FILE>) { $getfile{$1}="$source:$linenum"; $openfile++; } + elsif($function =~ /socketpair\(\) = (\d*) (\d*)/) { + $filedes{$1}=1; + $getfile{$1}="$source:$linenum"; + $openfile++; + $filedes{$2}=1; + $getfile{$2}="$source:$linenum"; + $openfile++; + } elsif($function =~ /accept\(\) = (\d*)/) { $filedes{$1}=1; $getfile{$1}="$source:$linenum"; diff --git a/tests/runtests.pl b/tests/runtests.pl index a498963d0..964e3b800 100755 --- a/tests/runtests.pl +++ b/tests/runtests.pl @@ -100,7 +100,7 @@ use sshhelp qw( find_sshd find_ssh find_sftp - find_gnutls_serv + find_httptlssrv sshversioninfo ); @@ -115,28 +115,29 @@ my $CLIENT6IP="[::1]"; # address which curl uses for incoming connections my $base = 8990; # base port number -my $HTTPPORT; # HTTP server port -my $HTTP6PORT; # HTTP IPv6 server port -my $HTTPSPORT; # HTTPS server port -my $FTPPORT; # FTP server port -my $FTP2PORT; # FTP server 2 port -my $FTPSPORT; # FTPS server port -my $FTP6PORT; # FTP IPv6 server port -my $TFTPPORT; # TFTP -my $TFTP6PORT; # TFTP -my $SSHPORT; # SCP/SFTP -my $SOCKSPORT; # SOCKS4/5 port -my $POP3PORT; # POP3 -my $POP36PORT; # POP3 IPv6 server port -my $IMAPPORT; # IMAP -my $IMAP6PORT; # IMAP IPv6 server port -my $SMTPPORT; # SMTP -my $SMTP6PORT; # SMTP IPv6 server port -my $RTSPPORT; # RTSP -my $RTSP6PORT; # RTSP IPv6 server port -my $GOPHERPORT; # Gopher -my $GOPHER6PORT; # Gopher IPv6 server port -my $HTTPTLSSRPPORT; # TLS-SRP HTTP port +my $HTTPPORT; # HTTP server port +my $HTTP6PORT; # HTTP IPv6 server port +my $HTTPSPORT; # HTTPS (stunnel) server port +my $FTPPORT; # FTP server port +my $FTP2PORT; # FTP server 2 port +my $FTPSPORT; # FTPS (stunnel) server port +my $FTP6PORT; # FTP IPv6 server port +my $TFTPPORT; # TFTP +my $TFTP6PORT; # TFTP +my $SSHPORT; # SCP/SFTP +my $SOCKSPORT; # SOCKS4/5 port +my $POP3PORT; # POP3 +my $POP36PORT; # POP3 IPv6 server port +my $IMAPPORT; # IMAP +my $IMAP6PORT; # IMAP IPv6 server port +my $SMTPPORT; # SMTP +my $SMTP6PORT; # SMTP IPv6 server port +my $RTSPPORT; # RTSP +my $RTSP6PORT; # RTSP IPv6 server port +my $GOPHERPORT; # Gopher +my $GOPHER6PORT; # Gopher IPv6 server port +my $HTTPTLSPORT; # HTTP TLS (non-stunnel) server port +my $HTTPTLS6PORT; # HTTP TLS (non-stunnel) IPv6 server port my $srcdir = $ENV{'srcdir'} || '.'; my $CURL="../src/curl".exe_ext(); # what curl executable to run on the tests @@ -191,6 +192,7 @@ my $valgrind = checktestcmd("valgrind"); my $valgrind_logfile="--logfile"; my $valgrind_tool; my $gdb = checktestcmd("gdb"); +my $httptlssrv = find_httptlssrv(); my $ssl_version; # set if libcurl is built with SSL support my $large_file; # set if libcurl is built with large file support @@ -203,6 +205,7 @@ my $has_ipv6; # set if libcurl is built with IPv6 support my $has_libz; # set if libcurl is built with libz support my $has_getrlimit; # set if system has getrlimit() my $has_ntlm; # set if libcurl is built with NTLM support +my $has_ntlm_wb; # set if libcurl is built with NTLM delegation to winbind my $has_charconv;# set if libcurl is built with CharConv support my $has_tls_srp; # set if libcurl is built with TLS-SRP support @@ -219,7 +222,8 @@ my $ssllib; # name of the lib we use (for human presentation) my $has_crypto; # set if libcurl is built with cryptographic support my $has_textaware; # set if running on a system that has a text mode concept # on files. Windows for example -my @protocols; # array of supported protocols + +my @protocols; # array of lowercase supported protocol servers my $skipped=0; # number of tests skipped; reported in main loop my %skipped; # skipped{reason}=counter, reasons for skip @@ -258,6 +262,7 @@ my $verbose; my $debugprotocol; my $anyway; my $gdbthis; # run test case with gdb debugger +my $gdbxwin; # use windowed gdb when using gdb my $keepoutfiles; # keep stdout and stderr files after tests my $listonly; # only list the tests my $postmortem; # display detailed info about failed tests @@ -308,7 +313,7 @@ $SIG{TERM} = \&catch_zap; # to prevent them to interfere with our testing! my $protocol; -foreach $protocol (('ftp', 'http', 'ftps', 'https', 'no')) { +foreach $protocol (('ftp', 'http', 'ftps', 'https', 'no', 'all')) { my $proxy = "${protocol}_proxy"; # clear lowercase version delete $ENV{$proxy} if($ENV{$proxy}); @@ -338,7 +343,7 @@ sub init_serverpidfile_hash { } } } - for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher', 'http+tls-srp')) { + for my $proto (('tftp', 'sftp', 'socks', 'ssh', 'rtsp', 'gopher', 'httptls')) { for my $ipvnum ((4, 6)) { for my $idnum ((1, 2)) { my $serv = servername_id($proto, $ipvnum, $idnum); @@ -391,7 +396,7 @@ sub startnew { die "error: exec() has returned"; } - # Ugly hack but ssh client doesn't support pid files + # Ugly hack but ssh client and gnutls-serv don't support pid files if ($fake) { if(open(OUT, ">$pidfile")) { print OUT $child . "\n"; @@ -630,20 +635,20 @@ sub stopserver { # All servers relative to the given one must be stopped also # my @killservers; - if($server =~ /^(ftp|http|imap|pop3|smtp)s(.*)$/) { - # given an ssl server, also kill non-ssl underlying one + if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { + # given a stunnel based ssl server, also kill non-ssl underlying one push @killservers, "${1}${2}"; } - elsif($server =~ /^(ftp|http|imap|pop3|smtp)(.*)$/) { - # given a non-ssl server, also kill ssl piggybacking one + elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|))$/) { + # given a non-ssl server, also kill stunnel based ssl piggybacking one push @killservers, "${1}s${2}"; } - elsif($server =~ /^(socks)(.*)$/) { - # given an socks server, also kill ssh underlying one + elsif($server =~ /^(socks)((\d*)(-ipv6|))$/) { + # given a socks server, also kill ssh underlying one push @killservers, "ssh${2}"; } - elsif($server =~ /^(ssh)(.*)$/) { - # given an ssh server, also kill socks piggybacking one + elsif($server =~ /^(ssh)((\d*)(-ipv6|))$/) { + # given a ssh server, also kill socks piggybacking one push @killservers, "socks${2}"; } push @killservers, $server; @@ -652,8 +657,7 @@ sub stopserver { # foreach my $server (@killservers) { if($run{$server}) { - # we must prepend a space since $pidlist may already contain - # a pid + # we must prepend a space since $pidlist may already contain a pid $pidlist .= " $run{$server}"; $run{$server} = 0; } @@ -678,8 +682,8 @@ sub stopserver { # Verify that the server that runs on $ip, $port is our server. This also # implies that we can speak with it, as there might be occasions when the # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't -# assign requested address" # - +# assign requested address") +# sub verifyhttp { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -758,8 +762,8 @@ sub verifyhttp { # Verify that the server that runs on $ip, $port is our server. This also # implies that we can speak with it, as there might be occasions when the # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't -# assign requested address" # - +# assign requested address") +# sub verifyftp { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -830,8 +834,8 @@ sub verifyftp { # Verify that the server that runs on $ip, $port is our server. This also # implies that we can speak with it, as there might be occasions when the # server runs fine but we cannot talk to it ("Failed to connect to ::1: Can't -# assign requested address" # - +# assign requested address") +# sub verifyrtsp { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -903,7 +907,7 @@ sub verifyrtsp { # Verify that the ssh server has written out its pidfile, recovering # the pid from the file and returning it if a process with that pid is # actually alive. - +# sub verifyssh { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -929,7 +933,7 @@ sub verifyssh { ####################################################################### # Verify that we can connect to the sftp server, properly authenticate # with generated config and key files and run a simple remote pwd. - +# sub verifysftp { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -964,17 +968,16 @@ sub verifysftp { } ####################################################################### -# Verify that the TLS-SRP HTTP server that runs on $ip, $port is our server. -# This also implies that we can speak with it, as there might be occasions when -# the server runs fine but we cannot talk to it ("Failed to connect to ::1: -# Can't assign requested address" # - -sub verifyhttptlssrp { +# Verify that the non-stunnel HTTP TLS extensions capable server that runs +# on $ip, $port is our server. This also implies that we can speak with it, +# as there might be occasions when the server runs fine but we cannot talk +# to it ("Failed to connect to ::1: Can't assign requested address") +# +sub verifyhttptls { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); my $pidfile = server_pidfilename($proto, $ipvnum, $idnum); my $pid = 0; - my $bonus=""; my $verifyout = "$LOGDIR/". servername_canon($proto, $ipvnum, $idnum) .'_verify.out'; @@ -989,7 +992,9 @@ sub verifyhttptlssrp { $flags .= "--verbose "; $flags .= "--globoff "; $flags .= "--insecure "; - $flags .= "--tlsauthtype SRP --tlsuser jsmith --tlspassword abc "; + $flags .= "--tlsauthtype SRP "; + $flags .= "--tlsuser jsmith "; + $flags .= "--tlspassword abc "; $flags .= "\"https://$ip:$port/verifiedserver\""; my $cmd = "$VCURL $flags 2>$verifylog"; @@ -1025,6 +1030,16 @@ sub verifyhttptlssrp { if($data && ($data =~ /GNUTLS/) && open(FILE, "<$pidfile")) { $pid=0+<FILE>; close(FILE); + if($pid > 0) { + # if we have a pid it is actually our httptls server, + # since runhttptlsserver() unlinks previous pidfile + if(!kill(0, $pid)) { + logmsg "RUN: $server server has died after starting up\n"; + checkdied($pid); + unlink($pidfile); + $pid = -1; + } + } return $pid; } elsif($res == 6) { @@ -1041,7 +1056,7 @@ sub verifyhttptlssrp { ####################################################################### # STUB for verifying socks - +# sub verifysocks { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; my $server = servername_id($proto, $ipvnum, $idnum); @@ -1070,6 +1085,11 @@ sub verifysocks { # particular can take a long time to start if it needs to generate # keys on a slow or loaded host. # +# Just for convenience, test harness uses 'https' and 'httptls' literals +# as values for 'proto' variable in order to differentiate different +# servers. 'https' literal is used for stunnel based https test servers, +# and 'httptls' is used for non-stunnel https test servers. +# my %protofunc = ('http' => \&verifyhttp, 'https' => \&verifyhttp, @@ -1083,7 +1103,7 @@ my %protofunc = ('http' => \&verifyhttp, 'ssh' => \&verifyssh, 'socks' => \&verifysocks, 'gopher' => \&verifyhttp, - 'http+tls-srp' => \&verifyhttptlssrp); + 'httptls' => \&verifyhttptls); sub verifyserver { my ($proto, $ipvnum, $idnum, $ip, $port) = @_; @@ -1124,7 +1144,6 @@ sub runhttpserver { my $logfile; my $flags = ""; - if($ipv6) { # if IPv6, use a different setup $ipvnum = 6; @@ -1191,7 +1210,7 @@ sub runhttpserver { } ####################################################################### -# start the https server (or rather, tunnel) +# start the https stunnel based server # sub runhttpsserver { my ($verbose, $ipv6, $certfile) = @_; @@ -1274,14 +1293,14 @@ sub runhttpsserver { } ####################################################################### -# start the TLS-SRP HTTP server +# start the non-stunnel HTTP TLS extensions capable server # -sub runhttptlssrpserver { - my ($verbose) = @_; - my $proto = "http+tls-srp"; - my $ip = $HOSTIP; - my $port = $HTTPTLSSRPPORT; - my $ipvnum = 4; +sub runhttptlsserver { + my ($verbose, $ipv6) = @_; + my $proto = "httptls"; + my $port = ($ipv6 && ($ipv6 =~ /6$/)) ? $HTTPTLS6PORT : $HTTPTLSPORT; + my $ip = ($ipv6 && ($ipv6 =~ /6$/)) ? "$HOST6IP" : "$HOSTIP"; + my $ipvnum = ($ipv6 && ($ipv6 =~ /6$/)) ? 6 : 4; my $idnum = 1; my $server; my $srvrname; @@ -1289,6 +1308,10 @@ sub runhttptlssrpserver { my $logfile; my $flags = ""; + if(!$httptlssrv) { + return (0,0); + } + $server = servername_id($proto, $ipvnum, $idnum); $pidfile = $serverpidfile{$server}; @@ -1308,23 +1331,16 @@ sub runhttptlssrpserver { $logfile = server_logfilename($LOGDIR, $proto, $ipvnum, $idnum); - $flags .= "--fork " if($forkserver); $flags .= "--http "; - $flags .= "-d 1 " if($debugprotocol); + $flags .= "--debug 1 " if($debugprotocol); $flags .= "--port $port "; - $flags .= "--srppasswd certs/srp-verifier-db --srppasswdconf certs/srp-verifier-conf "; - $flags .=" >log/gnutls.out 2>&1"; + $flags .= "--srppasswd certs/srp-verifier-db "; + $flags .= "--srppasswdconf certs/srp-verifier-conf"; - # Find gnutls-serv - my $gnutlsserv = find_gnutls_serv(); - if(!$gnutlsserv) { - logmsg "RUN: cannot find gnutls-serv\n"; - return (0,0); - } - my $cmd = "$gnutlsserv $flags"; - my ($httptlssrppid, $pid2) = startnew($cmd, $pidfile, 1, 1); + my $cmd = "$httptlssrv $flags > $logfile 2>&1"; + my ($httptlspid, $pid2) = startnew($cmd, $pidfile, 10, 1); # fake pidfile - if($httptlssrppid <= 0 || !kill(0, $httptlssrppid)) { + if($httptlspid <= 0 || !kill(0, $httptlspid)) { # it is NOT alive logmsg "RUN: failed to start the $srvrname server\n"; stopserver($server, "$pid2"); @@ -1333,12 +1349,12 @@ sub runhttptlssrpserver { return (0,0); } - # Server is up. Verify that we can speak to it. + # Server is up. Verify that we can speak to it. PID is from fake pidfile my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); if(!$pid3) { logmsg "RUN: $srvrname server failed verification\n"; # failed to talk to it properly. Kill the server and return failure - stopserver($server, "$httptlssrppid $pid2"); + stopserver($server, "$httptlspid $pid2"); displaylogs($testnumcheck); $doesntrun{$pidfile} = 1; return (0,0); @@ -1346,12 +1362,12 @@ sub runhttptlssrpserver { $pid2 = $pid3; if($verbose) { - logmsg "RUN: $srvrname server is now running PID $httptlssrppid\n"; + logmsg "RUN: $srvrname server is now running PID $httptlspid\n"; } sleep(1); - return ($httptlssrppid, $pid2); + return ($httptlspid, $pid2); } ####################################################################### @@ -1901,7 +1917,7 @@ sub runsocksserver { # start our socks server my $cmd="$ssh -N -F $sshconfig $ip > $sshlog 2>&1"; - my ($sshpid, $pid2) = startnew($cmd, $pidfile, 30, 1); + my ($sshpid, $pid2) = startnew($cmd, $pidfile, 30, 1); # fake pidfile if($sshpid <= 0 || !kill(0, $sshpid)) { # it is NOT alive @@ -1915,7 +1931,7 @@ sub runsocksserver { return (0,0); } - # Ugly hack but ssh doesn't support pid files + # Ugly hack but ssh doesn't support pid files. PID is from fake pidfile. my $pid3 = verifyserver($proto, $ipvnum, $idnum, $ip, $port); if(!$pid3) { logmsg "RUN: $srvrname server failed verification\n"; @@ -1984,7 +2000,6 @@ sub filteroff { # compare test results with the expected output, we might filter off # some pattern that is allowed to differ, output test results # - sub compare { # filter off patterns _before_ this comparison! my ($subject, $firstref, $secondref)=@_; @@ -2116,29 +2131,22 @@ sub checksystem { $has_openssl=1; $ssllib="polarssl"; } - elsif ($libcurl =~ /axtls/i) { - $has_axtls=1; - $ssllib="axTLS"; - } + elsif ($libcurl =~ /axtls/i) { + $has_axtls=1; + $ssllib="axTLS"; + } } elsif($_ =~ /^Protocols: (.*)/i) { # these are the protocols compiled in to this libcurl - @protocols = split(' ', $1); + @protocols = split(' ', lc($1)); # Generate a "proto-ipv6" version of each protocol to match the # IPv6 <server> name. This works even if IPv6 support isn't # compiled in because the <features> test will fail. - push @protocols, map($_ . "-ipv6", @protocols); - - # Hack - we need a different, non-stunnel server to test HTTP - # TLS-SRP, but we don't want to add HTTP+TLS-SRP as a protocol - # throughout curl - if ($has_gnutls) { - push @protocols, ('http+tls-srp'); - } + push @protocols, map($_ . '-ipv6', @protocols); # 'none' is used in test cases to mean no server - push @protocols, ('none'); + push @protocols, 'none'; } elsif($_ =~ /^Features: (.*)/i) { $feat = $1; @@ -2172,6 +2180,10 @@ sub checksystem { # NTLM enabled $has_ntlm=1; } + if($feat =~ /NTLM_WB/i) { + # NTLM delegation to winbind daemon ntlm_auth helper enabled + $has_ntlm_wb=1; + } if($feat =~ /CharConv/i) { # CharConv enabled $has_charconv=1; @@ -2181,6 +2193,27 @@ sub checksystem { $has_tls_srp=1; } } + # + # Test harness currently uses a non-stunnel server in order to + # run HTTP TLS-SRP tests required when curl is built with https + # protocol support and TLS-SRP feature enabled. For convenience + # 'httptls' may be included in the test harness protocols array + # to differentiate this from classic stunnel based 'https' test + # harness server. + # + if($has_tls_srp) { + my $add_httptls; + for(@protocols) { + if($_ =~ /^https(-ipv6|)$/) { + $add_httptls=1; + last; + } + } + if($add_httptls && (! grep /^httptls$/, @protocols)) { + push @protocols, 'httptls'; + push @protocols, 'httptls-ipv6'; + } + } } if(!$curl) { logmsg "unable to get curl's version, further details are:\n"; @@ -2302,6 +2335,13 @@ sub checksystem { logmsg sprintf("IMAP-IPv6/%d ", $IMAP6PORT); logmsg sprintf("SMTP-IPv6/%d\n", $SMTP6PORT); } + if($httptlssrv) { + logmsg sprintf("* HTTPTLS/%d ", $HTTPTLSPORT); + if($has_ipv6) { + logmsg sprintf("HTTPTLS-IPv6/%d ", $HTTPTLS6PORT); + } + logmsg "\n"; + } $has_textaware = ($^O eq 'MSWin32') || ($^O eq 'msys'); @@ -2314,36 +2354,57 @@ sub checksystem { # sub subVariables { my ($thing) = @_; - $$thing =~ s/%HOSTIP/$HOSTIP/g; - $$thing =~ s/%HTTPPORT/$HTTPPORT/g; - $$thing =~ s/%HOST6IP/$HOST6IP/g; - $$thing =~ s/%HTTP6PORT/$HTTP6PORT/g; - $$thing =~ s/%HTTPSPORT/$HTTPSPORT/g; - $$thing =~ s/%FTPPORT/$FTPPORT/g; + + # ports + $$thing =~ s/%FTP6PORT/$FTP6PORT/g; $$thing =~ s/%FTP2PORT/$FTP2PORT/g; $$thing =~ s/%FTPSPORT/$FTPSPORT/g; - $$thing =~ s/%SRCDIR/$srcdir/g; - $$thing =~ s/%PWD/$pwd/g; - $$thing =~ s/%TFTPPORT/$TFTPPORT/g; - $$thing =~ s/%TFTP6PORT/$TFTP6PORT/g; - $$thing =~ s/%SSHPORT/$SSHPORT/g; - $$thing =~ s/%SOCKSPORT/$SOCKSPORT/g; - $$thing =~ s/%POP3PORT/$POP3PORT/g; - $$thing =~ s/%POP36PORT/$POP36PORT/g; - $$thing =~ s/%IMAPPORT/$IMAPPORT/g; + $$thing =~ s/%FTPPORT/$FTPPORT/g; + + $$thing =~ s/%GOPHER6PORT/$GOPHER6PORT/g; + $$thing =~ s/%GOPHERPORT/$GOPHERPORT/g; + + $$thing =~ s/%HTTPTLS6PORT/$HTTPTLS6PORT/g; + $$thing =~ s/%HTTPTLSPORT/$HTTPTLSPORT/g; + $$thing =~ s/%HTTP6PORT/$HTTP6PORT/g; + $$thing =~ s/%HTTPSPORT/$HTTPSPORT/g; + $$thing =~ s/%HTTPPORT/$HTTPPORT/g; + $$thing =~ s/%IMAP6PORT/$IMAP6PORT/g; - $$thing =~ s/%SMTPPORT/$SMTPPORT/g; + $$thing =~ s/%IMAPPORT/$IMAPPORT/g; + + $$thing =~ s/%POP36PORT/$POP36PORT/g; + $$thing =~ s/%POP3PORT/$POP3PORT/g; + + $$thing =~ s/%RTSP6PORT/$RTSP6PORT/g; + $$thing =~ s/%RTSPPORT/$RTSPPORT/g; + $$thing =~ s/%SMTP6PORT/$SMTP6PORT/g; + $$thing =~ s/%SMTPPORT/$SMTPPORT/g; + + $$thing =~ s/%SOCKSPORT/$SOCKSPORT/g; + $$thing =~ s/%SSHPORT/$SSHPORT/g; + + $$thing =~ s/%TFTP6PORT/$TFTP6PORT/g; + $$thing =~ s/%TFTPPORT/$TFTPPORT/g; + + # client IP addresses + + $$thing =~ s/%CLIENT6IP/$CLIENT6IP/g; + $$thing =~ s/%CLIENTIP/$CLIENTIP/g; + + # server IP addresses + + $$thing =~ s/%HOST6IP/$HOST6IP/g; + $$thing =~ s/%HOSTIP/$HOSTIP/g; + + # misc + $$thing =~ s/%CURL/$CURL/g; + $$thing =~ s/%PWD/$pwd/g; + $$thing =~ s/%SRCDIR/$srcdir/g; $$thing =~ s/%USER/$USER/g; - $$thing =~ s/%CLIENTIP/$CLIENTIP/g; - $$thing =~ s/%CLIENT6IP/$CLIENT6IP/g; - $$thing =~ s/%RTSPPORT/$RTSPPORT/g; - $$thing =~ s/%RTSP6PORT/$RTSP6PORT/g; - $$thing =~ s/%GOPHERPORT/$GOPHERPORT/g; - $$thing =~ s/%GOPHER6PORT/$GOPHER6PORT/g; - $$thing =~ s/%HTTPTLSSRPPORT/$HTTPTLSSRPPORT/g; # The purpose of FTPTIME2 and FTPTIME3 is to provide times that can be # used for time-out tests and that whould work on most hosts as these @@ -2490,6 +2551,11 @@ sub singletest { next; } } + elsif($f eq "debug") { + if($debug_build) { + next; + } + } elsif($f eq "large_file") { if($large_file) { next; @@ -2515,6 +2581,11 @@ sub singletest { next; } } + elsif($f eq "NTLM_WB") { + if($has_ntlm_wb) { + next; + } + } elsif($f eq "getrlimit") { if($has_getrlimit) { next; @@ -2534,7 +2605,7 @@ sub singletest { next; } # See if this "feature" is in the list of supported protocols - elsif (grep /^$f$/, @protocols) { + elsif (grep /^\Q$f\E$/i, @protocols) { next; } @@ -2809,8 +2880,14 @@ sub singletest { } elsif(!$tool) { # run curl, add --verbose for debug information output - $cmd = "-1 ".$cmd if(exists $feature{"SSL"} && ($has_axtls)); - $cmdargs ="$out --include --verbose --trace-time $cmd"; + $cmd = "-1 ".$cmd if(exists $feature{"SSL"} && ($has_axtls)); + + my $inc=""; + if((!$cmdhash{'option'}) || ($cmdhash{'option'} !~ /no-include/)) { + $inc = "--include "; + } + + $cmdargs ="$out $inc--verbose --trace-time $cmd"; } else { $cmdargs = " $cmd"; # $cmd is the command line for the test file @@ -2904,7 +2981,8 @@ sub singletest { "$gdb --directory libtest $DBGCURL -x $LOGDIR/gdbcmd"); } elsif($gdbthis) { - runclient("$gdb --directory libtest $DBGCURL -x $LOGDIR/gdbcmd"); + my $GDBW = ($gdbxwin) ? "-w" : ""; + runclient("$gdb --directory libtest $DBGCURL $GDBW -x $LOGDIR/gdbcmd"); $cmdres=0; # makes it always continue after a debugged run } else { @@ -2964,6 +3042,10 @@ sub singletest { # Test harness ssh server does not have this synchronization mechanism, # this implies that some ssh server based tests might need a small delay # once that the client command has run to avoid false test failures. + # + # gnutls-serv also lacks this synchronization mechanism, so gnutls-serv + # based tests might need a small delay once that the client command has + # run to avoid false test failures. sleep($postcommanddelay) if($postcommanddelay); @@ -2981,20 +3063,20 @@ sub singletest { my @killservers; foreach my $server (@killtestservers) { chomp $server; - if($server =~ /^(ftp|http|imap|pop3|smtp)s(.*)$/) { - # given an ssl server, also kill non-ssl underlying one + if($server =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { + # given a stunnel ssl server, also kill non-ssl underlying one push @killservers, "${1}${2}"; } - elsif($server =~ /^(ftp|http|imap|pop3|smtp)(.*)$/) { - # given a non-ssl server, also kill ssl piggybacking one + elsif($server =~ /^(ftp|http|imap|pop3|smtp)((\d*)(-ipv6|))$/) { + # given a non-ssl server, also kill stunnel piggybacking one push @killservers, "${1}s${2}"; } - elsif($server =~ /^(socks)(.*)$/) { - # given an socks server, also kill ssh underlying one + elsif($server =~ /^(socks)((\d*)(-ipv6|))$/) { + # given a socks server, also kill ssh underlying one push @killservers, "ssh${2}"; } - elsif($server =~ /^(ssh)(.*)$/) { - # given an ssh server, also kill socks piggybacking one + elsif($server =~ /^(ssh)((\d*)(-ipv6|))$/) { + # given a ssh server, also kill socks piggybacking one push @killservers, "socks${2}"; } push @killservers, $server; @@ -3085,6 +3167,7 @@ sub singletest { my $errorcode = $err[0] || "0"; my $ok=""; my $res; + chomp $errorcode; if (@validstdout) { # verify redirected stdout my @actual = loadarray($STDOUT); @@ -3272,7 +3355,7 @@ sub singletest { } else { if(!$short) { - printf("\n%s returned $cmdres, %d was expected\n", + printf("\n%s returned $cmdres, when expecting %s\n", (!$tool)?"curl":$tool, $errorcode); } logmsg " exit FAILED\n"; @@ -3379,6 +3462,7 @@ sub singletest { ####################################################################### # Stop all running test servers +# sub stopservers { my $verbose = $_[0]; # @@ -3426,17 +3510,17 @@ sub stopservers { # startservers() starts all the named servers # # Returns: string with error reason or blank for success - +# sub startservers { my @what = @_; my ($pid, $pid2); for(@what) { my (@whatlist) = split(/\s+/,$_); my $what = lc($whatlist[0]); - $what =~ s/[^a-z0-9-+]//g; + $what =~ s/[^a-z0-9-]//g; my $certfile; - if($what =~ /^(ftp|http|imap|pop3|smtp)s(.*)$/) { + if($what =~ /^(ftp|http|imap|pop3|smtp)s((\d*)(-ipv6|))$/) { $certfile = ($whatlist[1]) ? $whatlist[1] : 'stunnel.pem'; } @@ -3541,7 +3625,6 @@ sub startservers { $run{'rtsp-ipv6'}="$pid $pid2"; } } - elsif($what eq "ftps") { if(!$stunnel) { # we can't run ftps tests without stunnel @@ -3578,11 +3661,11 @@ sub startservers { } elsif($what eq "https") { if(!$stunnel) { - # we can't run ftps tests without stunnel + # we can't run https tests without stunnel return "no stunnel"; } if(!$ssl_version) { - # we can't run ftps tests if libcurl is SSL-less + # we can't run https tests if libcurl is SSL-less return "curl lacks SSL support"; } if($runcert{'https'} && ($runcert{'https'} ne $certfile)) { @@ -3608,18 +3691,34 @@ sub startservers { $run{'https'}="$pid $pid2"; } } - elsif($what eq "http+tls-srp") { - if(!$has_gnutls) { - return "no GnuTLS"; + elsif($what eq "httptls") { + if(!$httptlssrv) { + # for now, we can't run http TLS-EXT tests without gnutls-serv + return "no gnutls-serv"; + } + if(!$run{'httptls'}) { + ($pid, $pid2) = runhttptlsserver($verbose, "IPv4"); + if($pid <= 0) { + return "failed starting HTTPTLS server (gnutls-serv)"; + } + logmsg sprintf("* pid httptls => %d %d\n", $pid, $pid2) + if($verbose); + $run{'httptls'}="$pid $pid2"; + } + } + elsif($what eq "httptls-ipv6") { + if(!$httptlssrv) { + # for now, we can't run http TLS-EXT tests without gnutls-serv + return "no gnutls-serv"; } - if(!$run{'http+tls-srp'}) { - ($pid, $pid2) = runhttptlssrpserver($verbose); + if(!$run{'httptls-ipv6'}) { + ($pid, $pid2) = runhttptlsserver($verbose, "IPv6"); if($pid <= 0) { - return "failed starting HTTP+TLS-SRP server (gnutls-serv)"; + return "failed starting HTTPTLS-IPv6 server (gnutls-serv)"; } - logmsg sprintf("* pid http+tls-srp => %d %d\n", $pid, $pid2) + logmsg sprintf("* pid httptls-ipv6 => %d %d\n", $pid, $pid2) if($verbose); - $run{'http+tls-srp'}="$pid $pid2"; + $run{'httptls-ipv6'}="$pid $pid2"; } } elsif($what eq "tftp") { @@ -3697,7 +3796,6 @@ sub startservers { # # Returns: a string, blank if everything is fine or a reason why it failed # - sub serverfortest { my ($testnum)=@_; @@ -3708,14 +3806,28 @@ sub serverfortest { return "no server specified"; } - for (@what) { - my $proto = lc($_); - chomp $proto; - $proto =~ s/\s.*//g; # take first word - if (! grep /^\Q$proto\E$/, @protocols) { - if (substr($proto,0,5) ne "socks") { - return "curl lacks $proto support"; + for(my $i = scalar(@what) - 1; $i >= 0; $i--) { + my $srvrline = $what[$i]; + chomp $srvrline if($srvrline); + if($srvrline =~ /^(\S+)((\s*)(.*))/) { + my $server = "${1}"; + my $lnrest = "${2}"; + my $tlsext; + if($server =~ /^(httptls)(\+)(ext|srp)(\d*)(-ipv6|)$/) { + $server = "${1}${4}${5}"; + $tlsext = uc("TLS-${3}"); + } + if(! grep /^\Q$server\E$/, @protocols) { + if(substr($server,0,5) ne "socks") { + if($tlsext) { + return "curl lacks $tlsext support"; + } + else { + return "curl lacks $server support"; + } + } } + $what[$i] = "$server$lnrest" if($tlsext); } } @@ -3895,6 +4007,11 @@ while(@ARGV) { # run this test with gdb $gdbthis=1; } + elsif ($ARGV[0] eq "-gw") { + # run this test with windowed gdb + $gdbthis=1; + $gdbxwin=1; + } elsif($ARGV[0] eq "-s") { # short output $short=1; @@ -3966,6 +4083,7 @@ Usage: runtests.pl [options] [test selection(s)] -c path use this curl executable -d display server debug info -g run the test case with gdb + -gw run the test case with gdb as a windowed application -h this help text -k keep stdout and stderr files present after tests -l list all test case names/descriptions @@ -4072,29 +4190,29 @@ if ($gdbthis) { } } -$HTTPPORT = $base++; # HTTP server port -$HTTPSPORT = $base++; # HTTPS server port -$FTPPORT = $base++; # FTP server port -$FTPSPORT = $base++; # FTPS server port -$HTTP6PORT = $base++; # HTTP IPv6 server port (different IP protocol - # but we follow the same port scheme anyway) -$FTP2PORT = $base++; # FTP server 2 port -$FTP6PORT = $base++; # FTP IPv6 port -$TFTPPORT = $base++; # TFTP (UDP) port -$TFTP6PORT = $base++; # TFTP IPv6 (UDP) port -$SSHPORT = $base++; # SSH (SCP/SFTP) port -$SOCKSPORT = $base++; # SOCKS port -$POP3PORT = $base++; -$POP36PORT = $base++; -$IMAPPORT = $base++; -$IMAP6PORT = $base++; -$SMTPPORT = $base++; -$SMTP6PORT = $base++; -$RTSPPORT = $base++; -$RTSP6PORT = $base++; -$GOPHERPORT =$base++; -$GOPHER6PORT=$base++; -$HTTPTLSSRPPORT=$base++; +$HTTPPORT = $base++; # HTTP server port +$HTTPSPORT = $base++; # HTTPS (stunnel) server port +$FTPPORT = $base++; # FTP server port +$FTPSPORT = $base++; # FTPS (stunnel) server port +$HTTP6PORT = $base++; # HTTP IPv6 server port +$FTP2PORT = $base++; # FTP server 2 port +$FTP6PORT = $base++; # FTP IPv6 port +$TFTPPORT = $base++; # TFTP (UDP) port +$TFTP6PORT = $base++; # TFTP IPv6 (UDP) port +$SSHPORT = $base++; # SSH (SCP/SFTP) port +$SOCKSPORT = $base++; # SOCKS port +$POP3PORT = $base++; # POP3 server port +$POP36PORT = $base++; # POP3 IPv6 server port +$IMAPPORT = $base++; # IMAP server port +$IMAP6PORT = $base++; # IMAP IPv6 server port +$SMTPPORT = $base++; # SMTP server port +$SMTP6PORT = $base++; # SMTP IPv6 server port +$RTSPPORT = $base++; # RTSP server port +$RTSP6PORT = $base++; # RTSP IPv6 server port +$GOPHERPORT = $base++; # Gopher IPv4 server port +$GOPHER6PORT = $base++; # Gopher IPv6 server port +$HTTPTLSPORT = $base++; # HTTP TLS (non-stunnel) server port +$HTTPTLS6PORT = $base++; # HTTP TLS (non-stunnel) IPv6 server port ####################################################################### # clear and create logging directory: @@ -4251,6 +4369,9 @@ sub displaylogs { if(($log =~ /^file\d+\.txt/) && ($log !~ /^file$testnum\.txt/)) { next; # skip fileNnn.txt of other tests } + if(($log =~ /^netrc\d+/) && ($log !~ /^netrc$testnum/)) { + next; # skip netrcNnn of other tests + } if(($log =~ /^valgrind\d+/) && ($log !~ /^valgrind$testnum(\..*|)$/)) { next; # skip valgrindNnn of other tests } diff --git a/tests/server/.gitignore b/tests/server/.gitignore index 9e9dd37a2..8007bec8b 100644 --- a/tests/server/.gitignore +++ b/tests/server/.gitignore @@ -4,3 +4,4 @@ rtspd sockfilt sws tftpd +fake_ntlm diff --git a/tests/server/Makefile.inc b/tests/server/Makefile.inc index be3f06808..6b0ee72f0 100644 --- a/tests/server/Makefile.inc +++ b/tests/server/Makefile.inc @@ -1,4 +1,4 @@ -noinst_PROGRAMS = getpart resolve rtspd sockfilt sws tftpd +noinst_PROGRAMS = getpart resolve rtspd sockfilt sws tftpd fake_ntlm CURLX_SRCS = \ $(top_srcdir)/lib/mprintf.c \ @@ -63,3 +63,8 @@ tftpd_SOURCES = $(CURLX_SRCS) $(CURLX_HDRS) $(USEFUL) $(UTIL) \ tftp.h tftpd_LDADD = @TEST_SERVER_LIBS@ tftpd_CFLAGS = $(AM_CFLAGS) + +fake_ntlm_SOURCES = $(CURLX_SRCS) $(CURLX_HDRS) $(USEFUL) $(UTIL) \ + fake_ntlm.c +fake_ntlm_LDADD = @TEST_SERVER_LIBS@ +fake_ntlm_CFLAGS = $(AM_CFLAGS) diff --git a/tests/server/fake_ntlm.c b/tests/server/fake_ntlm.c new file mode 100644 index 000000000..9bed5963d --- /dev/null +++ b/tests/server/fake_ntlm.c @@ -0,0 +1,283 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2010, Mandy Wu, <mandy.wu@intel.com> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://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. + * + ***************************************************************************/ + +/* + * This is a fake ntlm_auth, which is used for testing NTLM single-sign-on. + * When DEBUGBUILD is defined, libcurl invoke this tool instead of real winbind + * daemon helper /usr/bin/ntlm_auth. This tool will accept commands and + * responses with a pre-written string saved in test case test2005. + */ + +#define CURL_NO_OLDIES + +#include "setup.h" + +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif + +#define ENABLE_CURLX_PRINTF +#include "curlx.h" /* from the private lib dir */ +#include "getpart.h" +#include "util.h" + +/* include memdebug.h last */ +#include "memdebug.h" + +#ifndef DEFAULT_LOGFILE +#define DEFAULT_LOGFILE "log/fake_ntlm.log" +#endif + +const char *serverlogfile = DEFAULT_LOGFILE; + +/* + * Returns an allocated buffer with printable representation of input + * buffer contents or returns NULL on out of memory condition. + */ +static char *printable(char *inbuf, size_t inlength) +{ + char *outbuf; + char *newbuf; + size_t newsize; + size_t outsize; + size_t outincr = 0; + size_t i, o = 0; + +#define HEX_FMT_STR "[0x%02X]" +#define HEX_STR_LEN 6 +#define NOTHING_STR "[NOTHING]" +#define NOTHING_LEN 9 + + if(!inlength) + inlength = strlen(inbuf); + + if(inlength) { + outincr = ((inlength/2) < (HEX_STR_LEN+1)) ? HEX_STR_LEN+1 : inlength/2; + outsize = inlength + outincr; + } + else + outsize = NOTHING_LEN + 1; + + outbuf = malloc(outsize); + if(!outbuf) + return NULL; + + if(!inlength) { + sprintf(&outbuf[0], "%s", NOTHING_STR); + return outbuf; + } + + for(i=0; i<inlength; i++) { + + if(o > outsize - (HEX_STR_LEN + 1)) { + newsize = outsize + outincr; + newbuf = realloc(outbuf, newsize); + if(!newbuf) { + free(outbuf); + return NULL; + } + outbuf = newbuf; + outsize = newsize; + } + + if((inbuf[i] > 0x20) && (inbuf[i] < 0x7F)) { + outbuf[o] = inbuf[i]; + o++; + } + else { + sprintf(&outbuf[o], HEX_FMT_STR, inbuf[i]); + o += HEX_STR_LEN; + } + + } + outbuf[o] = '\0'; + + return outbuf; +} + +int main(int argc, char *argv[]) +{ + char buf[1024]; + FILE *stream; + char *filename; + int error; + char *type1_input = NULL, *type3_input = NULL; + char *type1_output = NULL, *type3_output = NULL; + size_t size = 0; + long testnum; + const char *env; + int arg = 1; + char *helper_user = (char *)"unknown"; + char *helper_proto = (char *)"unknown"; + char *helper_domain = (char *)"unknown"; + bool use_cached_creds = FALSE; + char *msgbuf; + + buf[0] = '\0'; + + while(argc > arg) { + if(!strcmp("--use-cached-creds", argv[arg])) { + use_cached_creds = TRUE; + arg++; + } + else if(!strcmp("--helper-protocol", argv[arg])) { + arg++; + if(argc > arg) + helper_proto = argv[arg++]; + } + else if(!strcmp("--username", argv[arg])) { + arg++; + if(argc > arg) + helper_user = argv[arg++]; + } + else if(!strcmp("--domain", argv[arg])) { + arg++; + if(argc > arg) + helper_domain = argv[arg++]; + } + else { + puts("Usage: fake_ntlm [option]\n" + " --use-cached-creds\n" + " --helper-protocol [protocol]\n" + " --username [username]\n" + " --domain [domain]"); + exit(1); + } + } + + logmsg("fake_ntlm (user: %s) (proto: %s) (domain: %s) (cached creds: %s)", + helper_user, helper_proto, helper_domain, + (use_cached_creds) ? "yes" : "no"); + + env = getenv("CURL_NTLM_AUTH_TESTNUM"); + if (env) { + char *endptr; + long lnum = strtol(env, &endptr, 10); + if((endptr != env + strlen(env)) || (lnum < 1L)) { + logmsg("Test number not valid in CURL_NTLM_AUTH_TESTNUM"); + exit(1); + } + testnum = lnum; + } else { + logmsg("Test number not specified in CURL_NTLM_AUTH_TESTNUM"); + exit(1); + } + + env = getenv("CURL_NTLM_AUTH_SRCDIR"); + if (env) { + path = env; + } + + filename = test2file(testnum); + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + /* get the ntlm_auth input/output */ + error = getpart(&type1_input, &size, "ntlm_auth_type1", "input", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 1 input failed with error: %d", error); + exit(1); + } + } + + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type3_input, &size, "ntlm_auth_type3", "input", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 3 input failed with error: %d", error); + exit(1); + } + } + + while(fgets(buf, sizeof(buf), stdin)) { + if(strcmp(buf, type1_input) == 0) { + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type1_output, &size, "ntlm_auth_type1", "output", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 1 output failed with error: %d", error); + exit(1); + } + } + printf("%s", type1_output); + fflush(stdout); + } + else if(strncmp(buf, type3_input, strlen(type3_input)) == 0) { + stream=fopen(filename, "rb"); + if(!stream) { + error = ERRNO; + logmsg("fopen() failed with error: %d %s", error, strerror(error)); + logmsg("Error opening file: %s", filename); + logmsg("Couldn't open test file %ld", testnum); + exit(1); + } + else { + size = 0; + error = getpart(&type3_output, &size, "ntlm_auth_type3", "output", stream); + fclose(stream); + if(error || size == 0) { + logmsg("getpart() type 3 output failed with error: %d", error); + exit(1); + } + } + printf("%s", type3_output); + fflush(stdout); + } + else { + printf("Unknown request\n"); + msgbuf = printable(buf, 0); + if(msgbuf) { + logmsg("invalid input: '%s'\n", msgbuf); + free(msgbuf); + } + else + logmsg("OOM formatting invalid input: '%s'\n", buf); + exit(1); + } + } + return 1; +} diff --git a/tests/server/getpart.c b/tests/server/getpart.c index 743cb21b9..9384d0cb0 100644 --- a/tests/server/getpart.c +++ b/tests/server/getpart.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -49,7 +49,7 @@ struct SessionHandle { #ifdef DEBUG_GETPART #define show(x) printf x #else -#define show(x) +#define show(x) Curl_nop_stmt #endif #if defined(_MSC_VER) && defined(_DLL) @@ -166,7 +166,9 @@ static int appenddata(char **dst_buf, /* dest buffer */ if(src_b64) { /* base64 decode the given buffer */ - src_len = Curl_base64_decode(src_buf, &buf64.as_uchar); + int error = (int) Curl_base64_decode(src_buf, &buf64.as_uchar, &src_len); + if(error) + return GPE_OUT_OF_MEMORY; src_buf = buf64.as_char; if(!src_len || !src_buf) { /* diff --git a/tests/server/sws.c b/tests/server/sws.c index 949831d6c..b2d6df7a6 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -107,7 +107,7 @@ struct httprequest { bool digest; /* Authorization digest header found */ bool ntlm; /* Authorization ntlm header found */ int writedelay; /* if non-zero, delay this number of seconds between - writes in the response */ + writes in the response */ int pipe; /* if non-zero, expect this many requests to do a "piped" request/response */ int skip; /* if non-zero, the server is instructed to not read this @@ -117,6 +117,7 @@ struct httprequest { int rcmd; /* doing a special command, see defines above */ int prot_version; /* HTTP version * 10 */ bool pipelining; /* true if request is pipelined */ + int callcount; /* times ProcessRequest() gets called */ }; static int ProcessRequest(struct httprequest *req); @@ -308,13 +309,16 @@ static int ProcessRequest(struct httprequest *req) bool chunked = FALSE; static char request[REQUEST_KEYWORD_SIZE]; static char doc[MAXDOCNAMELEN]; - char logbuf[256]; + char logbuf[456]; int prot_major, prot_minor; char *end; int error; end = strstr(line, end_of_headers); - logmsg("ProcessRequest() called"); + req->callcount++; + + logmsg("Process %d bytes request%s", req->offset, + req->callcount > 1?" [CONTINUED]":""); /* try to figure out the request characteristics as soon as possible, but only once! */ @@ -346,7 +350,7 @@ static int ProcessRequest(struct httprequest *req) FILE *stream; char *filename; - if((strlen(doc) + strlen(request)) < 200) + if((strlen(doc) + strlen(request)) < 400) sprintf(logbuf, "Got request: %s %s HTTP/%d.%d", request, doc, prot_major, prot_minor); else @@ -397,12 +401,13 @@ static int ProcessRequest(struct httprequest *req) return 1; /* done */ } else { + char *orgcmd = NULL; char *cmd = NULL; size_t cmdsize = 0; int num=0; /* get the custom server control "commands" */ - error = getpart(&cmd, &cmdsize, "reply", "servercmd", stream); + error = getpart(&orgcmd, &cmdsize, "reply", "servercmd", stream); fclose(stream); if(error) { logmsg("getpart() failed with error: %d", error); @@ -410,8 +415,9 @@ static int ProcessRequest(struct httprequest *req) return 1; /* done */ } - if(cmdsize) { - logmsg("Found a reply-servercmd section!"); + cmd = orgcmd; + while(cmd && cmdsize) { + char *check; if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) { logmsg("instructed to require authorization header"); @@ -445,9 +451,26 @@ static int ProcessRequest(struct httprequest *req) else { logmsg("funny instruction found: %s", cmd); } + /* try to deal with CRLF or just LF */ + check = strchr(cmd, '\r'); + if(!check) + check = strchr(cmd, '\n'); + + if(check) { + /* get to the letter following the newline */ + while((*check == '\r') || (*check == '\n')) + check++; + + if(!*check) + /* if we reached a zero, get out */ + break; + cmd = check; + } + else + break; } - if(cmd) - free(cmd); + if(orgcmd) + free(orgcmd); } } else { @@ -481,13 +504,17 @@ static int ProcessRequest(struct httprequest *req) } } } + else if((req->offset >= 3) && (req->testno == DOCNUMBER_NOTHING)) { + logmsg("** Unusual request. Starts with %02x %02x %02x", + line[0], line[1], line[2]); + } if(!end) { /* we don't have a complete request yet! */ - logmsg("ProcessRequest returned without a complete request"); + logmsg("request not complete yet"); return 0; /* not complete yet */ } - logmsg("ProcessRequest found a complete request"); + logmsg("- request found to be complete"); if(use_gopher) { /* when using gopher we cannot check the request until the entire @@ -616,10 +643,11 @@ static int ProcessRequest(struct httprequest *req) req->ntlm = TRUE; /* NTLM found */ logmsg("Received NTLM type-1, sending back data %ld", req->partno); } - else if((req->partno >= 1000) && strstr(req->reqbuf, "Authorization: Basic")) { - /* If the client is passing this Basic-header and the part number is already - >=1000, we add 1 to the part number. This allows simple Basic authentication - negotiation to work in the test suite. */ + else if((req->partno >= 1000) && + strstr(req->reqbuf, "Authorization: Basic")) { + /* If the client is passing this Basic-header and the part number is + already >=1000, we add 1 to the part number. This allows simple Basic + authentication negotiation to work in the test suite. */ req->partno += 1; logmsg("Received Basic request, sending back data %ld", req->partno); } @@ -631,6 +659,7 @@ static int ProcessRequest(struct httprequest *req) req->prot_version >= 11 && end && req->reqbuf + req->offset > end + strlen(end_of_headers) && + !req->cl && (!strncmp(req->reqbuf, "GET", strlen("GET")) || !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) { /* If we have a persistent connection, HTTP version >= 1.1 @@ -655,8 +684,10 @@ static int ProcessRequest(struct httprequest *req) makes the server NOT wait for PUT/POST data and you can then make the test case send a rejection before any such data has been sent. Test case 154 uses this.*/ - if(req->auth_req && !req->auth) + if(req->auth_req && !req->auth) { + logmsg("Return early due to auth requested by none provided"); return 1; /* done */ + } if(req->cl > 0) { if(req->cl <= req->offset - (end - req->reqbuf) - strlen(end_of_headers)) @@ -756,6 +787,7 @@ static int get_request(curl_socket_t sock, struct httprequest *req) req->rcmd = RCMD_NORMALREQ; req->prot_version = 0; req->pipelining = FALSE; + req->callcount = 0; /*** end of httprequest init ***/ @@ -767,9 +799,9 @@ static int get_request(curl_socket_t sock, struct httprequest *req) } else { if(req->skip) - /* we are instructed to not read the entire thing, so we make sure to only - read what we're supposed to and NOT read the enire thing the client - wants to send! */ + /* we are instructed to not read the entire thing, so we make sure to + only read what we're supposed to and NOT read the enire thing the + client wants to send! */ got = sread(sock, reqbuf + req->offset, req->cl); else got = sread(sock, reqbuf + req->offset, REQBUFSIZ-1 - req->offset); @@ -851,7 +883,7 @@ static int send_doc(curl_socket_t sock, struct httprequest *req) char partbuf[80]="data"; - logmsg("Send response number %ld part %ld", req->testno, req->partno); + logmsg("Send response test%ld section <data%ld>", req->testno, req->partno); switch(req->rcmd) { default: @@ -1394,8 +1426,13 @@ int main(int argc, char *argv[]) break; } - if(req.open) - logmsg("=> persistant connection request ended, awaits new request"); + if(req.open) { + logmsg("=> persistant connection request ended, awaits new request\n"); + /* + const char *keepopen="[KEEPING CONNECTION OPEN]"; + storerequest((char *)keepopen, strlen(keepopen)); + */ + } /* if we got a CONNECT, loop and get another request as well! */ } while(req.open || (req.testno == DOCNUMBER_CONNECT)); @@ -1403,6 +1440,14 @@ int main(int argc, char *argv[]) break; logmsg("====> Client disconnect"); + + if(!req.open) + /* When instructed to close connection after server-reply we + wait a very small amount of time before doing so. If this + is not done client might get an ECONNRESET before reading + a single byte of server-reply. */ + wait_ms(50); + sclose(msgsock); msgsock = CURL_SOCKET_BAD; diff --git a/tests/serverhelp.pm b/tests/serverhelp.pm index faaeebfd0..a1d1dc367 100644 --- a/tests/serverhelp.pm +++ b/tests/serverhelp.pm @@ -5,7 +5,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -63,6 +63,13 @@ use vars qw( #*************************************************************************** +# Just for convenience, test harness uses 'https' and 'httptls' literals as +# values for 'proto' variable in order to differentiate different servers. +# 'https' literal is used for stunnel based https test servers, and 'httptls' +# is used for non-stunnel https test servers. + + +#*************************************************************************** # Return server characterization factors given a server id string. # sub serverfactors { @@ -71,18 +78,20 @@ sub serverfactors { my $ipvnum; my $idnum; - if($server =~ /^((ftp|http|imap|pop3|smtp)s?)(\d*)(-ipv6|)$/) { + if($server =~ + /^((ftp|http|imap|pop3|smtp)s?)(\d*)(-ipv6|)$/) { $proto = $1; $idnum = ($3 && ($3 > 1)) ? $3 : 1; $ipvnum = ($4 && ($4 =~ /6$/)) ? 6 : 4; } - elsif($server =~ /^(tftp|sftp|socks|ssh|rtsp)(\d*)(-ipv6|)$/) { + elsif($server =~ + /^(tftp|sftp|socks|ssh|rtsp|gopher|httptls)(\d*)(-ipv6|)$/) { $proto = $1; $idnum = ($2 && ($2 > 1)) ? $2 : 1; $ipvnum = ($3 && ($3 =~ /6$/)) ? 6 : 4; } else { - die "invalid server id: $server" + die "invalid server id: '$server'" } return($proto, $ipvnum, $idnum); } @@ -95,16 +104,16 @@ sub servername_str { my ($proto, $ipver, $idnum) = @_; $proto = uc($proto) if($proto); - die "unsupported protocol: $proto" unless($proto && - ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER|HTTP\+TLS-SRP))$/)); + die "unsupported protocol: '$proto'" unless($proto && + ($proto =~ /^(((FTP|HTTP|IMAP|POP3|SMTP)S?)|(TFTP|SFTP|SOCKS|SSH|RTSP|GOPHER|HTTPTLS))$/)); $ipver = (not $ipver) ? 'ipv4' : lc($ipver); - die "unsupported IP version: $ipver" unless($ipver && + die "unsupported IP version: '$ipver'" unless($ipver && ($ipver =~ /^(4|6|ipv4|ipv6|-ipv4|-ipv6)$/)); $ipver = ($ipver =~ /6$/) ? '-IPv6' : ''; $idnum = 1 if(not $idnum); - die "unsupported ID number: $idnum" unless($idnum && + die "unsupported ID number: '$idnum'" unless($idnum && ($idnum =~ /^(\d+)$/)); $idnum = '' unless($idnum > 1); @@ -188,7 +197,7 @@ sub server_outputfilename { # sub mainsockf_pidfilename { my ($proto, $ipver, $idnum) = @_; - die "unsupported protocol: $proto" unless($proto && + die "unsupported protocol: '$proto'" unless($proto && (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/)); my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.pid':'_sockfilt.pid'; return '.'. servername_canon($proto, $ipver, $idnum) ."$trailer"; @@ -200,7 +209,7 @@ sub mainsockf_pidfilename { # sub mainsockf_logfilename { my ($logdir, $proto, $ipver, $idnum) = @_; - die "unsupported protocol: $proto" unless($proto && + die "unsupported protocol: '$proto'" unless($proto && (lc($proto) =~ /^(ftp|imap|pop3|smtp)s?$/)); my $trailer = (lc($proto) =~ /^ftps?$/) ? '_sockctrl.log':'_sockfilt.log'; return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; @@ -212,7 +221,7 @@ sub mainsockf_logfilename { # sub datasockf_pidfilename { my ($proto, $ipver, $idnum) = @_; - die "unsupported protocol: $proto" unless($proto && + die "unsupported protocol: '$proto'" unless($proto && (lc($proto) =~ /^ftps?$/)); my $trailer = '_sockdata.pid'; return '.'. servername_canon($proto, $ipver, $idnum) ."$trailer"; @@ -224,7 +233,7 @@ sub datasockf_pidfilename { # sub datasockf_logfilename { my ($logdir, $proto, $ipver, $idnum) = @_; - die "unsupported protocol: $proto" unless($proto && + die "unsupported protocol: '$proto'" unless($proto && (lc($proto) =~ /^ftps?$/)); my $trailer = '_sockdata.log'; return "${logdir}/". servername_canon($proto, $ipver, $idnum) ."$trailer"; diff --git a/tests/sshhelp.pm b/tests/sshhelp.pm index 493cbfed8..ced9a01d1 100644 --- a/tests/sshhelp.pm +++ b/tests/sshhelp.pm @@ -39,6 +39,7 @@ use vars qw( $sftpsrvexe $sftpexe $sshkeygenexe + $httptlssrvexe $sshdconfig $sshconfig $sftpconfig @@ -52,6 +53,7 @@ use vars qw( $cliprvkeyf $clipubkeyf @sftppath + @httptlssrvpath ); @@ -95,7 +97,7 @@ use vars qw( find_sftpsrv find_sftp find_sshkeygen - find_gnutls_serv + find_httptlssrv logmsg sshversioninfo ); @@ -104,27 +106,28 @@ use vars qw( #*************************************************************************** # Global variables initialization # -$sshdexe = 'sshd' .exe_ext(); # base name and ext of ssh daemon -$sshexe = 'ssh' .exe_ext(); # base name and ext of ssh client -$sftpsrvexe = 'sftp-server' .exe_ext(); # base name and ext of sftp-server -$sftpexe = 'sftp' .exe_ext(); # base name and ext of sftp client -$sshkeygenexe = 'ssh-keygen' .exe_ext(); # base name and ext of ssh-keygen -$sshdconfig = 'curl_sshd_config'; # ssh daemon config file -$sshconfig = 'curl_ssh_config'; # ssh client config file -$sftpconfig = 'curl_sftp_config'; # sftp client config file -$sshdlog = undef; # ssh daemon log file -$sshlog = undef; # ssh client log file -$sftplog = undef; # sftp client log file -$sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file -$knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file -$hstprvkeyf = 'curl_host_dsa_key'; # host private key file -$hstpubkeyf = 'curl_host_dsa_key.pub'; # host public key file -$cliprvkeyf = 'curl_client_key'; # client private key file -$clipubkeyf = 'curl_client_key.pub'; # client public key file +$sshdexe = 'sshd' .exe_ext(); # base name and ext of ssh daemon +$sshexe = 'ssh' .exe_ext(); # base name and ext of ssh client +$sftpsrvexe = 'sftp-server' .exe_ext(); # base name and ext of sftp-server +$sftpexe = 'sftp' .exe_ext(); # base name and ext of sftp client +$sshkeygenexe = 'ssh-keygen' .exe_ext(); # base name and ext of ssh-keygen +$httptlssrvexe = 'gnutls-serv' .exe_ext(); # base name and ext of gnutls-serv +$sshdconfig = 'curl_sshd_config'; # ssh daemon config file +$sshconfig = 'curl_ssh_config'; # ssh client config file +$sftpconfig = 'curl_sftp_config'; # sftp client config file +$sshdlog = undef; # ssh daemon log file +$sshlog = undef; # ssh client log file +$sftplog = undef; # sftp client log file +$sftpcmds = 'curl_sftp_cmds'; # sftp client commands batch file +$knownhosts = 'curl_client_knownhosts'; # ssh knownhosts file +$hstprvkeyf = 'curl_host_dsa_key'; # host private key file +$hstpubkeyf = 'curl_host_dsa_key.pub'; # host public key file +$cliprvkeyf = 'curl_client_key'; # client private key file +$clipubkeyf = 'curl_client_key.pub'; # client public key file #*************************************************************************** -# Absolute paths where to look for sftp-server plugin +# Absolute paths where to look for sftp-server plugin, when not in PATH # @sftppath = qw( /usr/lib/openssh @@ -150,6 +153,30 @@ $clipubkeyf = 'curl_client_key.pub'; # client public key file #*************************************************************************** +# Absolute paths where to look for httptlssrv (gnutls-serv), when not in PATH +# +@httptlssrvpath = qw( + /usr/sbin + /usr/libexec + /usr/lib + /usr/lib/misc + /usr/lib64/misc + /usr/local/bin + /usr/local/sbin + /usr/local/libexec + /opt/local/bin + /opt/local/sbin + /opt/local/libexec + /usr/freeware/bin + /usr/freeware/sbin + /usr/freeware/libexec + /opt/gnutls/bin + /opt/gnutls/sbin + /opt/gnutls/libexec + ); + + +#*************************************************************************** # Return file extension for executable files on this operating system # sub exe_ext { @@ -273,7 +300,7 @@ sub find_file { my @path = @_; foreach (@path) { my $file = File::Spec->catfile($_, $fn); - if(-e $file) { + if(-e $file && ! -d $file) { return $file; } } @@ -281,9 +308,27 @@ sub find_file { #*************************************************************************** +# Find an executable file somewhere in the given path +# +sub find_exe_file { + my $fn = $_[0]; + shift; + my @path = @_; + my $xext = exe_ext(); + foreach (@path) { + my $file = File::Spec->catfile($_, $fn); + if(-e $file && ! -d $file) { + return $file if(-x $file); + return $file if(($xext) && (lc($file) =~ /\Q$xext\E$/)); + } + } +} + + +#*************************************************************************** # Find a file in environment path or in our sftppath # -sub find_sfile { +sub find_file_spath { my $filename = $_[0]; my @spath; push(@spath, File::Spec->path()); @@ -291,18 +336,24 @@ sub find_sfile { return find_file($filename, @spath); } + #*************************************************************************** -# Find gnutls-serv and return canonical filename +# Find an executable file in environment path or in our httptlssrvpath # -sub find_gnutls_serv { - return find_file("gnutls-serv", split(':', $ENV{PATH})); +sub find_exe_file_hpath { + my $filename = $_[0]; + my @hpath; + push(@hpath, File::Spec->path()); + push(@hpath, @httptlssrvpath); + return find_exe_file($filename, @hpath); } + #*************************************************************************** # Find ssh daemon and return canonical filename # sub find_sshd { - return find_sfile($sshdexe); + return find_file_spath($sshdexe); } @@ -310,7 +361,7 @@ sub find_sshd { # Find ssh client and return canonical filename # sub find_ssh { - return find_sfile($sshexe); + return find_file_spath($sshexe); } @@ -318,7 +369,7 @@ sub find_ssh { # Find sftp-server plugin and return canonical filename # sub find_sftpsrv { - return find_sfile($sftpsrvexe); + return find_file_spath($sftpsrvexe); } @@ -326,7 +377,7 @@ sub find_sftpsrv { # Find sftp client and return canonical filename # sub find_sftp { - return find_sfile($sftpexe); + return find_file_spath($sftpexe); } @@ -334,7 +385,15 @@ sub find_sftp { # Find ssh-keygen and return canonical filename # sub find_sshkeygen { - return find_sfile($sshkeygenexe); + return find_file_spath($sshkeygenexe); +} + + +#*************************************************************************** +# Find httptlssrv (gnutls-serv) and return canonical filename +# +sub find_httptlssrv { + return find_exe_file_hpath($httptlssrvexe); } diff --git a/tests/sshserver.pl b/tests/sshserver.pl index b4390158d..8bb8bcdcf 100755 --- a/tests/sshserver.pl +++ b/tests/sshserver.pl @@ -6,7 +6,7 @@ # | (__| |_| | _ <| |___ # \___|\___/|_| \_\_____| # -# Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. +# Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. # # This software is licensed as described in the file COPYING, which # you should have received as part of this distribution. The terms @@ -362,8 +362,10 @@ if((($sshid =~ /OpenSSH/) && ($sshvernum < 299)) || #*************************************************************************** # Generate host and client key files for curl's tests # -if((! -e $hstprvkeyf) || (! -e $hstpubkeyf) || - (! -e $cliprvkeyf) || (! -e $clipubkeyf)) { +if((! -e $hstprvkeyf) || (! -s $hstprvkeyf) || + (! -e $hstpubkeyf) || (! -s $hstpubkeyf) || + (! -e $cliprvkeyf) || (! -s $cliprvkeyf) || + (! -e $clipubkeyf) || (! -s $clipubkeyf)) { # Make sure all files are gone so ssh-keygen doesn't complain unlink($hstprvkeyf, $hstpubkeyf, $cliprvkeyf, $clipubkeyf); logmsg 'generating host keys...' if($verbose); @@ -706,8 +708,9 @@ if(system "$sshd -t -f $sshdconfig > $sshdlog 2>&1") { #*************************************************************************** # Generate ssh client host key database file for curl's tests # -if(! -e $knownhosts) { +if((! -e $knownhosts) || (! -s $knownhosts)) { logmsg 'generating ssh client known hosts file...' if($verbose); + unlink($knownhosts); if(open(DSAKEYFILE, "<$hstpubkeyf")) { my @dsahostkey = do { local $/ = ' '; <DSAKEYFILE> }; if(close(DSAKEYFILE)) { diff --git a/tests/unit/curlcheck.h b/tests/unit/curlcheck.h index 4b4d32c8d..96203e075 100644 --- a/tests/unit/curlcheck.h +++ b/tests/unit/curlcheck.h @@ -49,7 +49,7 @@ fprintf(stderr, "%s:%d test failed: '%s'\n", \ __FILE__, __LINE__, msg); \ unitfail++; \ - } while(0) + } WHILE_FALSE /* The abort macros mark the current test step as failed, and exit the test */ @@ -74,7 +74,7 @@ __FILE__, __LINE__, msg); \ unitfail++; \ goto unit_test_abort; \ - } while(0) + } WHILE_FALSE diff --git a/tests/unit/unit1300.c b/tests/unit/unit1300.c index 199cf2c9e..2b8341683 100644 --- a/tests/unit/unit1300.c +++ b/tests/unit/unit1300.c @@ -40,8 +40,10 @@ static CURLcode unit_setup(void) if(!llist) return CURLE_OUT_OF_MEMORY; llist_destination = Curl_llist_alloc(test_curl_llist_dtor); - if(!llist_destination) + if(!llist_destination) { + Curl_llist_destroy(llist, NULL); return CURLE_OUT_OF_MEMORY; + } return CURLE_OK; } diff --git a/tests/unit/unit1302.c b/tests/unit/unit1302.c index 7a61ec062..fc50c8865 100644 --- a/tests/unit/unit1302.c +++ b/tests/unit/unit1302.c @@ -45,63 +45,80 @@ UNITTEST_START char *output; unsigned char *decoded; -size_t rc; +size_t size = 0; +unsigned char anychar = 'x'; +CURLcode rc; -rc = Curl_base64_encode(data, "i", 1, &output); -fail_unless( rc == 4 , "return code should be 4" ); +rc = Curl_base64_encode(data, "i", 1, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 4, "size should be 4"); verify_memory( output, "aQ==", 4); Curl_safefree(output); -rc = Curl_base64_encode(data, "ii", 2, &output); -fail_unless( rc == 4 , "return code should be 4" ); +rc = Curl_base64_encode(data, "ii", 2, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 4, "size should be 4"); verify_memory( output, "aWk=", 4); Curl_safefree(output); -rc = Curl_base64_encode(data, "iii", 3, &output); -fail_unless( rc == 4 , "return code should be 4" ); +rc = Curl_base64_encode(data, "iii", 3, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 4, "size should be 4"); verify_memory( output, "aWlp", 4); Curl_safefree(output); -rc = Curl_base64_encode(data, "iiii", 4, &output); -fail_unless( rc == 8 , "return code should be 8" ); +rc = Curl_base64_encode(data, "iiii", 4, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 8, "size should be 8"); verify_memory( output, "aWlpaQ==", 8); Curl_safefree(output); /* 0 length makes it do strlen() */ -rc = Curl_base64_encode(data, "iiii", 0, &output); -fail_unless( rc == 8 , "return code should be 8" ); +rc = Curl_base64_encode(data, "iiii", 0, &output, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 8, "size should be 8"); verify_memory( output, "aWlpaQ==", 8); Curl_safefree(output); -rc = Curl_base64_decode("aWlpaQ==", &decoded); -fail_unless(rc == 4, "return code should be 4"); +rc = Curl_base64_decode("aWlpaQ==", &decoded, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 4, "size should be 4"); verify_memory(decoded, "iiii", 4); Curl_safefree(decoded); -rc = Curl_base64_decode("aWlp", &decoded); -fail_unless(rc == 3, "return code should be 3"); +rc = Curl_base64_decode("aWlp", &decoded, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 3, "size should be 3"); verify_memory(decoded, "iii", 3); Curl_safefree(decoded); -rc = Curl_base64_decode("aWk=", &decoded); -fail_unless(rc == 2, "return code should be 2"); +rc = Curl_base64_decode("aWk=", &decoded, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 2, "size should be 2"); verify_memory(decoded, "ii", 2); Curl_safefree(decoded); -rc = Curl_base64_decode("aQ==", &decoded); -fail_unless(rc == 1, "return code should be 1"); +rc = Curl_base64_decode("aQ==", &decoded, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 1, "size should be 1"); verify_memory(decoded, "i", 2); Curl_safefree(decoded); /* this is an illegal input */ -decoded = NULL; -rc = Curl_base64_decode("aQ", &decoded); -fail_unless(rc == 0, "return code should be 0"); +size = 1; /* not zero */ +decoded = &anychar; /* not NULL */ +rc = Curl_base64_decode("aQ", &decoded, &size); +/* return code indiferent, but output shall be as follows */ +fail_unless(size == 0, "size should be 0"); fail_if(decoded, "returned pointer should be NULL"); /* this is garbage input that libcurl decodes as far as possible */ -rc = Curl_base64_decode("a\x1f==", &decoded); -fail_unless(rc == 1, "return code should be 1"); +size = 0; +decoded = NULL; +rc = Curl_base64_decode("a\x1f==", &decoded, &size); +fail_unless(rc == CURLE_OK, "return code should be CURLE_OK"); +fail_unless(size == 1, "size should be 1"); +fail_if(!decoded, "returned pointer should not be NULL"); Curl_safefree(decoded); UNITTEST_STOP diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c index 7b2985c58..8ddd8caee 100644 --- a/tests/unit/unit1304.c +++ b/tests/unit/unit1304.c @@ -41,7 +41,7 @@ static void unit_stop(void) UNITTEST_START int result; - static const char* filename1 = "log/netrc"; + static const char* filename1 = "log/netrc1304"; memcpy(filename, filename1, strlen(filename1)); /* |