Compare commits
	
		
			352 Commits
		
	
	
		
			curl-7_30_
			...
			curl-7_32_
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 70812c2f32 | ||
|   | a64bca68c7 | ||
|   | 67633e1308 | ||
|   | 715ca7c5fe | ||
|   | 001758760b | ||
|   | 2f06265e39 | ||
|   | 432431368f | ||
|   | 4b0028f82d | ||
|   | 8c9236bb2c | ||
|   | 2af0b10c95 | ||
|   | 08adecc9a1 | ||
|   | 015556d74c | ||
|   | 4c40fe64b8 | ||
|   | d20def2046 | ||
|   | d2b36e466a | ||
|   | 27f8c93daf | ||
|   | 058b86e6f3 | ||
|   | 0018d6830e | ||
|   | 59224a31fd | ||
|   | 0994d737c8 | ||
|   | 96749554fd | ||
|   | 785749405f | ||
|   | 7cc00d9a83 | ||
|   | 230e16dc03 | ||
|   | 0ce410a629 | ||
|   | 5d3cbde72e | ||
|   | 8fe8fd2b17 | ||
|   | 0ddc678927 | ||
|   | 51f0b798fa | ||
|   | 6b27703b5f | ||
|   | 045ccb59a4 | ||
|   | 784336deec | ||
|   | eb41e8eebe | ||
|   | 3cd43bbfec | ||
|   | 204e340bcd | ||
|   | 37f2ba7e57 | ||
|   | 09b9fc9009 | ||
|   | 7da3caaf95 | ||
|   | 82ab5f1b0c | ||
|   | 7ae64af368 | ||
|   | 2ad688ed7c | ||
|   | ca786233d2 | ||
|   | 14a3139c4d | ||
|   | 5af2bfb955 | ||
|   | 1691a31cab | ||
|   | 9dedcbf9ec | ||
|   | 537ffc4c69 | ||
|   | c3e7210548 | ||
|   | 9a5c2d8373 | ||
|   | 8693bbd8c4 | ||
|   | 251dd03b88 | ||
|   | 55ea83d622 | ||
|   | b5478a0e03 | ||
|   | db2deba6b4 | ||
|   | 41fb6443ce | ||
|   | e5dfe6c282 | ||
|   | e277e20a6d | ||
|   | a23e56d109 | ||
|   | ca89a0a092 | ||
|   | 50a74be125 | ||
|   | 8c1e3bb713 | ||
|   | 4fad1943a2 | ||
|   | 4d346673a2 | ||
|   | de052ca6fc | ||
|   | 1a593191c2 | ||
|   | 2c4ef997b9 | ||
|   | d020e2c381 | ||
|   | 48fe9226a0 | ||
|   | a77ac42e52 | ||
|   | 5880db8abd | ||
|   | 0f4ba89ffd | ||
|   | edeb1ae65f | ||
|   | 82232bbbaf | ||
|   | bb2e0686ab | ||
|   | 513e587c5e | ||
|   | 6ed2bcc5f5 | ||
|   | d529f3882b | ||
|   | e2e92486a7 | ||
|   | 2e5b3168d6 | ||
|   | 6bcacff1a5 | ||
|   | 12d01cb6fa | ||
|   | 90695fb2c5 | ||
|   | dd17069c9e | ||
|   | 26b0cb6ae2 | ||
|   | 6d30f8ebed | ||
|   | 11220678c4 | ||
|   | 448d55ef0a | ||
|   | 7b115cc1e1 | ||
|   | a10d5e3851 | ||
|   | 1016637f5a | ||
|   | 2e00872c04 | ||
|   | 56ece42c81 | ||
|   | 99924f6606 | ||
|   | 0eba02fd41 | ||
|   | 464c8693d2 | ||
|   | 50af17ef24 | ||
|   | 3a24cb7bc4 | ||
|   | e839446c2a | ||
|   | 695931cf8e | ||
|   | 964a7600b9 | ||
|   | d4492f955d | ||
|   | 9c15325d34 | ||
|   | d8c04909fa | ||
|   | c0a7a98aee | ||
|   | f5005dd8d0 | ||
|   | d3aaa68f55 | ||
|   | cfc907e43d | ||
|   | 2af64c6432 | ||
|   | 83f0dae129 | ||
|   | 65d53cf6ef | ||
|   | 0d9e65f79f | ||
|   | c983aa9efc | ||
|   | b16b7f9d3a | ||
|   | 5c6f12b9f2 | ||
|   | 2022b10e50 | ||
|   | 45339625bc | ||
|   | 20ff820ef2 | ||
|   | 39e85d99fe | ||
|   | 3a0e931fc7 | ||
|   | fe7e3229f8 | ||
|   | ecf042ff3c | ||
|   | aff245b360 | ||
|   | e01469907a | ||
|   | b7a933154a | ||
|   | 54f18e5427 | ||
|   | 833fba265d | ||
|   | d633052905 | ||
|   | 009d2336fe | ||
|   | abca89aaa0 | ||
|   | d689376cb0 | ||
|   | 98b0d66eb4 | ||
|   | 9c2853f2ae | ||
|   | aff7562922 | ||
|   | 365c5ba395 | ||
|   | cb1aa8b0e3 | ||
|   | d3d5c4a40e | ||
|   | 6117d4025e | ||
|   | d23745f7c9 | ||
|   | ad47d8e263 | ||
|   | 8a7a277c08 | ||
|   | 0030fbd382 | ||
|   | f3052c8a81 | ||
|   | 7d80ed64e4 | ||
|   | a2e0ce86ba | ||
|   | 6fab0bd9f1 | ||
|   | 02964ed630 | ||
|   | 6f3e7aabdc | ||
|   | 631e3e13a9 | ||
|   | 832c195179 | ||
|   | 7877619f85 | ||
|   | ec248b590d | ||
|   | 4846b5e9fe | ||
|   | 85c710e11e | ||
|   | 0de7249bb3 | ||
|   | 192c4f788d | ||
|   | da0db499fd | ||
|   | 88c5c63ffc | ||
|   | a9f5ad0e2a | ||
|   | e305f5ec71 | ||
|   | 7ac3e9f1ba | ||
|   | 03a3dd9ee3 | ||
|   | 5fc24a5297 | ||
|   | b1a295ac4e | ||
|   | 1826c768ab | ||
|   | 9c3e098259 | ||
|   | 0feeab7802 | ||
|   | f24dc09d20 | ||
|   | 9e10963c20 | ||
|   | 10b6d81c64 | ||
|   | 8026bd7abd | ||
|   | 9b8df58169 | ||
|   | 529a2e9110 | ||
|   | 21091549c0 | ||
|   | 7b97f03f09 | ||
|   | ce362e8eb9 | ||
|   | a4decb49a6 | ||
|   | c53fb36b0c | ||
|   | dc19e656b5 | ||
|   | 87cf677eca | ||
|   | 5657c56f63 | ||
|   | 51b3445e84 | ||
|   | a7452b8b8c | ||
|   | 0bf5ce77aa | ||
|   | 159d34b58e | ||
|   | 29bf0598aa | ||
|   | 239b58d34d | ||
|   | 74f1810546 | ||
|   | f4b08b8f40 | ||
|   | 6691fdf517 | ||
|   | 7d8d2a54ba | ||
|   | 9986c6cb2b | ||
|   | ba9a66663a | ||
|   | ac419bf562 | ||
|   | 520833cbe1 | ||
|   | e58d9c87f7 | ||
|   | 84f7991474 | ||
|   | 85b9dc8023 | ||
|   | 7d4d4892d8 | ||
|   | fc4759af9d | ||
|   | ee84c47655 | ||
|   | ce32176db7 | ||
|   | 04f52e9b4d | ||
|   | 100a33f7ff | ||
|   | 7ed25ccf0d | ||
|   | 01eede2662 | ||
|   | ae26ee3489 | ||
|   | 992bee504d | ||
|   | 01a2abedd7 | ||
|   | a45e3f93e4 | ||
|   | bdb396ef2a | ||
|   | 6add1901a1 | ||
|   | 51b0f09b5e | ||
|   | 8dac7be438 | ||
|   | bcf1b9dec1 | ||
|   | b045d079f8 | ||
|   | 683f2b8323 | ||
|   | 2de20dd9a1 | ||
|   | b47cf4f688 | ||
|   | a15b2b6c62 | ||
|   | 42e01cff9a | ||
|   | 865d4138a0 | ||
|   | 35874298e4 | ||
|   | 52d72e66c2 | ||
|   | f3d10aa0d4 | ||
|   | 7632bc911b | ||
|   | 92ef5f19c8 | ||
|   | 99b4045183 | ||
|   | 087f9bb20a | ||
|   | e2c7e19144 | ||
|   | f5c3d95384 | ||
|   | 6b10f5b963 | ||
|   | ee74b77d45 | ||
|   | 734bdb68c2 | ||
|   | 514817669e | ||
|   | cb9c0ac7d7 | ||
|   | 1c435295b8 | ||
|   | 46d26a0e77 | ||
|   | f4e3cae8a7 | ||
|   | b52cf5d2cd | ||
|   | 073e83b543 | ||
|   | c3e6d69acb | ||
|   | b56e3d43e5 | ||
|   | f317ffb7bb | ||
|   | 9ea5145952 | ||
|   | 1d7c38e1f0 | ||
|   | 18bfc8f2d7 | ||
|   | 945246988d | ||
|   | a5c0e20939 | ||
|   | 128517649c | ||
|   | 219358b93d | ||
|   | f133719f73 | ||
|   | f4e6e201b1 | ||
|   | 790b2086d7 | ||
|   | f9b691cdb0 | ||
|   | 4118c30261 | ||
|   | dacbdaab94 | ||
|   | 70e30f6caa | ||
|   | 7cb6c31370 | ||
|   | 5d3a031ca7 | ||
|   | a846fbbe2a | ||
|   | 6420672879 | ||
|   | c4067a5678 | ||
|   | 0523152ad6 | ||
|   | b37b5233ca | ||
|   | c68c7e588e | ||
|   | 1498a0073e | ||
|   | 27777949a0 | ||
|   | 4dc2d965d6 | ||
|   | 70bbbccc39 | ||
|   | 0dd470fc61 | ||
|   | 89acdf50fa | ||
|   | c0d502785f | ||
|   | a8c92cb608 | ||
|   | 53fda844cc | ||
|   | bbf63b0faa | ||
|   | 2af9fd4960 | ||
|   | 2c0d65785f | ||
|   | d791179d7f | ||
|   | c49ed0b6c0 | ||
|   | 868d8e6831 | ||
|   | e3aca1b2ce | ||
|   | ddac43b38e | ||
|   | 416ecc1584 | ||
|   | 455ba691a7 | ||
|   | 11332577b3 | ||
|   | 702b0dd408 | ||
|   | e8a9f794f0 | ||
|   | bddf3d4705 | ||
|   | e99c81a07c | ||
|   | fe880475ed | ||
|   | 5821d5f111 | ||
|   | d535c4a2e1 | ||
|   | ca8f17a303 | ||
|   | fddb7b44a7 | ||
|   | 49184c3723 | ||
|   | cc7f6a2ddf | ||
|   | 90fe59b829 | ||
|   | 7b074a460b | ||
|   | 993cdcd6ee | ||
|   | 8763374f0e | ||
|   | 63388fe1f3 | ||
|   | b75a88aa72 | ||
|   | bb20989a63 | ||
|   | 0d49e408a4 | ||
|   | 90c87f311e | ||
|   | da06ac7f3f | ||
|   | 6d9236e805 | ||
|   | c306d2e42f | ||
|   | f737e3a3dd | ||
|   | 686586b0f9 | ||
|   | e621a5f6ea | ||
|   | 8093f9541e | ||
|   | 68e7fb499d | ||
|   | d9569720dd | ||
|   | 1c40685d32 | ||
|   | 31c6e7af6a | ||
|   | 552ba67bb1 | ||
|   | 651254dcc7 | ||
|   | 26bdafcbf9 | ||
|   | 02dc9e788f | ||
|   | e11c6e9961 | ||
|   | e4eaa92728 | ||
|   | 577f8e5ac6 | ||
|   | 95ba6cdd54 | ||
|   | 7ce6cb9ab4 | ||
|   | 8723cade21 | ||
|   | d956d9db47 | ||
|   | ecf93ac986 | ||
|   | b3a01be2f3 | ||
|   | 00045a3009 | ||
|   | 3f7188dd94 | ||
|   | 720218fea1 | ||
|   | 73aa95592f | ||
|   | ad3fdbc0a4 | ||
|   | 73cbd21b5e | ||
|   | c5ba0c2f54 | ||
|   | edddf394b8 | ||
|   | 61d259f950 | ||
|   | c01735865f | ||
|   | ca46c5dbe2 | ||
|   | 2da127abb5 | ||
|   | bc33f2200d | ||
|   | fd399cde00 | ||
|   | 00c74019f4 | ||
|   | 9d0063befa | ||
|   | 01e55ebb26 | ||
|   | 4bbad1dac7 | ||
|   | ddbda328b3 | ||
|   | 8ffbeeda80 | ||
|   | 1d1ffaf912 | ||
|   | e0cff02061 | ||
|   | 7fe95bb0d5 | 
| @@ -103,7 +103,7 @@ if test ! -z $SDK32; then | ||||
|   ln -fs ${FRAMEWORK_VERSION}/Resources Resources | ||||
|   ln -fs ${FRAMEWORK_VERSION}/Headers Headers | ||||
|   cd Versions | ||||
|   ln -fs ${FRAMEWORK_VERSION} Current | ||||
|   ln -fs $(basename "${FRAMEWORK_VERSION}") Current | ||||
|  | ||||
|   echo Testing for SDK64 | ||||
|   if test -d $SDK64_DIR; then | ||||
|   | ||||
| @@ -148,12 +148,24 @@ vc-ssl-zlib: $(VC) | ||||
| 	cd ..\src | ||||
| 	nmake /f Makefile.$(VC) cfg=release-ssl-zlib | ||||
|  | ||||
| vc-winssl-zlib: $(VC) | ||||
| 	cd lib | ||||
| 	nmake /f Makefile.$(VC) cfg=release-winssl-zlib | ||||
| 	cd ..\src | ||||
| 	nmake /f Makefile.$(VC) cfg=release-winssl-zlib | ||||
|  | ||||
| vc-x64-ssl-zlib: $(VC) | ||||
| 	cd lib | ||||
| 	nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-ssl-zlib | ||||
| 	cd ..\src | ||||
| 	nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-ssl-zlib | ||||
|  | ||||
| vc-x64-winssl-zlib: $(VC) | ||||
| 	cd lib | ||||
| 	nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-winssl-zlib | ||||
| 	cd ..\src | ||||
| 	nmake /f Makefile.$(VC) MACHINE=x64 cfg=release-winssl-zlib | ||||
|  | ||||
| vc-ssl-dll: $(VC) | ||||
| 	cd lib | ||||
| 	nmake /f Makefile.$(VC) cfg=release-ssl-dll | ||||
|   | ||||
							
								
								
									
										180
									
								
								RELEASE-NOTES
									
									
									
									
									
								
							
							
						
						
									
										180
									
								
								RELEASE-NOTES
									
									
									
									
									
								
							| @@ -1,11 +1,11 @@ | ||||
| Curl and libcurl 7.30.0 | ||||
| Curl and libcurl 7.32.0 | ||||
|  | ||||
|  Public curl releases:         132 | ||||
|  Public curl releases:         134 | ||||
|  Command line options:         152 | ||||
|  curl_easy_setopt() options:   199 | ||||
|  Public functions in libcurl:  58 | ||||
|  Known libcurl bindings:       42 | ||||
|  Contributors:                 1005 | ||||
|  Contributors:                 1049 | ||||
|  | ||||
| *** | ||||
|   krb4 support is up for removal. If you care about it at all, speak up | ||||
| @@ -14,75 +14,56 @@ Curl and libcurl 7.30.0 | ||||
|  | ||||
| This release includes the following changes: | ||||
|  | ||||
|  o imap: Changed response tag generation to be completely unique | ||||
|  o imap: Added support for SASL-IR extension | ||||
|  o imap: Added support for the list command | ||||
|  o imap: Added support for the append command | ||||
|  o imap: Added custom request parsing | ||||
|  o imap: Added support to the fetch command for UID and SECTION properties | ||||
|  o imap: Added parsing and verification of the UIDVALIDITY mailbox attribute | ||||
|  o darwinssl: Make certificate errors less techy | ||||
|  o imap/pop3/smtp: Added support for the STARTTLS capability | ||||
|  o checksrc: ban use of sprintf, vsprintf, strcat, strncat and gets | ||||
|  o curl_global_init() now accepts the CURL_GLOBAL_ACK_EINTR flag [10] | ||||
|  o Added CURLMOPT_MAX_HOST_CONNECTIONS, CURLMOPT_MAX_TOTAL_CONNECTIONS for | ||||
|    new multi interface connection handling | ||||
|  o Added CURLMOPT_MAX_PIPELINE_LENGTH, CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE, | ||||
|    CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE, CURLMOPT_PIPELINING_SITE_BL and | ||||
|    CURLMOPT_PIPELINING_SERVER_BL for new pipelining control [15] | ||||
|  o curl: allow timeouts to accept decimal values | ||||
|  o OS400: add slist and certinfo EBCDIC support | ||||
|  o OS400: new SSL backend GSKit | ||||
|  o CURLOPT_XFERINFOFUNCTION: introducing a new progress callback | ||||
|  o LIBCURL-STRUCTS: new document | ||||
|  | ||||
| This release includes the following bugfixes: | ||||
|  | ||||
|  o SECURITY ADVISORY: cookie tailmatching to avoid cross-domain leakage [25] | ||||
|  o darwinssl: Fix build under Leopard | ||||
|  o DONE: consider callback-aborted transfers premature [1] | ||||
|  o ntlm: Fixed memory leaks | ||||
|  o smtp: Fixed an issue when processing EHLO failure responses | ||||
|  o pop3: Fixed incorrect return value from pop3_endofresp() | ||||
|  o pop3: Fixed SASL authentication capability detection | ||||
|  o pop3: Fixed blocking SSL connect when connecting via POP3S | ||||
|  o imap: Fixed memory leak when performing multiple selects  | ||||
|  o nss: fix misplaced code enabling non-blocking socket mode | ||||
|  o AddFormData: prevent only directories from being posted [2] | ||||
|  o darwinssl: fix infinite loop if server disconnected abruptly [3] | ||||
|  o metalink: fix improbable crash parsing metalink filename | ||||
|  o show proper host name on failed resolve | ||||
|  o MacOSX-Framework: Make script work in Xcode 4.0 and later | ||||
|  o strlcat: remove function [4] | ||||
|  o darwinssl: Fix send glitchiness with data > 32 or so KB [5] | ||||
|  o polarssl: better 1.1.x and 1.2.x support | ||||
|  o various documentation improvements | ||||
|  o multi: NULL pointer reference when closing an unused multi handle [9] | ||||
|  o SOCKS: fix socks proxy when noproxy matched [7] | ||||
|  o install-sh: updated to support multiple source files as arguments [6] | ||||
|  o PolarSSL: added human readable error strings | ||||
|  o resolver_error: remove wrong error message output | ||||
|  o docs: updates HTML index and general improvements | ||||
|  o curlbuild.h.dist: enhance non-configure GCC ABI detection logic | ||||
|  o sasl: Fixed null pointer reference when decoding empty digest challenge [8] | ||||
|  o easy: do not ignore poll() failures other than EINTR | ||||
|  o darwinssl: disable ECC ciphers under Mountain Lion by default | ||||
|  o CONNECT: count received headers [11] | ||||
|  o build: fixes for VMS | ||||
|  o CONNECT: clear 'rewindaftersend' on success [12] | ||||
|  o HTTP proxy: insert slash in URL if missing [13] | ||||
|  o hiperfifo: updated to use current libevent API [14] | ||||
|  o getinmemory.c: abort the transfer nicely if not enough memory | ||||
|  o improved win32 memorytracking | ||||
|  o corrected proxy header response headers count [16] | ||||
|  o FTP quote operations on re-used connection [17] | ||||
|  o tcpkeepalive on win32 [18] | ||||
|  o tcpkeepalive on Mac OS X [23] | ||||
|  o easy: acknowledge the CURLOPT_MAXCONNECTS option properly [19] | ||||
|  o easy interface: restore default MAXCONNECTS to 5 | ||||
|  o win32: don't set SO_SNDBUF for windows vista or later versions [20] | ||||
|  o HTTP: made cookie sort function more deterministic | ||||
|  o winssl: Fixed memory leak if connection was not successful | ||||
|  o FTP: wait on both connections during active STOR state [21] | ||||
|  o connect: treat a failed local bind of an interface as a non-fatal error [22] | ||||
|  o darwinssl: disable insecure ciphers by default | ||||
|  o FTP: handle "rubbish" in front of directory name in 257 responses [24] | ||||
|  o mk-ca-bundle: Fixed lost OpenSSL output with "-t" | ||||
|  o dotdot: introducing dot file path cleanup [1] | ||||
|  o docs: fix typo in curl_easy_getinfo manpage | ||||
|  o test1230: avoid using hard-wired port number | ||||
|  o test1396: invoke the correct test tool | ||||
|  o SIGPIPE: ignored while inside the library [2] | ||||
|  o darwinssl: fix crash that started happening in Lion | ||||
|  o OpenSSL: check for read errors, don't assume [3] | ||||
|  o c-ares: improve error message on failed resolve [4] | ||||
|  o printf: make sure %x are treated unsigned | ||||
|  o formpost: better random boundaries [5] | ||||
|  o url: restore the functionality of 'curl -u :' [6] | ||||
|  o curl.1: fix typo in --xattr description [7] | ||||
|  o digest: improve nonce generation | ||||
|  o configure: automake 1.14 compatibility tweak | ||||
|  o curl.1: document the --post303 option in the man page | ||||
|  o curl.1: document the --sasl-ir option in the man page | ||||
|  o setup-vms.h: sk_pop symbol tweak | ||||
|  o tool_paramhlp: try harder to catch negatives | ||||
|  o cmake: Fix for MSVC2010 project generation [8] | ||||
|  o asyn-ares: Don't blank ares servers if none configured | ||||
|  o curl_multi_wait: set revents for extra fds | ||||
|  o Reinstate "WIN32 MemoryTracking: track wcsdup() _wcsdup() and _tcsdup() | ||||
|  o ftp_do_more: consider DO_MORE complete when server connects back [9] | ||||
|  o curl_easy_perform: gradually increase the delay time [10] | ||||
|  o curl: fix symbolic names for CURLUSESSL_* enum in --libcurl output | ||||
|  o curl: fix upload of a zip file in OpenVMS [11] | ||||
|  o build: fix linking on Solaris 10 [12] | ||||
|  o curl_formadd: CURLFORM_FILECONTENT wrongly rejected some option combos [13] | ||||
|  o curl_formadd: fix file upload on VMS [14] | ||||
|  o curl_easy_pause: on unpause, trigger mulit-socket handling [15] | ||||
|  o md5 & metalink: use better build macros on Apple operating systems [16] | ||||
|  o darwinssl: fix build error in crypto authentication under Snow Leopard [16] | ||||
|  o curl: make --progress-bar update the line less frequently [17] | ||||
|  o configure: don't error out on variable confusions (CFLAGS, LDFLAGS etc) | ||||
|  o mk-ca-bundle: skip more untrusted certificates | ||||
|  o formadd: wrong pointer for file name when CURLFORM_BUFFERPTR used [18] | ||||
|  o FTP: when EPSV gets a 229 but fails to connect, retry with PASV | ||||
|  o mk-ca-bundle.1: don't install on make install [19] | ||||
|  o VMS: lots of updates and fixes of the build procedure | ||||
|  o global dns cache: didn't work (regression) | ||||
|  o global dns cache: fix memory leak | ||||
|  o  | ||||
|  | ||||
| This release includes the following known bugs: | ||||
|  | ||||
| @@ -91,43 +72,34 @@ 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: | ||||
|  | ||||
|  Kamil Dudka, Steve Holme, Nick Zitzmann, Patricia Muscalu, Dan Fandrich, | ||||
|  Gisle Vanem, Guenter Knauf, Yang Tse, Oliver Gondža, Aki Koskinen, | ||||
|  Alexander Klauer, Kim Vandry, Willem Sparreboom, Jeremy Huddleston, | ||||
|  Bruno de Carvalho, Rainer Jung, Jeremy Huddleston, Kim Vandry, Jiri Hruska, | ||||
|  Alexander Klauer, Saran Neti, Alessandro Ghedini, Linus Nielsen Feltzing, | ||||
|  Martin Jansen, John E. Malmberg, Tom Grace, Patrick Monnerat, | ||||
|  Zdenek Pavlas, Myk Taylor, Cédric Deltheil, Robert Wruck, Sam Deane, | ||||
|  Clemens Gruber, Marc Hoersken, Tomas Mlcoch, Fredrik Thulin, Steven Gu, | ||||
|  Andrew Kurushin, Christian Hägele, Daniel Theron, Bill Middlecamp, | ||||
|  Richard Michael, Yamada Yasuharu | ||||
|  Alex Vinnik, Alessandro Ghedini, Nick Zitzmann, Kamil Dudka, | ||||
|  Lluis Batlle i Rossell, Nach M. S., Kim Vandry, Ben Greear, Dan Fandrich, | ||||
|  Dave Reisner, Evgeny Turnaev, Guenter Knauf, John E. Malmberg, Marc Hoersken, | ||||
|  Patrick Monnerat, Sergei Nikulov, Yang Tse, Andreas Malzahn, Clemens Gruber, | ||||
|  Jean-Noel Rouvignac, Markus Moeller, Fabian Keil, Dagobert Michelsen, | ||||
|  Byrial Jensen, Justin Karneges, Edward Rudd, Marc Doughty, Konstantin Isakov, | ||||
|   | ||||
|  | ||||
|         Thanks! (and sorry if I forgot to mention someone) | ||||
|  | ||||
| References to bug reports and discussions on issues: | ||||
|  | ||||
|  [1] = http://curl.haxx.se/bug/view.cgi?id=1184 | ||||
|  [2] = http://curl.haxx.se/mail/archive-2013-02/0040.html | ||||
|  [3] = http://curl.haxx.se/mail/lib-2013-03/0014.html | ||||
|  [4] = http://curl.haxx.se/bug/view.cgi?id=1192 | ||||
|  [5] = http://curl.haxx.se/mail/lib-2013-02/0145.html | ||||
|  [6] = http://curl.haxx.se/bug/view.cgi?id=1195 | ||||
|  [7] = http://curl.haxx.se/bug/view.cgi?id=1190 | ||||
|  [8] = http://curl.haxx.se/bug/view.cgi?id=1193 | ||||
|  [9] = http://curl.haxx.se/bug/view.cgi?id=1194 | ||||
|  [10] = http://curl.haxx.se/bug/view.cgi?id=1168 | ||||
|  [11] = http://curl.haxx.se/bug/view.cgi?id=1204 | ||||
|  [12] = https://groups.google.com/d/msg/msysgit/B31LNftR4BI/KhRTz0iuGmUJ | ||||
|  [13] = http://curl.haxx.se/bug/view.cgi?id=1206 | ||||
|  [14] = http://curl.haxx.se/bug/view.cgi?id=1199 | ||||
|  [15] = http://daniel.haxx.se/blog/2013/03/26/better-pipelining-in-libcurl-7-30-0/ | ||||
|  [16] = http://curl.haxx.se/bug/view.cgi?id=1204 | ||||
|  [17] = http://curl.haxx.se/mail/lib-2013-03/0319.html | ||||
|  [18] = http://curl.haxx.se/bug/view.cgi?id=1209 | ||||
|  [19] = http://curl.haxx.se/bug/view.cgi?id=1212 | ||||
|  [20] = http://curl.haxx.se/bug/view.cgi?id=1188 | ||||
|  [21] = http://curl.haxx.se/bug/view.cgi?id=1183 | ||||
|  [22] = http://curl.haxx.se/bug/view.cgi?id=1189 | ||||
|  [23] = http://curl.haxx.se/bug/view.cgi?id=1214 | ||||
|  [24] = http://curl.haxx.se/mail/lib-2013-04/0113.html | ||||
|  [25] = http://curl.haxx.se/docs/adv_20130412.html | ||||
|  [1] = http://curl.haxx.se/bug/view.cgi?id=1200 | ||||
|  [2] = http://curl.haxx.se/bug/view.cgi?id=1180 | ||||
|  [3] = http://curl.haxx.se/bug/view.cgi?id=1249 | ||||
|  [4] = http://curl.haxx.se/bug/view.cgi?id=1191 | ||||
|  [5] = http://curl.haxx.se/bug/view.cgi?id=1251 | ||||
|  [6] = http://curl.haxx.se/mail/archive-2013-06/0052.html | ||||
|  [7] = http://curl.haxx.se/bug/view.cgi?id=1252 | ||||
|  [8] = http://curl.haxx.se/mail/lib-2013-07/0046.html | ||||
|  [9] = http://curl.haxx.se/mail/lib-2013-07/0115.html | ||||
|  [10] = http://curl.haxx.se/mail/lib-2013-07/0103.html | ||||
|  [11] = http://curl.haxx.se/bug/view.cgi?id=496 | ||||
|  [12] = http://curl.haxx.se/bug/view.cgi?id=1217 | ||||
|  [13] = http://curl.haxx.se/mail/lib-2013-07/0258.html | ||||
|  [14] = http://curl.haxx.se/bug/view.cgi?id=758 | ||||
|  [15] = http://curl.haxx.se/mail/lib-2013-07/0239.html | ||||
|  [16] = http://curl.haxx.se/bug/view.cgi?id=1255 | ||||
|  [17] = http://curl.haxx.se/mail/archive-2013-07/0031.html | ||||
|  [18] = http://curl.haxx.se/bug/view.cgi?id=1262 | ||||
|  [19] = http://curl.haxx.se/mail/lib-2013-08/0057.html | ||||
|   | ||||
							
								
								
									
										11
									
								
								acinclude.m4
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								acinclude.m4
									
									
									
									
									
								
							| @@ -2619,8 +2619,10 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]), | ||||
|     fi | ||||
|     capath="$want_capath" | ||||
|     ca="no" | ||||
|   else | ||||
|     dnl neither of --with-ca-* given | ||||
|   elif test "x$cross_compiling" != "xyes"; then | ||||
|     dnl NOT cross-compiling and... | ||||
|     dnl neither of the --with-ca-* options are provided | ||||
|  | ||||
|     dnl first try autodetecting a CA bundle , then a CA path | ||||
|     dnl both autodetections can be skipped by --without-ca-* | ||||
|     ca="no" | ||||
| @@ -2656,10 +2658,11 @@ AC_HELP_STRING([--without-ca-path], [Don't use a default CA path]), | ||||
|         fi | ||||
|       done | ||||
|     fi | ||||
|   else | ||||
|     dnl no option given and cross-compiling | ||||
|     AC_MSG_WARN([skipped the ca-cert path detection when cross-compiling]) | ||||
|   fi | ||||
|  | ||||
|  | ||||
|  | ||||
|   if test "x$ca" != "xno"; then | ||||
|     CURL_CA_BUNDLE='"'$ca'"' | ||||
|     AC_DEFINE_UNQUOTED(CURL_CA_BUNDLE, "$ca", [Location of default ca bundle]) | ||||
|   | ||||
							
								
								
									
										37
									
								
								configure.ac
									
									
									
									
									
								
							
							
						
						
									
										37
									
								
								configure.ac
									
									
									
									
									
								
							| @@ -126,7 +126,7 @@ fi | ||||
| dnl figure out the libcurl version | ||||
| CURLVERSION=`$SED -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curlver.h` | ||||
| XC_CHECK_PROG_CC | ||||
| AM_INIT_AUTOMAKE | ||||
| XC_AUTOMAKE | ||||
| AC_MSG_CHECKING([curl version]) | ||||
| AC_MSG_RESULT($CURLVERSION) | ||||
|  | ||||
| @@ -3158,14 +3158,26 @@ if test "$want_thres" = "yes"; then | ||||
|   AC_CHECK_HEADER(pthread.h, | ||||
|     [ AC_DEFINE(HAVE_PTHREAD_H, 1, [if you have <pthread.h>]) | ||||
|       save_CFLAGS="$CFLAGS" | ||||
|       CFLAGS="$CFLAGS -pthread" | ||||
|       AC_CHECK_LIB(pthread, pthread_create, | ||||
|         [ AC_MSG_NOTICE([using POSIX threaded DNS lookup]) | ||||
|           AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup]) | ||||
|           USE_THREADS_POSIX=1 | ||||
|           curl_res_msg="threaded" | ||||
|         ], | ||||
|         [ CFLAGS="$save_CFLAGS"]) | ||||
|  | ||||
|       dnl first check for function without lib | ||||
|       AC_CHECK_FUNC(pthread_create, [USE_THREADS_POSIX=1] ) | ||||
|  | ||||
|       dnl if it wasn't found without lib, search for it in pthread lib | ||||
|       if test "$USE_THREADS_POSIX" != "1" | ||||
|       then | ||||
|         CFLAGS="$CFLAGS -pthread" | ||||
|         AC_CHECK_LIB(pthread, pthread_create, | ||||
|                      [USE_THREADS_POSIX=1], | ||||
|                      [ CFLAGS="$save_CFLAGS"]) | ||||
|       fi | ||||
|  | ||||
|       if test "x$USE_THREADS_POSIX" = "x1" | ||||
|       then | ||||
|         AC_DEFINE(USE_THREADS_POSIX, 1, [if you want POSIX threaded DNS lookup]) | ||||
|         curl_res_msg="POSIX threaded" | ||||
|       fi | ||||
|  | ||||
|  | ||||
|   ]) | ||||
| fi | ||||
|  | ||||
| @@ -3338,6 +3350,11 @@ dnl yes or no | ||||
| ENABLE_SHARED="$enable_shared" | ||||
| AC_SUBST(ENABLE_SHARED) | ||||
|  | ||||
| dnl to let curl-config output the static libraries correctly | ||||
| ENABLE_STATIC="$enable_static" | ||||
| AC_SUBST(ENABLE_STATIC) | ||||
|  | ||||
|  | ||||
| dnl | ||||
| dnl For keeping supported features and protocols also in pkg-config file | ||||
| dnl since it is more cross-compile friendly than curl-config | ||||
| @@ -3514,6 +3531,8 @@ AC_OUTPUT | ||||
|  | ||||
| CURL_GENERATE_CONFIGUREHELP_PM | ||||
|  | ||||
| XC_AMEND_DISTCLEAN([lib src tests/unit tests/server tests/libtest docs/examples]) | ||||
|  | ||||
| AC_MSG_NOTICE([Configured to build curl/libcurl: | ||||
|  | ||||
|   curl version:     ${CURLVERSION} | ||||
|   | ||||
| @@ -155,7 +155,12 @@ while test $# -gt 0; do | ||||
|         ;; | ||||
|  | ||||
|     --static-libs) | ||||
|         echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ | ||||
|         if test "X@ENABLE_STATIC@" != "Xno" ; then | ||||
|           echo @libdir@/libcurl.@libext@ @LDFLAGS@ @LIBCURL_LIBS@ | ||||
|         else | ||||
|           echo "curl was built with static libraries disabled" >&2 | ||||
|           exit 1 | ||||
|         fi | ||||
|         ;; | ||||
|  | ||||
|     --configure) | ||||
|   | ||||
| @@ -79,9 +79,9 @@ | ||||
| 1.3 What To Read | ||||
|  | ||||
|  Source code, the man pages, the INTERNALS document, TODO, KNOWN_BUGS, the | ||||
|  most recent CHANGES. Just lurking on the libcurl mailing list is gonna give | ||||
|  you a lot of insights on what's going on right now. Asking there is a good | ||||
|  idea too. | ||||
|  most recent CHANGES. Just lurking on the curl-library mailing list is gonna | ||||
|  give you a lot of insights on what's going on right now. Asking there is a | ||||
|  good idea too. | ||||
|  | ||||
| 2. cURL Coding Standards | ||||
|  | ||||
| @@ -98,12 +98,12 @@ | ||||
|  | ||||
| 2.2 Indenting | ||||
|  | ||||
|  Please try using the same indenting levels and bracing method as all the | ||||
|  other code already does. It makes the source code a lot easier to follow if | ||||
|  all of it is written using the same style. We don't ask you to like it, we | ||||
|  just ask you to follow the tradition! ;-) This mainly means: 2-level indents, | ||||
|  using spaces only (no tabs) and having the opening brace ({) on the same line | ||||
|  as the if() or while(). | ||||
|  Use the same indenting levels and bracing method as all the other code | ||||
|  already does. It makes the source code easier to follow if all of it is | ||||
|  written using the same style. We don't ask you to like it, we just ask you to | ||||
|  follow the tradition! ;-) This mainly means: 2-level indents, using spaces | ||||
|  only (no tabs) and having the opening brace ({) on the same line as the if() | ||||
|  or while(). | ||||
|  | ||||
|  Also note that we use if() and while() with no space before the parenthesis. | ||||
|  | ||||
| @@ -151,6 +151,9 @@ | ||||
|  description exactly what they correct so that all patches can be selectively | ||||
|  applied by the maintainer or other interested parties. | ||||
|  | ||||
|  Also, separate patches enable bisecting much better when we track problems in | ||||
|  the future. | ||||
|  | ||||
| 2.9 Patch Against Recent Sources | ||||
|  | ||||
|  Please try to get the latest available sources to make your patches | ||||
| @@ -178,6 +181,10 @@ | ||||
|  test case that verifies that it works as documented. If every submitter also | ||||
|  posts a few test cases, it won't end up as a heavy burden on a single person! | ||||
|  | ||||
|  If you don't have test cases or perhaps you have done something that is very | ||||
|  hard to write tests for, do explain exactly how you have otherwise tested and | ||||
|  verified your changes. | ||||
|  | ||||
| 3. Pushing Out Your Changes | ||||
|  | ||||
| 3.1 Write Access to git Repository | ||||
|   | ||||
							
								
								
									
										16
									
								
								docs/FAQ
									
									
									
									
									
								
							
							
						
						
									
										16
									
								
								docs/FAQ
									
									
									
									
									
								
							| @@ -728,7 +728,7 @@ FAQ | ||||
|   When passing on a URL to curl to use, it may respond that the particular | ||||
|   protocol is not supported or disabled. The particular way this error message | ||||
|   is phrased is because curl doesn't make a distinction internally of whether | ||||
|   a particular protocol is not supported (ie never got any code added that | ||||
|   a particular protocol is not supported (i.e. never got any code added that | ||||
|   knows how to speak that protocol) or if it was explicitly disabled. curl can | ||||
|   be built to only support a given set of protocols, and the rest would then | ||||
|   be disabled or not supported. | ||||
| @@ -1055,11 +1055,11 @@ FAQ | ||||
|  | ||||
|   4.19 Why doesn't cURL return an error when the network cable is unplugged? | ||||
|  | ||||
|   Unplugging the cable is not an error situation. The TCP/IP protocol stack | ||||
|   Unplugging a cable is not an error situation. The TCP/IP protocol stack | ||||
|   was designed to be fault tolerant, so even though there may be a physical | ||||
|   break somewhere the connection shouldn't be affected, just possibly | ||||
|   delayed.  Eventually, the physical break will be fixed or the data will be | ||||
|   re-routed around the physical problem. | ||||
|   re-routed around the physical problem through another path. | ||||
|  | ||||
|   In such cases, the TCP/IP stack is responsible for detecting when the | ||||
|   network connection is irrevocably lost. Since with some protocols it is | ||||
| @@ -1077,6 +1077,12 @@ FAQ | ||||
|   falls too low, and --connect-timeout and --max-time can be used to put an | ||||
|   overall timeout on the connection phase or the entire transfer. | ||||
|  | ||||
|   A libcurl-using application running in a known physical environment (e.g. | ||||
|   an embedded device with only a single network connection) may want to act | ||||
|   immediately if its lone network connection goes down.  That can be achieved | ||||
|   by having the application monitor the network connection on its own using an | ||||
|   OS-specific mechanism, then signalling libcurl to abort (see also item 5.13). | ||||
|    | ||||
|  | ||||
| 5. libcurl Issues | ||||
|  | ||||
| @@ -1086,7 +1092,9 @@ FAQ | ||||
|  | ||||
|   We have written the libcurl code specifically adjusted for multi-threaded | ||||
|   programs. libcurl will use thread-safe functions instead of non-safe ones if | ||||
|   your system has such. | ||||
|   your system has such.  Note that you must never share the same handle in | ||||
|   multiple threads. | ||||
|  | ||||
|  | ||||
|   If you use a OpenSSL-powered libcurl in a multi-threaded environment, you | ||||
|   need to provide one or two locking functions: | ||||
|   | ||||
							
								
								
									
										14
									
								
								docs/HISTORY
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								docs/HISTORY
									
									
									
									
									
								
							| @@ -7,19 +7,19 @@ | ||||
|                           How cURL Became Like This | ||||
|  | ||||
|  | ||||
| In the second half of 1997, Daniel Stenberg came up with the idea to make | ||||
| Towards the end of 1996, Daniel Stenberg came up with the idea to make | ||||
| currency-exchange calculations available to Internet Relay Chat (IRC) | ||||
| users. All the necessary data are published on the Web; he just needed to | ||||
| automate their retrieval. | ||||
|  | ||||
| Daniel simply adopted an existing command-line open-source tool, httpget, that | ||||
| Brazilian Rafael Sagula had written. After a few minor adjustments, it did | ||||
| just what he needed. | ||||
| Brazilian Rafael Sagula had written and recently release version 0.1 of. After | ||||
| a few minor adjustments, it did just what he needed. HttpGet 1.0 was released | ||||
| on April 8th 1997 with brand new HTTP proxy support. | ||||
|  | ||||
| Soon, he found currencies on a GOPHER site, so support for that had to go in, | ||||
| and not before long FTP download support was added as well. The name of the | ||||
| project was changed to urlget to better fit what it actually did now, since | ||||
| the http-only days were already passed. | ||||
| We soon found and fixed support for getting currencies over GOPHER.  Once FTP | ||||
| download support was added, the name of the project was changed and urlget 2.0 | ||||
| was released in August 1997. The http-only days were already passed. | ||||
|  | ||||
| The project slowly grew bigger. When upload capabilities were added and the | ||||
| name once again was misleading, a second name change was made and on March 20, | ||||
|   | ||||
| @@ -220,7 +220,7 @@ Win32 | ||||
|    adjust as necessary. It is also possible to override these paths with | ||||
|    environment variables, for example: | ||||
|  | ||||
|      set ZLIB_PATH=c:\zlib-1.2.7 | ||||
|      set ZLIB_PATH=c:\zlib-1.2.8 | ||||
|      set OPENSSL_PATH=c:\openssl-0.9.8y | ||||
|      set LIBSSH2_PATH=c:\libssh2-1.4.3 | ||||
|  | ||||
| @@ -323,7 +323,7 @@ Win32 | ||||
|    documentation on how to compile zlib. Define the ZLIB_PATH environment | ||||
|    variable to the location of zlib.h and zlib.lib, for example: | ||||
|  | ||||
|      set ZLIB_PATH=c:\zlib-1.2.7 | ||||
|      set ZLIB_PATH=c:\zlib-1.2.8 | ||||
|  | ||||
|    Then run 'nmake vc-zlib' in curl's root directory. | ||||
|  | ||||
| @@ -1045,7 +1045,7 @@ PORTS | ||||
|         - Alpha OpenVMS V7.1-1H2 | ||||
|         - Alpha Tru64 v5.0 5.1 | ||||
|         - AVR32 Linux | ||||
|         - ARM Android 1.5, 2.1 | ||||
|         - ARM Android 1.5, 2.1, 2.3, 3.2, 4.x | ||||
|         - ARM INTEGRITY | ||||
|         - ARM iOS | ||||
|         - Cell Linux | ||||
| @@ -1116,6 +1116,7 @@ GNU GSS      http://www.gnu.org/software/gss/ | ||||
| GnuTLS       http://www.gnu.org/software/gnutls/ | ||||
| Heimdal      http://www.pdc.kth.se/heimdal/ | ||||
| libidn       http://www.gnu.org/software/libidn/ | ||||
| libmetalink  https://launchpad.net/libmetalink/ | ||||
| libssh2      http://www.libssh2.org/ | ||||
| MIT Kerberos http://web.mit.edu/kerberos/www/dist/ | ||||
| NSS          http://www.mozilla.org/projects/security/pki/nss/ | ||||
|   | ||||
							
								
								
									
										113
									
								
								docs/INTERNALS
									
									
									
									
									
								
							
							
						
						
									
										113
									
								
								docs/INTERNALS
									
									
									
									
									
								
							| @@ -111,6 +111,9 @@ Windows vs Unix | ||||
| Library | ||||
| ======= | ||||
|  | ||||
|  (See LIBCURL-STRUCTS for a separate document describing all major internal | ||||
|  structs and their purposes.) | ||||
|  | ||||
|  There are plenty of entry points to the library, namely each publicly defined | ||||
|  function that libcurl offers to applications. All of those functions are | ||||
|  rather small and easy-to-follow. All the ones prefixed with 'curl_easy' are | ||||
| @@ -135,16 +138,18 @@ Library | ||||
|  options is documented in the man page. This function mainly sets things in | ||||
|  the 'SessionHandle' struct. | ||||
|  | ||||
|  curl_easy_perform() does a whole lot of things: | ||||
|  curl_easy_perform() is just a wrapper function that makes use of the multi | ||||
|  API.  It basically curl_multi_init(), curl_multi_add_handle(), | ||||
|  curl_multi_wait(), and curl_multi_perform() until the transfer is done and | ||||
|  then returns. | ||||
|  | ||||
|  It starts off in the lib/easy.c file by calling Curl_perform() and the main | ||||
|  work then continues in lib/url.c. The flow continues with a call to | ||||
|  Curl_connect() to connect to the remote site. | ||||
|  Some of the most important key functions in url.c are called from multi.c | ||||
|  when certain key steps are to be made in the transfer operation. | ||||
|  | ||||
|  o Curl_connect() | ||||
|  | ||||
|    ... analyzes the URL, it separates the different components and connects to | ||||
|    the remote host. This may involve using a proxy and/or using SSL. The | ||||
|    Analyzes the URL, it separates the different components and connects to the | ||||
|    remote host. This may involve using a proxy and/or using SSL. The | ||||
|    Curl_resolv() function in lib/hostip.c is used for looking up host names | ||||
|    (it does then use the proper underlying method, which may vary between | ||||
|    platforms and builds). | ||||
| @@ -160,10 +165,7 @@ Library | ||||
|  o Curl_do() | ||||
|  | ||||
|    Curl_do() makes sure the proper protocol-specific function is called. The | ||||
|    functions are named after the protocols they handle. Curl_ftp(), | ||||
|    Curl_http(), Curl_dict(), etc. They all reside in their respective files | ||||
|    (ftp.c, http.c and dict.c). HTTPS is handled by Curl_http() and FTPS by | ||||
|    Curl_ftp(). | ||||
|    functions are named after the protocols they handle. | ||||
|  | ||||
|    The protocol-specific functions of course deal with protocol-specific | ||||
|    negotiations and setup. They have access to the Curl_sendf() (from | ||||
| @@ -182,10 +184,9 @@ Library | ||||
|    be called with some basic info about the upcoming transfer: what socket(s) | ||||
|    to read/write and the expected file transfer sizes (if known). | ||||
|  | ||||
|  o Transfer() | ||||
|  o Curl_readwrite() | ||||
|  | ||||
|    Curl_perform() then calls Transfer() in lib/transfer.c that performs the | ||||
|    entire file transfer. | ||||
|    Called during the transfer of the actual protocol payload. | ||||
|  | ||||
|    During transfer, the progress functions in lib/progress.c are called at a | ||||
|    frequent interval (or at the user's choice, a specified callback might get | ||||
| @@ -207,33 +208,11 @@ Library | ||||
|    used. This function is only used when we are certain that no more transfers | ||||
|    is going to be made on the connection. It can be also closed by force, or | ||||
|    it can be called to make sure that libcurl doesn't keep too many | ||||
|    connections alive at the same time (there's a default amount of 5 but that | ||||
|    can be changed with the CURLOPT_MAXCONNECTS option). | ||||
|    connections alive at the same time. | ||||
|  | ||||
|    This function cleans up all resources that are associated with a single | ||||
|    connection. | ||||
|  | ||||
|  Curl_perform() is the function that does the main "connect - do - transfer - | ||||
|  done" loop. It loops if there's a Location: to follow. | ||||
|  | ||||
|  When completed, the curl_easy_cleanup() should be called to free up used | ||||
|  resources. It runs Curl_disconnect() on all open connections. | ||||
|  | ||||
|  A quick roundup on internal function sequences (many of these call | ||||
|  protocol-specific function-pointers): | ||||
|  | ||||
|   Curl_connect - connects to a remote site and does initial connect fluff | ||||
|    This also checks for an existing connection to the requested site and uses | ||||
|    that one if it is possible. | ||||
|  | ||||
|    Curl_do - starts a transfer | ||||
|     Curl_handler::do_it() - transfers data | ||||
|    Curl_done - ends a transfer | ||||
|  | ||||
|   Curl_disconnect - disconnects from a remote site. This is called when the | ||||
|    disconnect is really requested, which doesn't necessarily have to be | ||||
|    exactly after curl_done in case we want to keep the connection open for | ||||
|    a while. | ||||
|  | ||||
|  HTTP(S) | ||||
|  | ||||
| @@ -316,48 +295,38 @@ Persistent Connections | ||||
|    hold connection-oriented data. It is meant to hold the root data as well as | ||||
|    all the options etc that the library-user may choose. | ||||
|  o The 'SessionHandle' struct holds the "connection cache" (an array of | ||||
|    pointers to 'connectdata' structs). There's one connectdata struct | ||||
|    allocated for each connection that libcurl knows about. Note that when you | ||||
|    use the multi interface, the multi handle will hold the connection cache | ||||
|    and not the particular easy handle. This of course to allow all easy handles | ||||
|    in a multi stack to be able to share and re-use connections. | ||||
|    pointers to 'connectdata' structs). | ||||
|  o This enables the 'curl handle' to be reused on subsequent transfers. | ||||
|  o When we are about to perform a transfer with curl_easy_perform(), we first | ||||
|    check for an already existing connection in the cache that we can use, | ||||
|    otherwise we create a new one and add to the cache. If the cache is full | ||||
|    already when we add a new connection, we close one of the present ones. We | ||||
|    select which one to close dependent on the close policy that may have been | ||||
|    previously set. | ||||
|  o When the transfer operation is complete, we try to leave the connection | ||||
|    open. Particular options may tell us not to, and protocols may signal | ||||
|    closure on connections and then we don't keep it open of course. | ||||
|  o When libcurl is told to perform a transfer, it first checks for an already | ||||
|    existing connection in the cache that we can use. Otherwise it creates a | ||||
|    new one and adds that the cache. If the cache is full already when a new | ||||
|    conncetion is added added, it will first close the oldest unused one. | ||||
|  o When the transfer operation is complete, the connection is left | ||||
|    open. Particular options may tell libcurl not to, and protocols may signal | ||||
|    closure on connections and then they won't be kept open of course. | ||||
|  o When curl_easy_cleanup() is called, we close all still opened connections, | ||||
|    unless of course the multi interface "owns" the connections. | ||||
|  | ||||
|  You do realize that the curl handle must be re-used in order for the | ||||
|  persistent connections to work. | ||||
|  The curl handle must be re-used in order for the persistent connections to | ||||
|  work. | ||||
|  | ||||
| multi interface/non-blocking | ||||
| ============================ | ||||
|  | ||||
|  We make an effort to provide a non-blocking interface to the library, the | ||||
|  multi interface. To make that interface work as good as possible, no | ||||
|  low-level functions within libcurl must be written to work in a blocking | ||||
|  manner. | ||||
|  The multi interface is a non-blocking interface to the library. To make that | ||||
|  interface work as good as possible, no low-level functions within libcurl | ||||
|  must be written to work in a blocking manner. (There are still a few spots | ||||
|  violating this rule.) | ||||
|  | ||||
|  One of the primary reasons we introduced c-ares support was to allow the name | ||||
|  resolve phase to be perfectly non-blocking as well. | ||||
|  | ||||
|  The ultimate goal is to provide the easy interface simply by wrapping the | ||||
|  multi interface functions and thus treat everything internally as the multi | ||||
|  interface is the single interface we have. | ||||
|  | ||||
|  The FTP and the SFTP/SCP protocols are thus perfect examples of how we adapt | ||||
|  and adjust the code to allow non-blocking operations even on multi-stage | ||||
|  protocols. They are built around state machines that return when they could | ||||
|  block waiting for data.  The DICT, LDAP and TELNET protocols are crappy | ||||
|  examples and they are subject for rewrite in the future to better fit the | ||||
|  libcurl protocol family. | ||||
|  The FTP and the SFTP/SCP protocols are examples of how we adapt and adjust | ||||
|  the code to allow non-blocking operations even on multi-stage command- | ||||
|  response protocols. They are built around state machines that return when | ||||
|  they would otherwise block waiting for data.  The DICT, LDAP and TELNET | ||||
|  protocols are crappy examples and they are subject for rewrite in the future | ||||
|  to better fit the libcurl protocol family. | ||||
|  | ||||
| SSL libraries | ||||
| ============= | ||||
| @@ -408,12 +377,12 @@ API/ABI | ||||
| Client | ||||
| ====== | ||||
|  | ||||
|  main() resides in src/main.c together with most of the client code. | ||||
|  main() resides in src/tool_main.c. | ||||
|  | ||||
|  src/tool_hugehelp.c is automatically generated by the mkhelp.pl perl script | ||||
|  to display the complete "manual" and the src/urlglob.c file holds the | ||||
|  functions used for the URL-"globbing" support. Globbing in the sense that | ||||
|  the {} and [] expansion stuff is there. | ||||
|  to display the complete "manual" and the src/tool_urlglob.c file holds the | ||||
|  functions used for the URL-"globbing" support. Globbing in the sense that the | ||||
|  {} and [] expansion stuff is there. | ||||
|  | ||||
|  The client mostly messes around to setup its 'config' struct properly, then | ||||
|  it calls the curl_easy_*() functions of the library and when it gets back | ||||
| @@ -425,8 +394,8 @@ Client | ||||
|  curl_easy_getinfo() function to extract useful information from the curl | ||||
|  session. | ||||
|  | ||||
|  Recent versions may loop and do all this several times if many URLs were | ||||
|  specified on the command line or config file. | ||||
|  It may loop and do all this several times if many URLs were specified on the | ||||
|  command line or config file. | ||||
|  | ||||
| Memory Debugging | ||||
| ================ | ||||
|   | ||||
| @@ -3,6 +3,25 @@ join in and help us correct one or more of these! Also be sure to check the | ||||
| changelog of the current development status, as one or more of these problems | ||||
| may have been fixed since this was written! | ||||
|  | ||||
| 83. curl is unable to load non-default openssl engines, because openssl isn't | ||||
|   initialized properly. This seems to require OpenSSL_config() or | ||||
|   CONF_modules_load_file() to be used by libcurl but the first seems to not | ||||
|   work and we've gotten not reports from tests with the latter. Possibly we | ||||
|   need to discuss with OpenSSL developers how this is supposed to be done. We | ||||
|   need users with actual external openssl engines for testing to work on this. | ||||
|   http://curl.haxx.se/bug/view.cgi?id=1208 | ||||
|  | ||||
| 82. When building with the Windows Borland compiler, it fails because the | ||||
|   "tlib" tool doesn't support hyphens (minus signs) in file names and we have | ||||
|   such in the build. | ||||
|   http://curl.haxx.se/bug/view.cgi?id=1222 | ||||
|  | ||||
| 81. When using -J (with -O), automaticly resumed downloading together with "-C | ||||
|   -" fails. Without -J the same command line works! This happens because the | ||||
|   resume logic is worked out before the target file name (and thus its | ||||
|   pre-transfer size) has been figured out! | ||||
|   http://curl.haxx.se/bug/view.cgi?id=1169 | ||||
|  | ||||
| 80. Curl doesn't recognize certificates in DER format in keychain, but it | ||||
|   works with PEM. | ||||
|   http://curl.haxx.se/bug/view.cgi?id=3439999 | ||||
| @@ -85,13 +104,6 @@ may have been fixed since this was written! | ||||
|   CURLOPT_FAILONERROR with FTP to detect if a file exists or not, but it is | ||||
|   not working: http://curl.haxx.se/mail/lib-2008-07/0295.html | ||||
|  | ||||
| 57. On VMS-Alpha: When using an http-file-upload the file is not sent to the | ||||
|   Server with the correct content-length.  Sending a file with 511 or less | ||||
|   bytes, content-length 512 is used.  Sending a file with 513 - 1023 bytes, | ||||
|   content-length 1024 is used.  Files with a length of a multiple of 512 Bytes | ||||
|   show the correct content-length. Only these files work for upload. | ||||
|   http://curl.haxx.se/bug/view.cgi?id=2057858 | ||||
|  | ||||
| 56. When libcurl sends CURLOPT_POSTQUOTE commands when connected to a SFTP | ||||
|   server using the multi interface, the commands are not being sent correctly | ||||
|   and instead the connection is "cancelled" (the operation is considered done) | ||||
| @@ -169,12 +181,6 @@ may have been fixed since this was written! | ||||
|   We probably have even more bugs and lack of features when a SOCKS proxy is | ||||
|   used. | ||||
|  | ||||
| 22. Sending files to a FTP server using curl on VMS, might lead to curl | ||||
|   complaining on "unaligned file size" on completion. The problem is related | ||||
|   to VMS file structures and the perceived file sizes stat() returns. A | ||||
|   possible fix would involve sending a "STRU VMS" command. | ||||
|   http://curl.haxx.se/bug/view.cgi?id=1156287 | ||||
|  | ||||
| 21. FTP ASCII transfers do not follow RFC959. They don't convert the data | ||||
|    accordingly (not for sending nor for receiving). RFC 959 section 3.1.1.1 | ||||
|    clearly describes how this should be done: | ||||
|   | ||||
							
								
								
									
										245
									
								
								docs/LIBCURL-STRUCTS
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										245
									
								
								docs/LIBCURL-STRUCTS
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,245 @@ | ||||
|                                   _   _ ____  _ | ||||
|                               ___| | | |  _ \| | | ||||
|                              / __| | | | |_) | | | ||||
|                             | (__| |_| |  _ <| |___ | ||||
|                              \___|\___/|_| \_\_____| | ||||
|  | ||||
| Structs in libcurl | ||||
|  | ||||
| This document should cover 7.32.0 pretty accurately, but will make sense even | ||||
| for older and later versions as things don't change drastically that often. | ||||
|  | ||||
|  1. The main structs in libcurl | ||||
|   1.1 SessionHandle | ||||
|   1.2 connectdata | ||||
|   1.3 Curl_multi | ||||
|   1.4 Curl_handler | ||||
|   1.5 conncache | ||||
|   1.6 Curl_share | ||||
|   1.7 CookieInfo | ||||
|  | ||||
| ============================================================================== | ||||
|  | ||||
| 1. The main structs in libcurl | ||||
|  | ||||
|   1.1 SessionHandle | ||||
|  | ||||
|   The SessionHandle handle struct is the one returned to the outside in the | ||||
|   external API as a "CURL *". This is usually known as an easy handle in API | ||||
|   documentations and examples. | ||||
|  | ||||
|   Information and state that is related to the actual connection is in the | ||||
|   'connectdata' struct. When a transfer is about to be made, libcurl will | ||||
|   either create a new connection or re-use an existing one. The particular | ||||
|   connectdata that is used by this handle is pointed out by | ||||
|   SessionHandle->easy_conn. | ||||
|  | ||||
|   Data and information that regard this particular single transfer is put in | ||||
|   the SingleRequest sub-struct. | ||||
|  | ||||
|   When the SessionHandle struct is added to a multi handle, as it must be in | ||||
|   order to do any transfer, the ->multi member will point to the Curl_multi | ||||
|   struct it belongs to. The ->prev and ->next members will then be used by the | ||||
|   multi code to keep a linked list of SessionHandle structs that are added to | ||||
|   that same multi handle. libcurl always uses multi so ->multi *will* point to | ||||
|   a Curl_multi when a transfer is in progress. | ||||
|  | ||||
|   ->mstate is the multi state of this particular SessionHandle. When | ||||
|   multi_runsingle() is called, it will act on this handle according to which | ||||
|   state it is in. The mstate is also what tells which sockets to return for a | ||||
|   speicific SessionHandle when curl_multi_fdset() is called etc. | ||||
|  | ||||
|   The libcurl source code generally use the name 'data' for the variable that | ||||
|   points to the SessionHandle. | ||||
|  | ||||
|  | ||||
|   1.2 connectdata | ||||
|  | ||||
|   A general idea in libcurl is to keep connections around in a connection | ||||
|   "cache" after they have been used in case they will be used again and then | ||||
|   re-use an existing one instead of creating a new as it creates a significant | ||||
|   performance boost. | ||||
|  | ||||
|   Each 'connectdata' identifies a single physical conncetion to a server. If | ||||
|   the connection can't be kept alive, the connection will be closed after use | ||||
|   and then this struct can be removed from the cache and freed. | ||||
|  | ||||
|   Thus, the same SessionHandle can be used multiple times and each time select | ||||
|   another connectdata struct to use for the connection. Keep this in mind, as | ||||
|   it is then important to consider if options or choices are based on the | ||||
|   connection or the SessionHandle. | ||||
|  | ||||
|   Functions in libcurl will assume that connectdata->data points to the | ||||
|   SessionHandle that uses this connection. | ||||
|  | ||||
|   As a special complexity, some protocols supported by libcurl require a | ||||
|   special disconnect procedure that is more than just shutting down the | ||||
|   socket. It can involve sending one or more commands to the server before | ||||
|   doing so. Since connections are kept in the connection cache after use, the | ||||
|   original SessionHandle may no longer be around when the time comes to shut | ||||
|   down a particular connection. For this purpose, libcurl holds a special | ||||
|   dummy 'closure_handle' SessionHandle in the Curl_multi struct to  | ||||
|  | ||||
|   FTP uses two TCP connections for a typical transfer but it keeps both in | ||||
|   this single struct and thus can be considered a single connection for most | ||||
|   internal concerns. | ||||
|  | ||||
|   The libcurl source code generally use the name 'conn' for the variable that | ||||
|   points to the connectdata. | ||||
|  | ||||
|  | ||||
|   1.3 Curl_multi | ||||
|  | ||||
|   Internally, the easy interface is implemented as a wrapper around multi | ||||
|   interface functions. This makes everything multi interface. | ||||
|  | ||||
|   Curl_multi is the multi handle struct exposed as "CURLM *" in external APIs. | ||||
|  | ||||
|   This struct holds a list of SessionHandle structs that have been added to | ||||
|   this handle with curl_multi_add_handle(). The start of the list is ->easyp | ||||
|   and ->num_easy is a counter of added SessionHandles. | ||||
|  | ||||
|   ->msglist is a linked list of messages to send back when | ||||
|   curl_multi_info_read() is called. Basically a node is added to that list | ||||
|   when an individual SessionHandle's transfer has completed. | ||||
|  | ||||
|   ->hostcache points to the name cache. It is a hash table for looking up name | ||||
|   to IP. The nodes have a limited life time in there and this cache is meant | ||||
|   to reduce the time for when the same name is wanted within a short period of | ||||
|   time. | ||||
|  | ||||
|   ->timetree points to a tree of SessionHandles, sorted by the remaining time | ||||
|   until it should be checked - normally some sort of timeout. Each | ||||
|   SessionHandle has one node in the tree. | ||||
|  | ||||
|   ->sockhash is a hash table to allow fast lookups of socket descriptor to | ||||
|   which SessionHandle that uses that descriptor. This is necessary for the | ||||
|   multi_socket API. | ||||
|  | ||||
|   ->conn_cache points to the connection cache. It keeps track of all | ||||
|   connections that are kept after use. The cache has a maximum size. | ||||
|  | ||||
|   ->closure_handle is described in the 'connectdata' section. | ||||
|  | ||||
|   The libcurl source code generally use the name 'multi' for the variable that | ||||
|   points to the Curl_multi struct. | ||||
|  | ||||
|  | ||||
|   1.4 Curl_handler | ||||
|  | ||||
|   Each unique protocol that is supported by libcurl needs to provide at least | ||||
|   one Curl_handler struct. It defines what the protocol is called and what | ||||
|   functions the main code should call to deal with protocol specific issues. | ||||
|   In general, there's a source file named [protocol].c in which there's a | ||||
|   "struct Curl_handler Curl_handler_[protocol]" declared. In url.c there's | ||||
|   then the main array with all individual Curl_handler structs pointed to from | ||||
|   a single array which is scanned through when a URL is given to libcurl to | ||||
|   work with. | ||||
|  | ||||
|   ->scheme is the URL scheme name, usually spelled out in uppercase. That's | ||||
|   "HTTP" or "FTP" etc. SSL versions of the protcol need its own Curl_handler | ||||
|   setup so HTTPS separate from HTTP. | ||||
|  | ||||
|   ->setup_connection is called to allow the protocol code to allocate protocol | ||||
|   specific data that then gets associated with that SessionHandle for the rest | ||||
|   of this transfer. It gets freed again at the end of the transfer. It will be | ||||
|   called before the 'connectdata' for the transfer has been selected/created. | ||||
|   Most protocols will allocate its private 'struct [PROTOCOL]' here and assign | ||||
|   SessionHandle->req.protop to point to it. | ||||
|  | ||||
|   ->connect_it allows a protocol to do some specific actions after the TCP | ||||
|   connect is done, that can still be considered part of the connection phase. | ||||
|  | ||||
|   Some protocols will alter the connectdata->recv[] and connectdata->send[] | ||||
|   function pointers in this function. | ||||
|  | ||||
|   ->connecting is similarly a function that keeps getting called as long as the | ||||
|   protocol considers itself still in the connecting phase. | ||||
|  | ||||
|   ->do_it is the function called to issue the transfer request. What we call | ||||
|   the DO action internally. If the DO is not enough and things need to be kept | ||||
|   getting done for the entier DO sequence to complete, ->doing is then usually | ||||
|   also provided. Each protocol that needs to do multiple commands or similar | ||||
|   for do/doing need to implement their own state machines (see SCP, SFTP, | ||||
|   FTP). Some protocols (only FTP and only due to historical reasons) has a | ||||
|   separate piece of the DO state called DO_MORE. | ||||
|  | ||||
|   ->doing keeps getting called while issudeing the transfer request command(s) | ||||
|  | ||||
|   ->done gets called when the transfer is complete and DONE. That's after the | ||||
|   main data has been transferred. | ||||
|  | ||||
|   ->do_more gets called doring the DO_MORE state. The FTP protocol uses this | ||||
|   state when setting up the second connection. | ||||
|  | ||||
|   ->proto_getsock | ||||
|   ->doing_getsock | ||||
|   ->domore_getsock | ||||
|   ->perform_getsock | ||||
|   Functions that return socket information. Which socket(s) to wait for which | ||||
|   action(s) during the particular multi state. | ||||
|  | ||||
|   ->disconnect is called immediately before the TCP connection is shutdown. | ||||
|  | ||||
|   ->readwrite gets called during transfer to allow the protocol to do extra | ||||
|   reads/writes | ||||
|  | ||||
|   ->defport is the default report TCP or UDP port this protocol uses | ||||
|  | ||||
|   ->protocol is one or more bits in the CURLPROTO_* set. The SSL versions have | ||||
|   their "base" protocol set and then the SSL variation. Like "HTTP|HTTPS". | ||||
|  | ||||
|   ->flags is a bitmask with additional information about the protocol that will | ||||
|   make it get treated differently by the generic engine: | ||||
|  | ||||
|     PROTOPT_SSL - will make it connect and negotiate SSL | ||||
|  | ||||
|     PROTOPT_DUAL - this protocol uses two connections | ||||
|  | ||||
|     PROTOPT_CLOSEACTION - this protocol has actions to do before closing the | ||||
|     connection. This flag is no longer used by code, yet still set for a bunch | ||||
|     protocol handlers. | ||||
|    | ||||
|     PROTOPT_DIRLOCK - "direction lock". The SSH protocols set this bit to | ||||
|     limit which "direction" of socket actions that the main engine will | ||||
|     concern itself about. | ||||
|  | ||||
|     PROTOPT_NONETWORK - a protocol that doesn't use network (read file:) | ||||
|  | ||||
|     PROTOPT_NEEDSPWD - this protocol needs a password and will use a default | ||||
|     one unless one is provided | ||||
|  | ||||
|     PROTOPT_NOURLQUERY - this protocol can't handle a query part on the URL | ||||
|     (?foo=bar) | ||||
|  | ||||
|  | ||||
|   1.5 conncache | ||||
|  | ||||
|   Is a hash table with connections for later re-use. Each SessionHandle has | ||||
|   a pointer to its connection cache. Each multi handle sets up a connection | ||||
|   cache that all added SessionHandles share by default. | ||||
|  | ||||
|  | ||||
|   1.6 Curl_share | ||||
|    | ||||
|   The libcurl share API allocates a Curl_share struct, exposed to the external | ||||
|   API as "CURLSH *". | ||||
|  | ||||
|   The idea is that the struct can have a set of own versions of caches and | ||||
|   pools and then by providing this struct in the CURLOPT_SHARE option, those | ||||
|   specific SessionHandles will use the caches/pools that this share handle | ||||
|   holds. | ||||
|  | ||||
|   Then individual SessionHandle structs can be made to share specific things | ||||
|   that they otherwise wouldn't, such as cookies. | ||||
|  | ||||
|   The Curl_share struct can currently hold cookies, DNS cache and the SSL | ||||
|   session cache. | ||||
|  | ||||
|    | ||||
|   1.7 CookieInfo | ||||
|  | ||||
|   This is the main cookie struct. It holds all known cookies and related | ||||
|   information. Each SessionHandle has its own private CookieInfo even when | ||||
|   they are added to a multi handle. They can be made to share cookies by using | ||||
|   the share API. | ||||
| @@ -5,7 +5,7 @@ | ||||
| #                            | (__| |_| |  _ <| |___ | ||||
| #                             \___|\___/|_| \_\_____| | ||||
| # | ||||
| # Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| # Copyright (C) 1998 - 2013, 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,7 +22,8 @@ | ||||
|  | ||||
| AUTOMAKE_OPTIONS = foreign no-dependencies | ||||
|  | ||||
| man_MANS = curl.1 curl-config.1 mk-ca-bundle.1 | ||||
| man_MANS = curl.1 curl-config.1 | ||||
| noinst_man_MANS = mk-ca-bundle.1 | ||||
| GENHTMLPAGES = curl.html curl-config.html mk-ca-bundle.html | ||||
| PDFPAGES = curl.pdf curl-config.pdf mk-ca-bundle.pdf | ||||
|  | ||||
| @@ -36,7 +37,7 @@ EXTRA_DIST = MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS SSLCERTS	 \ | ||||
|  README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS VERSIONS	 \ | ||||
|  KNOWN_BUGS BINDINGS $(man_MANS) $(HTMLPAGES) HISTORY INSTALL		 \ | ||||
|  $(PDFPAGES) LICENSE-MIXING README.netware DISTRO-DILEMMA INSTALL.devcpp \ | ||||
|  MAIL-ETIQUETTE HTTP-COOKIES | ||||
|  MAIL-ETIQUETTE HTTP-COOKIES LIBCURL-STRUCTS | ||||
|  | ||||
| MAN2HTML= roffit < $< >$@ | ||||
|  | ||||
|   | ||||
							
								
								
									
										60
									
								
								docs/THANKS
									
									
									
									
									
								
							
							
						
						
									
										60
									
								
								docs/THANKS
									
									
									
									
									
								
							| @@ -13,14 +13,15 @@ Adam Tkac | ||||
| Adrian Schuur | ||||
| Adriano Meirelles | ||||
| Ajit Dhumale | ||||
| Aki Koskinen | ||||
| Akos Pasztory | ||||
| Alan Pinstein | ||||
| Albert Chin | ||||
| Albert Chin-A-Young | ||||
| Albert Choy | ||||
| Ale Vesely | ||||
| Alejandro Alvarez | ||||
| Aleksandar Milivojevic | ||||
| Aleksey Tulinov | ||||
| Alessandro Ghedini | ||||
| Alessandro Vesely | ||||
| Alex Bligh | ||||
| @@ -31,6 +32,7 @@ Alex Suykov | ||||
| Alex Vinnik | ||||
| Alex aka WindEagle | ||||
| Alexander Beedie | ||||
| Alexander Klauer | ||||
| Alexander Kourakos | ||||
| Alexander Krasnostavsky | ||||
| Alexander Lazic | ||||
| @@ -46,11 +48,13 @@ Amol Pattekar | ||||
| Amr Shahin | ||||
| Anatoli Tubman | ||||
| Anders Gustafsson | ||||
| Anders Havn | ||||
| Andi Jahja | ||||
| Andre Guibert de Bruet | ||||
| Andreas Damm | ||||
| Andreas Faerber | ||||
| Andreas Farber | ||||
| Andreas Malzahn | ||||
| Andreas Ntaflos | ||||
| Andreas Olsson | ||||
| Andreas Rieke | ||||
| @@ -64,9 +68,11 @@ Andrew Biggs | ||||
| Andrew Bushnell | ||||
| Andrew Francis | ||||
| Andrew Fuller | ||||
| Andrew Kurushin | ||||
| Andrew Moise | ||||
| Andrew Wansink | ||||
| Andrew de los Reyes | ||||
| Andrii Moiseiev | ||||
| Andrés García | ||||
| Andy Cedilnik | ||||
| Andy Serpa | ||||
| @@ -101,12 +107,14 @@ Ben Van Hof | ||||
| Ben Winslow | ||||
| Benbuck Nason | ||||
| Benjamin Gerard | ||||
| Benjamin Gilbert | ||||
| Benjamin Johnson | ||||
| Bernard Leak | ||||
| Bernhard Reutner-Fischer | ||||
| Bertrand Demiddelaer | ||||
| Bill Egert | ||||
| Bill Hoffman | ||||
| Bill Middlecamp | ||||
| Bjoern Sikora | ||||
| Bjorn Augustsson | ||||
| Bjorn Reese | ||||
| @@ -133,6 +141,7 @@ Bruce Mitchener | ||||
| Bruno de Carvalho | ||||
| Bryan Henderson | ||||
| Bryan Kemp | ||||
| Byrial Jensen | ||||
| Cameron Kaiser | ||||
| Camille Moncelier | ||||
| Caolan McNamara | ||||
| @@ -153,13 +162,13 @@ Chris Maltby | ||||
| Chris Mumford | ||||
| Chris Smowton | ||||
| Christian Grothoff | ||||
| Christian Hagele | ||||
| Christian Hägele | ||||
| Christian Krause | ||||
| Christian Kurz | ||||
| Christian Robottom Reis | ||||
| Christian Schmitz | ||||
| Christian Vogt | ||||
| Christian Weisgerber | ||||
| Christophe Demory | ||||
| Christophe Legry | ||||
| Christopher Conroy | ||||
| @@ -169,6 +178,7 @@ Christopher Stone | ||||
| Ciprian Badescu | ||||
| Claes Jakobsson | ||||
| Clarence Gardner | ||||
| Clemens Gruber | ||||
| Clifford Wolf | ||||
| Cody Jones | ||||
| Colin Hogben | ||||
| @@ -180,10 +190,10 @@ Craig A West | ||||
| Craig Davison | ||||
| Craig Markwardt | ||||
| Cris Bailiff | ||||
| Cristian Rodriguez | ||||
| Cristian Rodríguez | ||||
| Curt Bogmine | ||||
| Cyrill Osterwalder | ||||
| Cédric Deltheil | ||||
| Dag Ekengren | ||||
| Dagobert Michelsen | ||||
| Damien Adant | ||||
| @@ -231,6 +241,7 @@ David Odin | ||||
| David Phillips | ||||
| David Rosenstrauch | ||||
| David Shaw | ||||
| David Strauss | ||||
| David Tarendash | ||||
| David Thiel | ||||
| David Wright | ||||
| @@ -263,6 +274,7 @@ Douglas R. Horner | ||||
| Douglas Steinwand | ||||
| Dov Murik | ||||
| Duane Cathey | ||||
| Duncan | ||||
| Duncan Mac-Vicar Prett | ||||
| Dustin Boswell | ||||
| Dylan Ellicott | ||||
| @@ -271,6 +283,7 @@ Early Ehlinger | ||||
| Ebenezer Ikonne | ||||
| Edin Kadribasic | ||||
| Eduard Bloch | ||||
| Edward Rudd | ||||
| Edward Sheldrake | ||||
| Eelco Dolstra | ||||
| Eetu Ojanen | ||||
| @@ -288,15 +301,18 @@ Eric Lavigne | ||||
| Eric Melville | ||||
| Eric Mertens | ||||
| Eric Rautman | ||||
| Eric S. Raymond | ||||
| Eric Thelin | ||||
| Eric Vergnaud | ||||
| Eric Wong | ||||
| Eric Young | ||||
| Erick Nuwendam | ||||
| Erik Johansson | ||||
| Erwan Legrand | ||||
| Erwin Authried | ||||
| Eugene Kotlyarov | ||||
| Evan Jordan | ||||
| Evgeny Turnaev | ||||
| Eygene Ryabinkin | ||||
| Fabian Hiernaux | ||||
| Fabian Keil | ||||
| @@ -317,6 +333,7 @@ Fred Machado | ||||
| Fred New | ||||
| Fred Noz | ||||
| Frederic Lepied | ||||
| Fredrik Thulin | ||||
| Gabriel Kuri | ||||
| Gabriel Sjoberg | ||||
| Garrett Holmstrom | ||||
| @@ -360,6 +377,7 @@ Gwenole Beauchesne | ||||
| Götz Babin-Ebell | ||||
| Hamish Mackenzie | ||||
| Hang Kin Lau | ||||
| Hang Su | ||||
| Hanno Kranzhoff | ||||
| Hans Steegers | ||||
| Hans-Jurgen May | ||||
| @@ -394,6 +412,7 @@ Immanuel Gregoire | ||||
| Ingmar Runge | ||||
| Ingo Ralf Blum | ||||
| Ingo Wilken | ||||
| Ishan SinghLevett | ||||
| Jack Zhang | ||||
| Jacky Lam | ||||
| Jacob Meuser | ||||
| @@ -415,6 +434,7 @@ Jan Koen Annot | ||||
| Jan Kunder | ||||
| Jan Schaumann | ||||
| Jan Van Boghout | ||||
| Jared Jennings | ||||
| Jared Lundell | ||||
| Jari Sundell | ||||
| Jason Glasgow | ||||
| @@ -429,6 +449,7 @@ Jean-Claude Chauve | ||||
| Jean-Francois Bertrand | ||||
| Jean-Louis Lemaire | ||||
| Jean-Marc Ranger | ||||
| Jean-Noel Rouvignac | ||||
| Jean-Philippe Barrette-LaPierre | ||||
| Jeff Connelly | ||||
| Jeff Johnson | ||||
| @@ -438,6 +459,7 @@ Jeff Pohlmeyer | ||||
| Jeff Weber | ||||
| Jeffrey Pohlmeyer | ||||
| Jeremy Friesner | ||||
| Jeremy Huddleston | ||||
| Jerome Muffat-Meridol | ||||
| Jerome Vouillon | ||||
| Jerry Wu | ||||
| @@ -449,8 +471,8 @@ Jim Drash | ||||
| Jim Freeman | ||||
| Jim Hollinger | ||||
| Jim Meyering | ||||
| Jiri Jaburek | ||||
| Jiri Hruska | ||||
| Jiri Jaburek | ||||
| Jocelyn Jaubert | ||||
| Joe Halpin | ||||
| Joe Malicki | ||||
| @@ -465,6 +487,7 @@ John Bradshaw | ||||
| John Crow | ||||
| John Dennis | ||||
| John E. Malmberg | ||||
| John Gardiner Myers | ||||
| John Janssen | ||||
| John Joseph Bachir | ||||
| John Kelly | ||||
| @@ -506,6 +529,7 @@ Julien Royer | ||||
| Jun-ichiro itojun Hagino | ||||
| Jurij Smakov | ||||
| Justin Fletcher | ||||
| Justin Karneges | ||||
| Jörg Mueller-Tolk | ||||
| Jörn Hartroth | ||||
| Kai Engert | ||||
| @@ -534,10 +558,12 @@ Kevin Lussier | ||||
| Kevin Reed | ||||
| Kevin Roth | ||||
| Kim Rinnewitz | ||||
| Kim Vandry | ||||
| Kimmo Kinnunen | ||||
| Kjell Ericson | ||||
| Kjetil Jacobsen | ||||
| Klevtsov Vadim | ||||
| Konstantin Isakov | ||||
| Kris Kennaway | ||||
| Krishnendu Majumdar | ||||
| Krister Johansen | ||||
| @@ -550,6 +576,7 @@ Larry Fahnoe | ||||
| Lars Buitinck | ||||
| Lars Gustafsson | ||||
| Lars J. Aas | ||||
| Lars Johannesen | ||||
| Lars Nilsson | ||||
| Lars Torben Wilson | ||||
| Lau Hang Kin | ||||
| @@ -572,6 +599,7 @@ Loren Kirkby | ||||
| Luca Altea | ||||
| Luca Alteas | ||||
| Lucas Adamski | ||||
| Ludovico Cavedon | ||||
| Lukasz Czekierda | ||||
| Luke Amery | ||||
| Luke Call | ||||
| @@ -583,6 +611,7 @@ Mandy Wu | ||||
| Manfred Schwarb | ||||
| Manuel Massing | ||||
| Marc Boucher | ||||
| Marc Doughty | ||||
| Marc Hoersken | ||||
| Marc Kleine-Budde | ||||
| Marcel Raad | ||||
| @@ -614,6 +643,7 @@ Martin C. Martin | ||||
| Martin Drasar | ||||
| Martin Hager | ||||
| Martin Hedenfalk | ||||
| Martin Jansen | ||||
| Martin Lemke | ||||
| Martin Skinner | ||||
| Martin Storsjo | ||||
| @@ -661,12 +691,14 @@ Michal Gorny | ||||
| Michal Kowalczyk | ||||
| Michal Marek | ||||
| Michele Bini | ||||
| Miguel Angel | ||||
| Mihai Ionescu | ||||
| Mikael Johansson | ||||
| Mikael Sennerholm | ||||
| Mike Bytnar | ||||
| Mike Crowe | ||||
| Mike Dobbs | ||||
| Mike Giancola | ||||
| Mike Hommey | ||||
| Mike Power | ||||
| Mike Protts | ||||
| @@ -676,6 +708,8 @@ Mitz Wark | ||||
| Mohamed Lrhazi | ||||
| Mohun Biswas | ||||
| Moonesamy | ||||
| Myk Taylor | ||||
| Nach M. S. | ||||
| Nathan Coulter | ||||
| Nathan O'Sullivan | ||||
| Nathanael Nerode | ||||
| @@ -709,6 +743,7 @@ Ofer | ||||
| Olaf Flebbe | ||||
| Olaf Stueben | ||||
| Olaf Stüben | ||||
| Oliver Gondža | ||||
| Olivier Berger | ||||
| Oren Tirosh | ||||
| Ori Avtalion | ||||
| @@ -720,6 +755,7 @@ Pascal Terjan | ||||
| Pasha Kuznetsov | ||||
| Pat Ray | ||||
| Patrice Guerin | ||||
| Patricia Muscalu | ||||
| Patrick Bihan-Faou | ||||
| Patrick Monnerat | ||||
| Patrick Scott | ||||
| @@ -742,6 +778,7 @@ Pedro Neves | ||||
| Pete Su | ||||
| Peter Bray | ||||
| Peter Forret | ||||
| Peter Gal | ||||
| Peter Heuchert | ||||
| Peter Hjalmarsson | ||||
| Peter Korsgaard | ||||
| @@ -779,6 +816,7 @@ Quinn Slack | ||||
| Rafa Muyo | ||||
| Rafael Sagula | ||||
| Rainer Canavan | ||||
| Rainer Jung | ||||
| Rainer Koenig | ||||
| Rajesh Naganathan | ||||
| Ralf S. Engelschall | ||||
| @@ -793,6 +831,7 @@ Reinout van Schouwen | ||||
| Renato Botelho | ||||
| Renaud Chaillat | ||||
| Renaud Duhaut | ||||
| Renaud Guillard | ||||
| Rene Bernhardt | ||||
| Rene Rebe | ||||
| Reuven Wachtfogel | ||||
| @@ -806,6 +845,7 @@ Richard Bramante | ||||
| Richard Clayton | ||||
| Richard Cooper | ||||
| Richard Gorton | ||||
| Richard Michael | ||||
| Richard Prescott | ||||
| Richard Silverman | ||||
| Rick Jones | ||||
| @@ -822,6 +862,7 @@ Robert Iakobashvili | ||||
| Robert Olson | ||||
| Robert Schumann | ||||
| Robert Weaver | ||||
| Robert Wruck | ||||
| Robin Cornelius | ||||
| Robin Johnson | ||||
| Robin Kay | ||||
| @@ -846,6 +887,7 @@ Ryan Schmidt | ||||
| S. Moonesamy | ||||
| Salvador Dávila | ||||
| Salvatore Sorrentino | ||||
| Sam Deane | ||||
| Sam Listopad | ||||
| Sampo Kellomaki | ||||
| Samuel Díaz García | ||||
| @@ -856,6 +898,7 @@ Sandor Feldi | ||||
| Santhana Todatry | ||||
| Saqib Ali | ||||
| Sara Golemon | ||||
| Saran Neti | ||||
| Saul good | ||||
| Scott Bailey | ||||
| Scott Barrett | ||||
| @@ -888,6 +931,7 @@ Stan van de Burgt | ||||
| Stanislav Ivochkin | ||||
| Stefan Esser | ||||
| Stefan Krause | ||||
| Stefan Neis | ||||
| Stefan Teleman | ||||
| Stefan Tomanek | ||||
| Stefan Ulrich | ||||
| @@ -906,6 +950,7 @@ Steve Oliphant | ||||
| Steve Roskowski | ||||
| Steven Bazyl | ||||
| Steven G. Johnson | ||||
| Steven Gu | ||||
| Steven M. Schweda | ||||
| Steven Parkes | ||||
| Stoned Elipot | ||||
| @@ -934,6 +979,7 @@ Tim Harder | ||||
| Tim Heckman | ||||
| Tim Newsome | ||||
| Tim Sneddon | ||||
| Timo Sirainen | ||||
| Tinus van den Berg | ||||
| Tobias Rundström | ||||
| Toby Peterson | ||||
| @@ -943,6 +989,7 @@ Todd Ouska | ||||
| Todd Vierling | ||||
| Tom Benoist | ||||
| Tom Donovan | ||||
| Tom Grace | ||||
| Tom Lee | ||||
| Tom Mattison | ||||
| Tom Moers | ||||
| @@ -994,9 +1041,12 @@ Wesley Laxton | ||||
| Wesley Miaw | ||||
| Wez Furlong | ||||
| Wilfredo Sanchez | ||||
| Willem Sparreboom | ||||
| Wojciech Zwiefka | ||||
| Wouter Van Rooy | ||||
| Wu Yongzheng | ||||
| Xavier Bouchoux | ||||
| Yamada Yasuharu | ||||
| Yang Tse | ||||
| Yarram Sunil | ||||
| Yehoshua Hershberg | ||||
| @@ -1004,6 +1054,8 @@ Yukihiro Kawada | ||||
| Yuriy Sosov | ||||
| Yves Arrouye | ||||
| Yves Lejeune | ||||
| Zdenek Pavlas | ||||
| Zekun Ni | ||||
| Zmey Petroff | ||||
| Zvi Har'El | ||||
| nk | ||||
|   | ||||
							
								
								
									
										133
									
								
								docs/TODO
									
									
									
									
									
								
							
							
						
						
									
										133
									
								
								docs/TODO
									
									
									
									
									
								
							| @@ -16,8 +16,8 @@ | ||||
|  1.3 struct lifreq | ||||
|  1.4 signal-based resolver timeouts | ||||
|  1.5 get rid of PATH_MAX | ||||
|  1.6 progress callback without doubles | ||||
|  1.7 Happy Eyeball dual stack connect | ||||
|  1.6 Happy Eyeball dual stack connect | ||||
|  1.7 Modified buffer size approach | ||||
|  | ||||
|  2. libcurl - multi interface | ||||
|  2.1 More non-blocking | ||||
| @@ -38,6 +38,7 @@ | ||||
|  5.1 Better persistency for HTTP 1.0 | ||||
|  5.2 support FF3 sqlite cookie files | ||||
|  5.3 Rearrange request header order | ||||
|  5.4 HTTP2/SPDY | ||||
|  | ||||
|  6. TELNET | ||||
|  6.1 ditch stdin | ||||
| @@ -46,19 +47,18 @@ | ||||
|  6.4 send data in chunks | ||||
|  | ||||
|  7. SMTP | ||||
|  7.1 Specify the preferred authentication mechanism | ||||
|  7.2 Initial response | ||||
|  7.3 Pipelining | ||||
|  7.4 Graceful base64 decoding failure | ||||
|  7.1 Pipelining | ||||
|  7.2 Graceful base64 decoding failure | ||||
|  7.3 Enhanced capability support | ||||
|   | ||||
|  8. POP3 | ||||
|  8.1 auth= in URLs | ||||
|  8.2 Initial response | ||||
|  8.3 Graceful base64 decoding failure | ||||
|  8.1 Pipelining | ||||
|  8.2 Graceful base64 decoding failure | ||||
|  8.3 Enhanced capability support | ||||
|   | ||||
|  9. IMAP | ||||
|  9.1 auth= in URLs | ||||
|  9.2 Graceful base64 decoding failure | ||||
|  9.1 Graceful base64 decoding failure | ||||
|  9.2 Enhanced capability support | ||||
|   | ||||
|  10. LDAP | ||||
|  10.1 SASL based authentication mechanisms | ||||
| @@ -157,16 +157,7 @@ | ||||
|  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. | ||||
|  | ||||
| 1.7 Happy Eyeball dual stack connect | ||||
| 1.6 Happy Eyeball dual stack connect | ||||
|  | ||||
|  In order to make alternative technologies not suffer when transitioning, like | ||||
|  when introducing IPv6 as an alternative to IPv4 and there are more than one | ||||
| @@ -178,6 +169,28 @@ | ||||
|  | ||||
|     http://tools.ietf.org/html/rfc6555 | ||||
|  | ||||
| 1.7 Modified buffer size approach | ||||
|  | ||||
|  Current libcurl allocates a fixed 16K size buffer for download and an | ||||
|  additional 16K for upload. They are always unconditionally part of the easy | ||||
|  handle. If CRLF translations are requested, an additional 32K "scratch | ||||
|  buffer" is allocated. A total of 64K transfer buffers in the worst case. | ||||
|  | ||||
|  First, while the handles are not actually in use these buffers could be freed | ||||
|  so that lingering handles just kept in queues or whatever waste less memory. | ||||
|  | ||||
|  Secondly, SFTP is a protocol that needs to handle many ~30K blocks at once | ||||
|  since each need to be individually acked and therefore libssh2 must be | ||||
|  allowed to send (or receive) many separate ones in parallel to achieve high | ||||
|  transfer speeds. A current libcurl build with a 16K buffer makes that | ||||
|  impossible, but one with a 512K buffer will reach MUCH faster transfers. But | ||||
|  allocating 512K unconditionally for all buffers just in case they would like | ||||
|  to do fast SFTP transfers at some point is not a good solution either. | ||||
|  | ||||
|  Dynamically allocate buffer size depending on protocol in use in combination | ||||
|  with freeing it after each individual transfer? Other suggestions? | ||||
|  | ||||
|  | ||||
| 2. libcurl - multi interface | ||||
|  | ||||
| 2.1 More non-blocking | ||||
| @@ -269,6 +282,25 @@ | ||||
|  headers use a default value so only headers that need to be moved have to be | ||||
|  specified. | ||||
|  | ||||
| 5.4 HTTP2/SPDY | ||||
|  | ||||
|  The first drafts for HTTP2 have been published | ||||
|  (http://tools.ietf.org/html/draft-ietf-httpbis-http2-03) and is so far based | ||||
|  on SPDY (http://www.chromium.org/spdy) designs and experiences. Chances are | ||||
|  it will end up in that style. Chrome and Firefox already support SPDY and | ||||
|  lots of web services do. | ||||
|  | ||||
|  It would make sense to implement SPDY support now and later transition into | ||||
|  or add HTTP2 support as well. | ||||
|  | ||||
|  We should base or HTTP2/SPDY work on a 3rd party library for the protocol | ||||
|  fiddling. The Spindy library (http://spindly.haxx.se/) was an attempt to make | ||||
|  such a library with an API suitable for use by libcurl but that effort has | ||||
|  more or less stalled.  spdylay (https://github.com/tatsuhiro-t/spdylay) may | ||||
|  be a better option, either used directly or wrapped with a more spindly-like | ||||
|  API. | ||||
|  | ||||
|  | ||||
| 6. TELNET | ||||
|  | ||||
| 6.1 ditch stdin | ||||
| @@ -295,65 +327,54 @@ to provide the data to send. | ||||
|  | ||||
| 7. SMTP | ||||
|  | ||||
| 7.1 Specify the preferred authentication mechanism | ||||
|  | ||||
|  Add the ability to specify the preferred authentication mechanism or a list | ||||
|  of mechanisms that should be used. Not only that, but the order that is | ||||
|  returned by the server during the EHLO response should be honored by curl. | ||||
|  | ||||
| 7.2 Initial response | ||||
|  | ||||
|  Add the ability for the user to specify whether the initial response is | ||||
|  included in the AUTH command. Some email servers, such as Microsoft | ||||
|  Exchange, can work with either whilst others need to have the initial | ||||
|  response sent separately: | ||||
|  | ||||
|  http://curl.haxx.se/mail/lib-2012-03/0114.html | ||||
|  | ||||
| 7.3 Pipelining | ||||
| 7.1 Pipelining | ||||
|  | ||||
|  Add support for pipelining emails. | ||||
|  | ||||
| 7.4 Graceful base64 decoding failure | ||||
| 7.2 Graceful base64 decoding failure | ||||
|  | ||||
|  Rather than shutting down the session and returning an error when the | ||||
|  decoding of a base64 encoded authentication response fails, we should | ||||
|  gracefully shutdown the authentication process by sending a * response to the | ||||
|  server as per RFC4954. | ||||
|  | ||||
| 7.3 Enhanced capability support | ||||
|  | ||||
|  Add the ability, for an application that uses libcurl, to obtain the list of | ||||
|  capabilities returned from the EHLO command. | ||||
|  | ||||
| 8. POP3 | ||||
|  | ||||
| 8.1 auth= in URLs | ||||
| 8.1 Pipelining | ||||
|  | ||||
|  Being able to specify the preferred authentication mechanism in the URL as | ||||
|  per RFC2384. | ||||
|  Add support for pipelining commands. | ||||
|  | ||||
| 8.2 Initial response | ||||
|  | ||||
|  Add the ability for the user to specify whether the initial response is | ||||
|  included in the AUTH command as per RFC5034. | ||||
|  | ||||
| 8.3 Graceful base64 decoding failure | ||||
| 8.2 Graceful base64 decoding failure | ||||
|  | ||||
|  Rather than shutting down the session and returning an error when the | ||||
|  decoding of a base64 encoded authentication response fails, we should | ||||
|  gracefully shutdown the authentication process by sending a * response to the | ||||
|  server as per RFC5034. | ||||
|   | ||||
| 8.3 Enhanced capability support | ||||
|  | ||||
|  Add the ability, for an application that uses libcurl, to obtain the list of | ||||
|  capabilities returned from the CAPA command. | ||||
|  | ||||
| 9. IMAP | ||||
|  | ||||
| 9.1 auth= in URLs | ||||
|  | ||||
|  Being able to specify the preferred authentication mechanism in the URL as | ||||
|  per RFC5092. | ||||
|  | ||||
| 9.2 Graceful base64 decoding failure | ||||
| 9.1 Graceful base64 decoding failure | ||||
|  | ||||
|  Rather than shutting down the session and returning an error when the | ||||
|  decoding of a base64 encoded authentication response fails, we should | ||||
|  gracefully shutdown the authentication process by sending a * response to the | ||||
|  server as per RFC3501. | ||||
|  | ||||
| 9.2 Enhanced capability support | ||||
|  | ||||
|  Add the ability, for an application that uses libcurl, to obtain the list of | ||||
|  capabilities returned from the CAPABILITY command. | ||||
|  | ||||
| 10. LDAP | ||||
|  | ||||
| 10.1 SASL based authentication mechanisms | ||||
| @@ -429,6 +450,12 @@ to provide the data to send. | ||||
|  keys and certs over DNS using DNSSEC as an alternative to the CA model. | ||||
|  http://www.rfc-editor.org/rfc/rfc6698.txt | ||||
|  | ||||
|  An initial patch was posted by Suresh Krishnaswamy on March 7th 2013 | ||||
|  (http://curl.haxx.se/mail/lib-2013-03/0075.html) but it was a too simple | ||||
|  approach. See Daniel's comments: | ||||
|  http://curl.haxx.se/mail/lib-2013-03/0103.html . libunbound may be the | ||||
|  correct library to base this development on. | ||||
|  | ||||
| 13. GnuTLS | ||||
|  | ||||
| 13.1 SSL engine stuff | ||||
|   | ||||
							
								
								
									
										40
									
								
								docs/curl.1
									
									
									
									
									
								
							
							
						
						
									
										40
									
								
								docs/curl.1
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -230,7 +230,9 @@ server sends an unsupported encoding, curl will report an error. | ||||
| .IP "--connect-timeout <seconds>" | ||||
| Maximum time in seconds that you allow the connection to the server to take. | ||||
| This only limits the connection phase, once curl has connected this option is | ||||
| of no more use. See also the \fI-m, --max-time\fP option. | ||||
| of no more use.  Since 7.32.0, this option accepts decimal values, but the | ||||
| actual timeout will decrease in accuracy as the specified timeout increases in | ||||
| decimal precision. See also the \fI-m, --max-time\fP option. | ||||
|  | ||||
| If this option is used several times, the last one will be used. | ||||
| .IP "--create-dirs" | ||||
| @@ -388,7 +390,15 @@ curl the nickname of the certificate to use within the NSS database defined | ||||
| by the environment variable SSL_DIR (or by default /etc/pki/nssdb). If the | ||||
| NSS PEM PKCS#11 module (libnsspem.so) is available then PEM files may be | ||||
| loaded. If you want to use a file from the current directory, please precede | ||||
| it with "./" prefix, in order to avoid confusion with a nickname. | ||||
| it with "./" prefix, in order to avoid confusion with a nickname.  If the | ||||
| nickname contains ":", it needs to be preceded by "\\" so that it is not | ||||
| recognized as password delimiter.  If the nickname contains "\\", it needs to | ||||
| be escaped as "\\\\" so that it is not recognized as an escape character. | ||||
|  | ||||
| (iOS and Mac OS X only) If curl is built against Secure Transport, then the | ||||
| certificate string must match the name of a certificate that's in the system or | ||||
| user keychain. The private key corresponding to the certificate, and | ||||
| certificate chain (if any),  must also be present in the keychain. | ||||
|  | ||||
| If this option is used several times, the last one will be used. | ||||
| .IP "--engine <name>" | ||||
| @@ -805,7 +815,10 @@ Basic authentication). | ||||
| .IP "-m, --max-time <seconds>" | ||||
| Maximum time in seconds that you allow the whole operation to take.  This is | ||||
| useful for preventing your batch jobs from hanging for hours due to slow | ||||
| networks or links going down.  See also the \fI--connect-timeout\fP option. | ||||
| networks or links going down.  Since 7.32.0, this option accepts decimal | ||||
| values, but the actual timeout will decrease in accuracy as the specified | ||||
| timeout increases in decimal precision.  See also the \fI--connect-timeout\fP | ||||
| option. | ||||
|  | ||||
| If this option is used several times, the last one will be used. | ||||
| .IP "--mail-auth <address>" | ||||
| @@ -1038,6 +1051,13 @@ ubiquitous in web browsers, so curl does the conversion by default to maintain | ||||
| consistency. However, a server may require a POST to remain a POST after such | ||||
| a redirection. This option is meaningful only when using \fI-L, --location\fP | ||||
| (Added in 7.19.1) | ||||
| .IP "--post303" | ||||
| (HTTP) Tells curl to respect RFC 2616/10.3.2 and not convert POST requests | ||||
| into GET requests when following a 303 redirection. The non-RFC behaviour is | ||||
| ubiquitous in web browsers, so curl does the conversion by default to maintain | ||||
| consistency. However, a server may require a POST to remain a POST after such | ||||
| a redirection. This option is meaningful only when using \fI-L, --location\fP | ||||
| (Added in 7.26.0) | ||||
| .IP "--proto <protocols>" | ||||
| Tells curl to use the listed protocols for its initial retrieval. Protocols | ||||
| are evaluated left to right, are comma separated, and are each a protocol | ||||
| @@ -1272,8 +1292,12 @@ Set this option to zero to not timeout retries. (Added in 7.12.3) | ||||
|  | ||||
| If this option is used several times, the last one will be used. | ||||
| .IP "-s, --silent" | ||||
| Silent or quiet mode. Don't show progress meter or error messages.  Makes | ||||
| Curl mute. | ||||
| Silent or quiet mode. Don't show progress meter or error messages.  Makes Curl | ||||
| mute. It will still output the data you ask for, potentially even to the | ||||
| terminal/stdout unless you redirect it. | ||||
| .IP "--sasl-ir" | ||||
| Enable initial response in SASL authentication. | ||||
| (Added in 7.31.0) | ||||
| .IP "-S, --show-error" | ||||
| When used with \fI-s\fP it makes curl show an error message if it fails. | ||||
| .IP "--ssl" | ||||
| @@ -1669,7 +1693,7 @@ 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 | ||||
| metadata in extended 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. | ||||
| @@ -1689,7 +1713,7 @@ speed-time seconds it gets aborted. speed-time is set with \fI-y\fP and is 30 | ||||
| if not set. | ||||
|  | ||||
| If this option is used several times, the last one will be used. | ||||
| .IP "-z/--time-cond <date expression>|<file>" | ||||
| .IP "-z, --time-cond <date expression>|<file>" | ||||
| (HTTP/FTP) Request a file that has been modified later than the given time and | ||||
| date, or one that has been modified before that time. The <date expression> | ||||
| can be all sorts of date strings or if it doesn't match any internal ones, it | ||||
|   | ||||
							
								
								
									
										2
									
								
								docs/examples/.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								docs/examples/.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -43,3 +43,5 @@ simplessl | ||||
| smtp-multi | ||||
| smtp-tls | ||||
| url2file | ||||
| usercertinmem | ||||
| xmlstream | ||||
|   | ||||
| @@ -13,4 +13,4 @@ COMPLICATED_EXAMPLES = curlgtk.c curlx.c htmltitle.cpp cacertinmem.c	   \ | ||||
|   ftpuploadresume.c ghiper.c hiperfifo.c htmltidy.c multithread.c	   \ | ||||
|   opensslthreadlock.c sampleconv.c synctime.c threaded-ssl.c evhiperfifo.c \ | ||||
|   smooth-gtk-thread.c version-check.pl href_extractor.c asiohiper.cpp \ | ||||
|   multi-uv.c | ||||
|   multi-uv.c xmlstream.c usercertinmem.c | ||||
|   | ||||
| @@ -27,14 +27,14 @@ | ||||
| ## 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.7 | ||||
| ## set ZLIB_PATH=c:/zlib-1.2.8 | ||||
| ## set ZLIB=1 | ||||
| # | ||||
| ########################################################################### | ||||
|  | ||||
| # Edit the path below to point to the base of your Zlib sources. | ||||
| ifndef ZLIB_PATH | ||||
| ZLIB_PATH = ../../../zlib-1.2.7 | ||||
| ZLIB_PATH = ../../../zlib-1.2.8 | ||||
| endif | ||||
| # Edit the path below to point to the base of your OpenSSL package. | ||||
| ifndef OPENSSL_PATH | ||||
|   | ||||
| @@ -14,7 +14,7 @@ endif | ||||
|  | ||||
| # Edit the path below to point to the base of your Zlib sources. | ||||
| ifndef ZLIB_PATH | ||||
| ZLIB_PATH = ../../../zlib-1.2.7 | ||||
| ZLIB_PATH = ../../../zlib-1.2.8 | ||||
| endif | ||||
|  | ||||
| # Edit the path below to point to the base of your OpenSSL package. | ||||
|   | ||||
| @@ -78,4 +78,5 @@ simplepost.c   - HTTP POST | ||||
| simplessl.c    - HTTPS example with certificates many options set | ||||
| synctime.c     - Sync local time by extracting date from remote HTTP servers | ||||
| url2file.c     - download a document and store it in a file | ||||
| xmlstream.c    - Stream-parse a document using the streaming Expat parser | ||||
| 10-at-a-time.c - Download many files simultaneously, 10 at a time. | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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,9 +30,10 @@ struct myprogress { | ||||
|   CURL *curl; | ||||
| }; | ||||
|  | ||||
| static int progress(void *p, | ||||
|                     double dltotal, double dlnow, | ||||
|                     double ultotal, double ulnow) | ||||
| /* this is how the CURLOPT_XFERINFOFUNCTION callback works */ | ||||
| static int xferinfo(void *p, | ||||
|                     curl_off_t dltotal, curl_off_t dlnow, | ||||
|                     curl_off_t ultotal, curl_off_t ulnow) | ||||
| { | ||||
|   struct myprogress *myp = (struct myprogress *)p; | ||||
|   CURL *curl = myp->curl; | ||||
| @@ -48,7 +49,9 @@ static int progress(void *p, | ||||
|     fprintf(stderr, "TOTAL TIME: %f \r\n", curtime); | ||||
|   } | ||||
|  | ||||
|   fprintf(stderr, "UP: %g of %g  DOWN: %g of %g\r\n", | ||||
|   fprintf(stderr, "UP: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T | ||||
|           "  DOWN: %" CURL_FORMAT_CURL_OFF_T " of %" CURL_FORMAT_CURL_OFF_T | ||||
|           "\r\n", | ||||
|           ulnow, ultotal, dlnow, dltotal); | ||||
|  | ||||
|   if(dlnow > STOP_DOWNLOAD_AFTER_THIS_MANY_BYTES) | ||||
| @@ -56,6 +59,19 @@ static int progress(void *p, | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* for libcurl older than 7.32.0 (CURLOPT_PROGRESSFUNCTION) */ | ||||
| static int older_progress(void *p, | ||||
|                           double dltotal, double dlnow, | ||||
|                           double ultotal, double ulnow) | ||||
| { | ||||
|   return xferinfo(p, | ||||
|                   (curl_off_t)dltotal, | ||||
|                   (curl_off_t)dlnow, | ||||
|                   (curl_off_t)ultotal, | ||||
|                   (curl_off_t)ulnow); | ||||
| } | ||||
|  | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
|   CURL *curl; | ||||
| @@ -68,9 +84,28 @@ int main(void) | ||||
|     prog.curl = curl; | ||||
|  | ||||
|     curl_easy_setopt(curl, CURLOPT_URL, "http://example.com/"); | ||||
|     curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, progress); | ||||
|  | ||||
|     curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, older_progress); | ||||
|     /* pass the struct pointer into the progress function */ | ||||
|     curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, &prog); | ||||
|  | ||||
| #if LIBCURL_VERSION_NUM >= 0x072000 | ||||
|     /* xferinfo was introduced in 7.32.0, no earlier libcurl versions will | ||||
|        compile as they won't have the symbols around. | ||||
|  | ||||
|        If built with a newer libcurl, but running with an older libcurl: | ||||
|        curl_easy_setopt() will fail in run-time trying to set the new | ||||
|        callback, making the older callback get used. | ||||
|  | ||||
|        New libcurls will prefer the new callback and instead use that one even | ||||
|        if both callbacks are set. */ | ||||
|  | ||||
|     curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xferinfo); | ||||
|     /* pass the struct pointer into the xferinfo function, note that this is | ||||
|        an alias to CURLOPT_PROGRESSDATA */ | ||||
|     curl_easy_setopt(curl, CURLOPT_XFERINFODATA, &prog); | ||||
| #endif | ||||
|  | ||||
|     curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L); | ||||
|     res = curl_easy_perform(curl); | ||||
|  | ||||
|   | ||||
| @@ -54,23 +54,22 @@ int main(void) | ||||
|   curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, write_data); | ||||
|  | ||||
|   /* open the files */ | ||||
|   headerfile = fopen(headerfilename,"w"); | ||||
|   headerfile = fopen(headerfilename,"wb"); | ||||
|   if (headerfile == NULL) { | ||||
|     curl_easy_cleanup(curl_handle); | ||||
|     return -1; | ||||
|   } | ||||
|   bodyfile = fopen(bodyfilename,"w"); | ||||
|   bodyfile = fopen(bodyfilename,"wb"); | ||||
|   if (bodyfile == NULL) { | ||||
|     curl_easy_cleanup(curl_handle); | ||||
|     return -1; | ||||
|   } | ||||
|  | ||||
|   /* we want the headers to this file handle */ | ||||
|   /* we want the headers be written to this file handle */ | ||||
|   curl_easy_setopt(curl_handle,   CURLOPT_WRITEHEADER, headerfile); | ||||
|  | ||||
|   /* | ||||
|    * Notice here that if you want the actual data sent anywhere else but | ||||
|    * stdout, you should consider using the CURLOPT_WRITEDATA option.  */ | ||||
|   /* we want the body be written to this file handle instead of stdout */ | ||||
|   curl_easy_setopt(curl_handle,   CURLOPT_WRITEDATA, bodyfile); | ||||
|  | ||||
|   /* get it! */ | ||||
|   curl_easy_perform(curl_handle); | ||||
| @@ -78,6 +77,9 @@ int main(void) | ||||
|   /* close the header file */ | ||||
|   fclose(headerfile); | ||||
|  | ||||
|   /* close the body file */ | ||||
|   fclose(bodyfile); | ||||
|  | ||||
|   /* cleanup curl stuff */ | ||||
|   curl_easy_cleanup(curl_handle); | ||||
|  | ||||
|   | ||||
							
								
								
									
										211
									
								
								docs/examples/usercertinmem.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										211
									
								
								docs/examples/usercertinmem.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,211 @@ | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 2013, 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. | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| /* Example using an in memory PEM user certificate and RSA key to retrieve an | ||||
|  * https page. | ||||
|  * Written by Ishan SinghLevett, based on Theo Borm's cacertinmem.c. | ||||
|  * Note this example does not use a CA certificate, however one should be used | ||||
|  * if you want a properly secure connection | ||||
|  */ | ||||
|  | ||||
| #include <openssl/ssl.h> | ||||
| #include <openssl/x509.h> | ||||
| #include <openssl/pem.h> | ||||
| #include <curl/curl.h> | ||||
| #include <stdio.h> | ||||
|  | ||||
| static size_t writefunction(void *ptr, size_t size, size_t nmemb, void *stream) | ||||
| { | ||||
|   fwrite(ptr,size,nmemb,stream); | ||||
|   return(nmemb*size); | ||||
| } | ||||
|  | ||||
| static CURLcode sslctx_function(CURL *curl, void *sslctx, void *parm) | ||||
| { | ||||
|   X509 *cert = NULL; | ||||
|   BIO *bio = NULL; | ||||
|   BIO *kbio = NULL; | ||||
|   RSA *rsa = NULL; | ||||
|   int ret; | ||||
|  | ||||
|   const char *mypem = /* www.cacert.org */ | ||||
|     "-----BEGIN CERTIFICATE-----\n"\ | ||||
|     "MIIHPTCCBSWgAwIBAgIBADANBgkqhkiG9w0BAQQFADB5MRAwDgYDVQQKEwdSb290\n"\ | ||||
|     "IENBMR4wHAYDVQQLExVodHRwOi8vd3d3LmNhY2VydC5vcmcxIjAgBgNVBAMTGUNB\n"\ | ||||
|     "IENlcnQgU2lnbmluZyBBdXRob3JpdHkxITAfBgkqhkiG9w0BCQEWEnN1cHBvcnRA\n"\ | ||||
|     "Y2FjZXJ0Lm9yZzAeFw0wMzAzMzAxMjI5NDlaFw0zMzAzMjkxMjI5NDlaMHkxEDAO\n"\ | ||||
|     "BgNVBAoTB1Jvb3QgQ0ExHjAcBgNVBAsTFWh0dHA6Ly93d3cuY2FjZXJ0Lm9yZzEi\n"\ | ||||
|     "MCAGA1UEAxMZQ0EgQ2VydCBTaWduaW5nIEF1dGhvcml0eTEhMB8GCSqGSIb3DQEJ\n"\ | ||||
|     "ARYSc3VwcG9ydEBjYWNlcnQub3JnMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC\n"\ | ||||
|     "CgKCAgEAziLA4kZ97DYoB1CW8qAzQIxL8TtmPzHlawI229Z89vGIj053NgVBlfkJ\n"\ | ||||
|     "8BLPRoZzYLdufujAWGSuzbCtRRcMY/pnCujW0r8+55jE8Ez64AO7NV1sId6eINm6\n"\ | ||||
|     "zWYyN3L69wj1x81YyY7nDl7qPv4coRQKFWyGhFtkZip6qUtTefWIonvuLwphK42y\n"\ | ||||
|     "fk1WpRPs6tqSnqxEQR5YYGUFZvjARL3LlPdCfgv3ZWiYUQXw8wWRBB0bF4LsyFe7\n"\ | ||||
|     "w2t6iPGwcswlWyCR7BYCEo8y6RcYSNDHBS4CMEK4JZwFaz+qOqfrU0j36NK2B5jc\n"\ | ||||
|     "G8Y0f3/JHIJ6BVgrCFvzOKKrF11myZjXnhCLotLddJr3cQxyYN/Nb5gznZY0dj4k\n"\ | ||||
|     "epKwDpUeb+agRThHqtdB7Uq3EvbXG4OKDy7YCbZZ16oE/9KTfWgu3YtLq1i6L43q\n"\ | ||||
|     "laegw1SJpfvbi1EinbLDvhG+LJGGi5Z4rSDTii8aP8bQUWWHIbEZAWV/RRyH9XzQ\n"\ | ||||
|     "QUxPKZgh/TMfdQwEUfoZd9vUFBzugcMd9Zi3aQaRIt0AUMyBMawSB3s42mhb5ivU\n"\ | ||||
|     "fslfrejrckzzAeVLIL+aplfKkQABi6F1ITe1Yw1nPkZPcCBnzsXWWdsC4PDSy826\n"\ | ||||
|     "YreQQejdIOQpvGQpQsgi3Hia/0PsmBsJUUtaWsJx8cTLc6nloQsCAwEAAaOCAc4w\n"\ | ||||
|     "ggHKMB0GA1UdDgQWBBQWtTIb1Mfz4OaO873SsDrusjkY0TCBowYDVR0jBIGbMIGY\n"\ | ||||
|     "gBQWtTIb1Mfz4OaO873SsDrusjkY0aF9pHsweTEQMA4GA1UEChMHUm9vdCBDQTEe\n"\ | ||||
|     "MBwGA1UECxMVaHR0cDovL3d3dy5jYWNlcnQub3JnMSIwIAYDVQQDExlDQSBDZXJ0\n"\ | ||||
|     "IFNpZ25pbmcgQXV0aG9yaXR5MSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGNhY2Vy\n"\ | ||||
|     "dC5vcmeCAQAwDwYDVR0TAQH/BAUwAwEB/zAyBgNVHR8EKzApMCegJaAjhiFodHRw\n"\ | ||||
|     "czovL3d3dy5jYWNlcnQub3JnL3Jldm9rZS5jcmwwMAYJYIZIAYb4QgEEBCMWIWh0\n"\ | ||||
|     "dHBzOi8vd3d3LmNhY2VydC5vcmcvcmV2b2tlLmNybDA0BglghkgBhvhCAQgEJxYl\n"\ | ||||
|     "aHR0cDovL3d3dy5jYWNlcnQub3JnL2luZGV4LnBocD9pZD0xMDBWBglghkgBhvhC\n"\ | ||||
|     "AQ0ESRZHVG8gZ2V0IHlvdXIgb3duIGNlcnRpZmljYXRlIGZvciBGUkVFIGhlYWQg\n"\ | ||||
|     "b3ZlciB0byBodHRwOi8vd3d3LmNhY2VydC5vcmcwDQYJKoZIhvcNAQEEBQADggIB\n"\ | ||||
|     "ACjH7pyCArpcgBLKNQodgW+JapnM8mgPf6fhjViVPr3yBsOQWqy1YPaZQwGjiHCc\n"\ | ||||
|     "nWKdpIevZ1gNMDY75q1I08t0AoZxPuIrA2jxNGJARjtT6ij0rPtmlVOKTV39O9lg\n"\ | ||||
|     "18p5aTuxZZKmxoGCXJzN600BiqXfEVWqFcofN8CCmHBh22p8lqOOLlQ+TyGpkO/c\n"\ | ||||
|     "gr/c6EWtTZBzCDyUZbAEmXZ/4rzCahWqlwQ3JNgelE5tDlG+1sSPypZt90Pf6DBl\n"\ | ||||
|     "Jzt7u0NDY8RD97LsaMzhGY4i+5jhe1o+ATc7iwiwovOVThrLm82asduycPAtStvY\n"\ | ||||
|     "sONvRUgzEv/+PDIqVPfE94rwiCPCR/5kenHA0R6mY7AHfqQv0wGP3J8rtsYIqQ+T\n"\ | ||||
|     "SCX8Ev2fQtzzxD72V7DX3WnRBnc0CkvSyqD/HMaMyRa+xMwyN2hzXwj7UfdJUzYF\n"\ | ||||
|     "CpUCTPJ5GhD22Dp1nPMd8aINcGeGG7MW9S/lpOt5hvk9C8JzC6WZrG/8Z7jlLwum\n"\ | ||||
|     "GCSNe9FINSkYQKyTYOGWhlC0elnYjyELn8+CkcY7v2vcB5G5l1YjqrZslMZIBjzk\n"\ | ||||
|     "zk6q5PYvCdxTby78dOs6Y5nCpqyJvKeyRKANihDjbPIky/qbn3BHLt4Ui9SyIAmW\n"\ | ||||
|     "omTxJBzcoTWcFbLUvFUufQb1nA5V9FrWk9p2rSVzTMVD\n"\ | ||||
|     "-----END CERTIFICATE-----\n"; | ||||
|  | ||||
| /*replace the XXX with the actual RSA key*/ | ||||
|   const char *mykey = | ||||
|     "-----BEGIN RSA PRIVATE KEY-----\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX\n"\ | ||||
|     "-----END RSA PRIVATE KEY-----\n"; | ||||
|  | ||||
|   (void)curl; /* avoid warnings */ | ||||
|   (void)parm; /* avoid warnings */ | ||||
|  | ||||
|   /* get a BIO */ | ||||
|   bio = BIO_new_mem_buf((char *)mypem, -1); | ||||
|  | ||||
|   if (bio == NULL) { | ||||
|     printf("BIO_new_mem_buf failed\n"); | ||||
|   } | ||||
|  | ||||
|   /* use it to read the PEM formatted certificate from memory into an X509 | ||||
|    * structure that SSL can use | ||||
|    */ | ||||
|   cert = PEM_read_bio_X509(bio, NULL, 0, NULL); | ||||
|   if (cert == NULL) { | ||||
|     printf("PEM_read_bio_X509 failed...\n"); | ||||
|   } | ||||
|  | ||||
|   /*tell SSL to use the X509 certificate*/ | ||||
|   ret = SSL_CTX_use_certificate((SSL_CTX*)sslctx, cert); | ||||
|   if (ret != 1) { | ||||
|     printf("Use certificate failed\n"); | ||||
|   } | ||||
|  | ||||
|   /*create a bio for the RSA key*/ | ||||
|   kbio = BIO_new_mem_buf((char *)mykey, -1); | ||||
|   if (kbio == NULL) { | ||||
|     printf("BIO_new_mem_buf failed\n"); | ||||
|   } | ||||
|  | ||||
|   /*read the key bio into an RSA object*/ | ||||
|   rsa = PEM_read_bio_RSAPrivateKey(kbio, NULL, 0, NULL); | ||||
|   if (rsa == NULL) { | ||||
|     printf("Failed to create key bio\n"); | ||||
|   } | ||||
|  | ||||
|   /*tell SSL to use the RSA key from memory*/ | ||||
|   ret = SSL_CTX_use_RSAPrivateKey((SSL_CTX*)sslctx, rsa); | ||||
|   if (ret != 1) { | ||||
|     printf("Use Key failed\n"); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   /* all set to go */ | ||||
|   return CURLE_OK ; | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
|   CURL *ch; | ||||
|   CURLcode rv; | ||||
|  | ||||
|   rv = curl_global_init(CURL_GLOBAL_ALL); | ||||
|   ch = curl_easy_init(); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_VERBOSE, 0L); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_HEADER, 0L); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_NOPROGRESS, 1L); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_NOSIGNAL, 1L); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_WRITEFUNCTION, *writefunction); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_WRITEDATA, stdout); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_HEADERFUNCTION, *writefunction); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_WRITEHEADER, stderr); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_SSLCERTTYPE,"PEM"); | ||||
|  | ||||
|   /* both VERIFYPEER and VERIFYHOST are set to 0 in this case because there is | ||||
|      no CA certificate*/ | ||||
|  | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYPEER, 0L); | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_SSL_VERIFYHOST, 0L); | ||||
|   rv = curl_easy_setopt(ch, CURLOPT_URL, "https://www.example.com/"); | ||||
|   rv = curl_easy_setopt(ch, CURLOPT_SSLKEYTYPE, "PEM"); | ||||
|  | ||||
|   /* first try: retrieve page without user certificate and key -> will fail | ||||
|    */ | ||||
|   rv = curl_easy_perform(ch); | ||||
|   if (rv==CURLE_OK) { | ||||
|     printf("*** transfer succeeded ***\n"); | ||||
|   } | ||||
|   else { | ||||
|     printf("*** transfer failed ***\n"); | ||||
|   } | ||||
|  | ||||
|   /* second try: retrieve page using user certificate and key -> will succeed | ||||
|    * load the certificate and key by installing a function doing the necessary | ||||
|    * "modifications" to the SSL CONTEXT just before link init | ||||
|    */ | ||||
|   rv = curl_easy_setopt(ch,CURLOPT_SSL_CTX_FUNCTION, *sslctx_function); | ||||
|   rv = curl_easy_perform(ch); | ||||
|   if (rv==CURLE_OK) { | ||||
|     printf("*** transfer succeeded ***\n"); | ||||
|   } | ||||
|   else { | ||||
|     printf("*** transfer failed ***\n"); | ||||
|   } | ||||
|  | ||||
|   curl_easy_cleanup(ch); | ||||
|   curl_global_cleanup(); | ||||
|   return rv; | ||||
| } | ||||
							
								
								
									
										158
									
								
								docs/examples/xmlstream.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										158
									
								
								docs/examples/xmlstream.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,158 @@ | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2013, 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. | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| /* Stream-parse a document using the streaming Expat parser. | ||||
|  * Written by David Strauss | ||||
|  * | ||||
|  * Expat => http://www.libexpat.org/ | ||||
|  * | ||||
|  * gcc -Wall -I/usr/local/include xmlstream.c -lcurl -lexpat -o xmlstream | ||||
|  * | ||||
|  */ | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <string.h> | ||||
| #include <assert.h> | ||||
|  | ||||
| #include <expat.h> | ||||
| #include <curl/curl.h> | ||||
|  | ||||
| struct MemoryStruct { | ||||
|   char *memory; | ||||
|   size_t size; | ||||
| }; | ||||
|  | ||||
| struct ParserStruct { | ||||
|   int ok; | ||||
|   size_t tags; | ||||
|   size_t depth; | ||||
|   struct MemoryStruct characters; | ||||
| }; | ||||
|  | ||||
| static void startElement(void *userData, const XML_Char *name, const XML_Char **atts) | ||||
| { | ||||
|   struct ParserStruct *state = (struct ParserStruct *) userData; | ||||
|   state->tags++; | ||||
|   state->depth++; | ||||
|  | ||||
|   /* Get a clean slate for reading in character data. */ | ||||
|   free(state->characters.memory); | ||||
|   state->characters.memory = NULL; | ||||
|   state->characters.size = 0; | ||||
| } | ||||
|  | ||||
| static void characterDataHandler(void *userData, const XML_Char *s, int len) | ||||
| { | ||||
|   struct ParserStruct *state = (struct ParserStruct *) userData; | ||||
|   struct MemoryStruct *mem = &state->characters; | ||||
|  | ||||
|   mem->memory = realloc(mem->memory, mem->size + len + 1); | ||||
|   if(mem->memory == NULL) { | ||||
|     /* Out of memory. */ | ||||
|     fprintf(stderr, "Not enough memory (realloc returned NULL).\n"); | ||||
|     state->ok = 0; | ||||
|     return; | ||||
|   } | ||||
|  | ||||
|   memcpy(&(mem->memory[mem->size]), s, len); | ||||
|   mem->size += len; | ||||
|   mem->memory[mem->size] = 0; | ||||
| } | ||||
|  | ||||
| static void endElement(void *userData, const XML_Char *name) | ||||
| { | ||||
|   struct ParserStruct *state = (struct ParserStruct *) userData; | ||||
|   state->depth--; | ||||
|  | ||||
|   printf("%5lu   %10lu   %s\n", state->depth, state->characters.size, name); | ||||
| } | ||||
|  | ||||
| static size_t parseStreamCallback(void *contents, size_t length, size_t nmemb, void *userp) | ||||
| { | ||||
|   XML_Parser parser = (XML_Parser) userp; | ||||
|   size_t real_size = length * nmemb; | ||||
|   struct ParserStruct *state = (struct ParserStruct *) XML_GetUserData(parser); | ||||
|  | ||||
|   /* Only parse if we're not already in a failure state. */ | ||||
|   if (state->ok && XML_Parse(parser, contents, real_size, 0) == 0) { | ||||
|     int error_code = XML_GetErrorCode(parser); | ||||
|     fprintf(stderr, "Parsing response buffer of length %lu failed with error code %d (%s).\n", | ||||
|             real_size, error_code, XML_ErrorString(error_code)); | ||||
|     state->ok = 0; | ||||
|   } | ||||
|  | ||||
|   return real_size; | ||||
| } | ||||
|  | ||||
| int main(void) | ||||
| { | ||||
|   CURL *curl_handle; | ||||
|   CURLcode res; | ||||
|   XML_Parser parser; | ||||
|   struct ParserStruct state; | ||||
|  | ||||
|   /* Initialize the state structure for parsing. */ | ||||
|   memset(&state, 0, sizeof(struct ParserStruct)); | ||||
|   state.ok = 1; | ||||
|  | ||||
|   /* Initialize a namespace-aware parser. */ | ||||
|   parser = XML_ParserCreateNS(NULL, '\0'); | ||||
|   XML_SetUserData(parser, &state); | ||||
|   XML_SetElementHandler(parser, startElement, endElement); | ||||
|   XML_SetCharacterDataHandler(parser, characterDataHandler); | ||||
|  | ||||
|   /* Initalize a libcurl handle. */ | ||||
|   curl_global_init(CURL_GLOBAL_ALL ^ CURL_GLOBAL_SSL); | ||||
|   curl_handle = curl_easy_init(); | ||||
|   curl_easy_setopt(curl_handle, CURLOPT_URL, "http://www.w3schools.com/xml/simple.xml"); | ||||
|   curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, parseStreamCallback); | ||||
|   curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)parser); | ||||
|  | ||||
|   printf("Depth   Characters   Closing Tag\n"); | ||||
|  | ||||
|   /* Perform the request and any follow-up parsing. */ | ||||
|   res = curl_easy_perform(curl_handle); | ||||
|   if(res != CURLE_OK) { | ||||
|     fprintf(stderr, "curl_easy_perform() failed: %s\n", | ||||
|             curl_easy_strerror(res)); | ||||
|   } | ||||
|   else if (state.ok) { | ||||
|     /* Expat requires one final call to finalize parsing. */ | ||||
|     if (XML_Parse(parser, NULL, 0, 1) == 0) { | ||||
|       int error_code = XML_GetErrorCode(parser); | ||||
|       fprintf(stderr, "Finalizing parsing failed with error code %d (%s).\n", | ||||
|               error_code, XML_ErrorString(error_code)); | ||||
|     } | ||||
|     else { | ||||
|       printf("                     --------------\n"); | ||||
|       printf("                     %lu tags total\n", state.tags); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Clean up. */ | ||||
|   free(state.characters.memory); | ||||
|   XML_ParserFree(parser); | ||||
|   curl_easy_cleanup(curl_handle); | ||||
|   curl_global_cleanup(); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
| @@ -232,7 +232,7 @@ Pass a pointer to a char pointer to receive a pointer to a string holding the | ||||
| most recent RTSP Session ID. | ||||
|  | ||||
| Applications wishing to resume an RTSP session on another connection should | ||||
| retreive this info before closing the active connection. | ||||
| retrieve this info before closing the active connection. | ||||
| .IP CURLINFO_RTSP_CLIENT_CSEQ | ||||
| Pass a pointer to a long to receive the next CSeq that will be used by the | ||||
| application. | ||||
| @@ -244,7 +244,7 @@ by the application. | ||||
| unimplemented).\fP | ||||
|  | ||||
| Applications wishing to resume an RTSP session on another connection should | ||||
| retreive this info before closing the active connection. | ||||
| retrieve this info before closing the active connection. | ||||
| .IP CURLINFO_RTSP_CSEQ_RECV | ||||
| Pass a pointer to a long to receive the most recently received CSeq from the | ||||
| server. If your application encounters a \fICURLE_RTSP_CSEQ_ERROR\fP then you | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -68,6 +68,18 @@ code means something wrong occurred after the new state was set.  See the | ||||
| .SH AVAILABILITY | ||||
| This function was added in libcurl 7.18.0. Before this version, there was no | ||||
| explicit support for pausing transfers. | ||||
| .SH "USAGE WITH THE MULTI-SOCKET INTERFACE" | ||||
| Before libcurl 7.32.0, when a specific handle was unpaused with this function, | ||||
| there was no particular forced rechecking or similar of the socket's state, | ||||
| which made the continuation of the transfer get delayed until next | ||||
| multi-socket call invoke or even longer. Alternatively, the user could | ||||
| forcibly call for example curl_multi_socket_all(3) - with a rather hefty | ||||
| performance penalty. | ||||
|  | ||||
| Starting in libcurl 7.32.0, unpausing a transfer will schedule a timeout | ||||
| trigger for that handle 1 millisecond into the future, so that a | ||||
| curl_multi_socket_action( ... CURL_SOCKET_TIMEOUT) can be used immediately | ||||
| afterwards to get the transfer going again as desired. | ||||
| .SH "MEMORY USE" | ||||
| When pausing a read by returning the magic return code from a write callback, | ||||
| the read data is already in libcurl's internal buffers so it'll have to keep | ||||
|   | ||||
| @@ -342,15 +342,34 @@ argument in the closesocket callback set with | ||||
| The default value of this parameter is unspecified. | ||||
| (Option added in 7.21.7) | ||||
| .IP CURLOPT_PROGRESSFUNCTION | ||||
| Pass a pointer to a function that matches the following prototype: \fBint | ||||
| function(void *clientp, double dltotal, double dlnow, double ultotal, double | ||||
| ulnow); \fP. This function gets called by libcurl instead of its internal | ||||
| equivalent with a frequent interval during operation (roughly once per second | ||||
| or sooner) no matter if data is being transferred or not.  Unknown/unused | ||||
| argument values passed to the callback will be set to zero (like if you only | ||||
| download data, the upload size will remain 0). Returning a non-zero value from | ||||
| this callback will cause libcurl to abort the transfer and return | ||||
| \fICURLE_ABORTED_BY_CALLBACK\fP. | ||||
| Pass a pointer to a function that matches the following prototype: | ||||
|  | ||||
| \fBint function(void *clientp, double dltotal, double dlnow, double ultotal, | ||||
| double ulnow);\fP | ||||
|  | ||||
| This function gets called by libcurl instead of its internal equivalent with a | ||||
| frequent interval. While data is being transferred it will be called very | ||||
| frequently, and during slow periods like when nothing is being transferred it | ||||
| can slow down to about one call per second. | ||||
|  | ||||
| \fIclientp\fP is the pointer set with \fICURLOPT_PROGRESSDATA\fP, it is not | ||||
| actually used by libcurl but is only passed along from the application to the | ||||
| callback. | ||||
|  | ||||
| The callback gets told how much data libcurl will transfer and has | ||||
| transferred, in number of bytes. \fIdltotal\fP is the total number of bytes | ||||
| libcurl expects to download in this transfer. \fIdlnow\fP is the number of | ||||
| bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl | ||||
| expects to upload in this transfer. \fIulnow\fP is the number of bytes | ||||
| uploaded so far. | ||||
|  | ||||
| Unknown/unused argument values passed to the callback will be set to zero | ||||
| (like if you only download data, the upload size will remain 0). Many times | ||||
| the callback will be called one or more times first, before it knows the data | ||||
| sizes so a program must be made to handle that. | ||||
|  | ||||
| Returning a non-zero value from this callback will cause libcurl to abort the | ||||
| transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP. | ||||
|  | ||||
| If you transfer data with the multi interface, this function will not be | ||||
| called during periods of idleness unless you call the appropriate libcurl | ||||
| @@ -358,10 +377,54 @@ function that performs transfers. | ||||
|  | ||||
| \fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually | ||||
| get called. | ||||
| .IP CURLOPT_XFERINFOFUNCTION | ||||
| Pass a pointer to a function that matches the following prototype: | ||||
|  | ||||
| .nf | ||||
| \fBint function(void *clientp, curl_off_t dltotal, curl_off_t dlnow, | ||||
|                 curl_off_t ultotal, curl_off_t ulnow);\fP | ||||
| .fi | ||||
|  | ||||
| This function gets called by libcurl instead of its internal equivalent with a | ||||
| frequent interval. While data is being transferred it will be called very | ||||
| frequently, and during slow periods like when nothing is being transferred it | ||||
| can slow down to about one call per second. | ||||
|  | ||||
| \fIclientp\fP is the pointer set with \fICURLOPT_XFERINFODATA\fP, it is only | ||||
| passed along from the application to the callback. | ||||
|  | ||||
| The callback gets told how much data libcurl will transfer and has | ||||
| transferred, in number of bytes. \fIdltotal\fP is the total number of bytes | ||||
| libcurl expects to download in this transfer. \fIdlnow\fP is the number of | ||||
| bytes downloaded so far. \fIultotal\fP is the total number of bytes libcurl | ||||
| expects to upload in this transfer. \fIulnow\fP is the number of bytes | ||||
| uploaded so far. | ||||
|  | ||||
| Unknown/unused argument values passed to the callback will be set to zero | ||||
| (like if you only download data, the upload size will remain 0). Many times | ||||
| the callback will be called one or more times first, before it knows the data | ||||
| sizes so a program must be made to handle that. | ||||
|  | ||||
| Returning a non-zero value from this callback will cause libcurl to abort the | ||||
| transfer and return \fICURLE_ABORTED_BY_CALLBACK\fP. | ||||
|  | ||||
| If you transfer data with the multi interface, this function will not be | ||||
| called during periods of idleness unless you call the appropriate libcurl | ||||
| function that performs transfers. | ||||
|  | ||||
| \fICURLOPT_NOPROGRESS\fP must be set to 0 to make this function actually | ||||
| get called. | ||||
|  | ||||
| (Added in 7.32.0) | ||||
| .IP CURLOPT_PROGRESSDATA | ||||
| Pass a pointer that will be untouched by libcurl and passed as the first | ||||
| argument in the progress callback set with \fICURLOPT_PROGRESSFUNCTION\fP. | ||||
| The default value of this parameter is unspecified. | ||||
| .IP CURLOPT_XFERINFODATA | ||||
| Pass a pointer that will be untouched by libcurl and passed as the first | ||||
| argument in the progress callback set with \fICURLOPT_XFERINFOFUNCTION\fP. | ||||
| The default value of this parameter is unspecified. This option is an alias | ||||
| for CURLOPT_PROGRESSDATA. (Added in 7.32.0) | ||||
| .IP CURLOPT_HEADERFUNCTION | ||||
| Pass a pointer to a function that matches the following prototype: | ||||
| \fBsize_t function( void *ptr, size_t size, size_t nmemb, void | ||||
| @@ -620,12 +683,20 @@ scheme://host:port/path | ||||
|  | ||||
| For a greater explanation of the format please see RFC3986. | ||||
|  | ||||
| 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. | ||||
| If the given URL lacks the scheme (such as "http://" or "ftp://" etc) then | ||||
| libcurl will attempt to resolve the protocol based on one of the following | ||||
| given host names: | ||||
|  | ||||
| HTTP, FTP, DICT, LDAP, IMAP, POP3 or SMTP | ||||
|  | ||||
| (POP3 and SMTP added in 7.31.0) | ||||
|  | ||||
| Should the protocol, either that specified by the scheme or deduced by libcurl | ||||
| from the host name, not be supported by libcurl then | ||||
| (\fICURLE_UNSUPPORTED_PROTOCOL\fP) will be returned from either the | ||||
| \fIcurl_easy_perform(3)\fP or \fIcurl_multi_perform(3)\fP functions when you | ||||
| call them. Use \fIcurl_version_info(3)\fP for detailed information of which | ||||
| protocols are supported by the build of libcurl you are using. | ||||
|  | ||||
| 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 | ||||
| @@ -640,17 +711,23 @@ 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: | ||||
| It is also possible to specify the user name, password and any supported login | ||||
| options as part of the host, for the following protocols, when connecting to | ||||
| servers that require authentication: | ||||
|  | ||||
| http://user:password@www.example.com | ||||
|  | ||||
| ftp://user:password@ftp.example.com | ||||
|  | ||||
| pop3://user:password@mail.example.com | ||||
| imap://user:password;options@mail.example.com | ||||
|  | ||||
| pop3://user:password;options@mail.example.com | ||||
|  | ||||
| smtp://user:password;options@mail.example.com | ||||
|  | ||||
| At present only IMAP, POP3 and SMTP support login options as part of the host. | ||||
| For more information about the login options in URL syntax please see RFC2384, | ||||
| RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0). | ||||
|  | ||||
| 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 | ||||
| @@ -1040,8 +1117,8 @@ the full path name to the file you want libcurl to use as .netrc file. If this | ||||
| option is omitted, and \fICURLOPT_NETRC\fP is set, libcurl will attempt to | ||||
| find a .netrc file in the current user's home directory. (Added in 7.10.9) | ||||
| .IP CURLOPT_USERPWD | ||||
| Pass a char * as parameter, which should be [user name]:[password] to use for | ||||
| the connection. Use \fICURLOPT_HTTPAUTH\fP to decide the authentication method. | ||||
| Pass a char * as parameter, pointing to a zero terminated login details string | ||||
| for the connection. The format of which is: [user name]:[password];[options]. | ||||
|  | ||||
| When using NTLM, you can set the domain by prepending it to the user name and | ||||
| separating the domain and name with a forward (/) or backward slash (\\). Like | ||||
| @@ -1054,10 +1131,18 @@ and password information to hosts using the initial host name (unless | ||||
| \fICURLOPT_UNRESTRICTED_AUTH\fP is set), so if libcurl follows locations to | ||||
| other hosts it will not send the user and password to those. This is enforced | ||||
| to prevent accidental information leakage. | ||||
|  | ||||
| At present only IMAP, POP3 and SMTP support login options as part of the | ||||
| details string. For more information about the login options please see | ||||
| RFC2384, RFC5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0). | ||||
|  | ||||
| Use \fICURLOPT_HTTPAUTH\fP to specify the authentication method for HTTP based | ||||
| connections. | ||||
| .IP CURLOPT_PROXYUSERPWD | ||||
| Pass a char * as parameter, which should be [user name]:[password] to use for | ||||
| the connection to the HTTP proxy.  Use \fICURLOPT_PROXYAUTH\fP to decide | ||||
| the authentication method. | ||||
| the connection to the HTTP proxy. | ||||
|  | ||||
| Use \fICURLOPT_PROXYAUTH\fP to specify the authentication method. | ||||
| .IP CURLOPT_USERNAME | ||||
| Pass a char * as parameter, which should be pointing to the zero terminated | ||||
| user name to use for the transfer. | ||||
| @@ -1134,7 +1219,7 @@ Microsoft. It uses a challenge-response and hash concept similar to Digest, to | ||||
| prevent the password from being eavesdropped. | ||||
|  | ||||
| You need to build libcurl with either OpenSSL, GnuTLS or NSS support for this | ||||
| option to work, or build libcurl on Windows. | ||||
| option to work, or build libcurl on Windows with SSPI support. | ||||
| .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 | ||||
| @@ -1195,6 +1280,15 @@ actual name and password with the \fICURLOPT_PROXYUSERPWD\fP option. The | ||||
| bitmask can be constructed by or'ing together the bits listed above for the | ||||
| \fICURLOPT_HTTPAUTH\fP option. As of this writing, only Basic, Digest and NTLM | ||||
| work. (Added in 7.10.7) | ||||
| .IP CURLOPT_SASL_IR | ||||
| Pass a long. If the value is 1, curl will send the initial response to the | ||||
| server in the first authentication packet in order to reduce the number of | ||||
| ping pong requests. Only applicable to supporting SASL authentication | ||||
| mechanisms and to the IMAP, POP3 and SMTP protocols. (Added in 7.31.0) | ||||
|  | ||||
| Note: Whilst IMAP supports this option there is no need to explicitly set it, | ||||
| as libcurl can determine the feature itself when the server supports the | ||||
| SASL-IR CAPABILITY. | ||||
| .SH HTTP OPTIONS | ||||
| .IP CURLOPT_AUTOREFERER | ||||
| Pass a parameter set to 1 to enable this. When enabled, libcurl will | ||||
| @@ -1392,10 +1486,12 @@ internally, your added one will be used instead. If you add a header with no | ||||
| content as in 'Accept:' (no data on the right side of the colon), the | ||||
| internally used header will get disabled. Thus, using this option you can add | ||||
| new headers, replace internal headers and remove internal headers. To add a | ||||
| header with no content, make the content be two quotes: \&"". The headers | ||||
| included in the linked list must not be CRLF-terminated, because curl adds | ||||
| CRLF after each header item. Failure to comply with this will result in | ||||
| strange bugs because the server will most likely ignore part of the headers | ||||
| header with no content (nothing to the right side of the colon), use the | ||||
| form 'MyHeader;' (note the ending semicolon). | ||||
|  | ||||
| The headers included in the linked list must not be CRLF-terminated, because | ||||
| curl adds CRLF after each header item. Failure to comply with this will result | ||||
| in strange bugs because the server will most likely ignore part of the headers | ||||
| you specified. | ||||
|  | ||||
| The first line in a request (containing the method, usually a GET or POST) is | ||||
| @@ -2208,6 +2304,12 @@ changed with \fICURLOPT_SSLCERTTYPE\fP. | ||||
| With NSS this can also be the nickname of the certificate you wish to | ||||
| authenticate with. If you want to use a file from the current directory, please | ||||
| precede it with "./" prefix, in order to avoid confusion with a nickname. | ||||
|  | ||||
| (iOS and Mac OS X only) With Secure Transport, this string must match the name | ||||
| of a certificate that's in the system or user keychain. You should encode this | ||||
| string in UTF-8 format in case it contains non-ASCII characters. The private | ||||
| key corresponding to the certificate, and certificate chain (if any),  must | ||||
| also be present in the keychain. (Added in 7.31.0) | ||||
| .IP CURLOPT_SSLCERTTYPE | ||||
| Pass a pointer to a zero terminated string as parameter. The string should be | ||||
| the format of your certificate. Supported formats are "PEM" and "DER".  (Added | ||||
| @@ -2216,6 +2318,10 @@ in 7.9.3) | ||||
| Pass a pointer to a zero terminated string as parameter. The string should be | ||||
| the file name of your private key. The default format is "PEM" and can be | ||||
| changed with \fICURLOPT_SSLKEYTYPE\fP. | ||||
|  | ||||
| (iOS and Mac OS X only) This option is ignored if curl was built against Secure | ||||
| Transport. Secure Transport expects the private key to be already present in | ||||
| the keychain containing the certificate. | ||||
| .IP CURLOPT_SSLKEYTYPE | ||||
| Pass a pointer to a zero terminated string as parameter. The string should be | ||||
| the format of your private key. Supported formats are "PEM", "DER" and "ENG". | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -42,7 +42,7 @@ After the \fIlastitem\fP pointer follow the real arguments. | ||||
| The pointers \fIfirstitem\fP and \fIlastitem\fP should both be pointing to | ||||
| NULL in the first call to this function. All list-data will be allocated by | ||||
| the function itself. You must call \fIcurl_formfree(3)\fP on the | ||||
| \fIfirstitem\P after the form post has been done to free the resources. | ||||
| \fIfirstitem\fP after the form post has been done to free the resources. | ||||
|  | ||||
| Using POST with HTTP 1.1 implies the use of a "Expect: 100-continue" header. | ||||
| You can disable this header with \fICURLOPT_HTTPHEADER\fP as usual. | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -29,9 +29,9 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle); | ||||
| .ad | ||||
| .SH DESCRIPTION | ||||
| Adds a standard easy handle to the multi stack. This function call will make | ||||
| this \fImulti_handle\fP control the specified \fIeasy_handle\fP. | ||||
| Furthermore, libcurl now initiates the connection associated with the | ||||
| specified \fIeasy_handle\fP. | ||||
| this \fImulti_handle\fP control the specified \fIeasy_handle\fP.  Furthermore, | ||||
| libcurl now initiates the connection associated with the specified | ||||
| \fIeasy_handle\fP. | ||||
|  | ||||
| When an easy handle has been added to a multi stack, you can not and you must | ||||
| not use \fIcurl_easy_perform(3)\fP on that handle! | ||||
| @@ -41,6 +41,12 @@ cache (CURLOPT_DNS_USE_GLOBAL_CACHE), it will be made to use the DNS cache | ||||
| that is shared between all easy handles within the multi handle when | ||||
| \fIcurl_multi_add_handle(3)\fP is called. | ||||
|  | ||||
| If you have CURLMOPT_TIMERFUNCTION set in the multi handle (and you really | ||||
| should if you're working event-based with \fIcurl_multi_socket_action(3)\fP | ||||
| and friends), that callback will be called from within this function to ask | ||||
| for an updated timer so that your main event loop will get the activity on | ||||
| this handle to get started. | ||||
|  | ||||
| The easy handle will remain added until you remove it again with | ||||
| \fIcurl_multi_remove_handle(3)\fP. You should remove the easy handle from the | ||||
| multi stack before you terminate first the easy handle and then the multi | ||||
|   | ||||
| @@ -74,9 +74,9 @@ The socket \fBcallback\fP function uses a prototype like this | ||||
|                            int action,      /* see values below */ | ||||
|                            void *userp,    /* private callback pointer */ | ||||
|                            void *socketp); /* private socket pointer, | ||||
|                                               \fBNULL\fI if not | ||||
|                                               \fBNULL\fP if not | ||||
|                                               previously assigned with | ||||
|                                               \fIcurl_multi_assign(3)\fP */ | ||||
|                                               \fBcurl_multi_assign(3)\fP */ | ||||
|  | ||||
| .fi | ||||
| The callback MUST return 0. | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -36,12 +36,17 @@ CURLMcode curl_multi_wait(CURLM *multi_handle, | ||||
| This function polls on all file descriptors used by the curl easy handles | ||||
| contained in the given multi handle set.  It will block until activity is | ||||
| detected on at least one of the handles or \fItimeout_ms\fP has passed. | ||||
| Alternatively, if the multi handle has a pending internal timeout that has a | ||||
| shorter expiry time than \fItimeout_ms\fP, that shorter time will be used | ||||
| instead to make sure timeout accuracy is reasonably kept. | ||||
|  | ||||
| The calling application may pass additional curl_waitfd structures which are | ||||
| similar to \fIpoll(2)\fP's pollfd structure to be waited on in the same call. | ||||
|  | ||||
| On completion, if \fInumfds\fP is supplied, it will be populated with the | ||||
| number of file descriptors on which interesting events occured. | ||||
| total number of file descriptors on which interesting events occured. This | ||||
| number can include both libcurl internal descriptors as well as descriptors | ||||
| provided in \fIextra_fds\fP. | ||||
|  | ||||
| If no extra file descriptors are provided and libcurl has no file descriptor | ||||
| to offer to wait for, this function will return immediately. | ||||
|   | ||||
| @@ -34,8 +34,10 @@ The share interface was added to enable sharing of data between curl | ||||
| \&"handles". | ||||
| .SH "ONE SET OF DATA - MANY TRANSFERS" | ||||
| You can have multiple easy handles share data between them. Have them update | ||||
| and use the \fBsame\fP cookie database or DNS cache! This way, each single | ||||
| transfer will take advantage from data updates made by the other transfer(s). | ||||
| and use the \fBsame\fP cookie database, DNS cache, TLS session cache! This | ||||
| way, each single transfer will take advantage from data updates made by the | ||||
| other transfer(s). The sharing interface, however, does not share active or | ||||
| persistent connections between different easy handles. | ||||
| .SH "SHARE OBJECT" | ||||
| You create a shared object with \fIcurl_share_init(3)\fP. It returns a handle | ||||
| for a newly created one. | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
| .\" *                            | (__| |_| |  _ <| |___ | ||||
| .\" *                             \___|\___/|_| \_\_____| | ||||
| .\" * | ||||
| .\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
| .\" * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -1157,13 +1157,13 @@ and install a CURLOPT_OPENSOCKETFUNCTION callback function in which addresses | ||||
| are sanitized before use. | ||||
|  | ||||
| .IP "Private Resources" | ||||
| A user who can control the DNS server of a domain being passed in within | ||||
| a URL can change the address of the host to a local, private address | ||||
| which the libcurl application will then use. e.g. The innocuous URL | ||||
| http://fuzzybunnies.example.com/ could actually resolve to the IP address | ||||
| of a server behind a firewall, such as 127.0.0.1 or 10.1.2.3 | ||||
| Apps can mitigate against this by setting a CURLOPT_OPENSOCKETFUNCTION | ||||
| and checking the address before a connection. | ||||
| A user who can control the DNS server of a domain being passed in within a URL | ||||
| can change the address of the host to a local, private address which a | ||||
| server-side libcurl-using application could then use. e.g. the innocuous URL | ||||
| http://fuzzybunnies.example.com/ could actually resolve to the IP address of a | ||||
| server behind a firewall, such as 127.0.0.1 or 10.1.2.3.  Apps can mitigate | ||||
| against this by setting a CURLOPT_OPENSOCKETFUNCTION and checking the address | ||||
| before a connection. | ||||
|  | ||||
| All the malicious scenarios regarding redirected URLs apply just as well | ||||
| to non-redirected URLs, if the user is allowed to specify an arbitrary URL | ||||
| @@ -1178,6 +1178,19 @@ IP address and port number for a server local to the app running libcurl | ||||
| but behind a firewall.  Apps can mitigate against this by using the | ||||
| CURLOPT_FTP_SKIP_PASV_IP option or CURLOPT_FTPPORT. | ||||
|  | ||||
| .IP "IPv6 Addresses" | ||||
| libcurl will normally handle IPv6 addresses transparently and just as easily | ||||
| as IPv4 addresses. That means that a sanitizing function that filters out | ||||
| addressses like 127.0.0.1 isn't sufficient--the equivalent IPv6 addresses ::1, | ||||
| ::, 0:00::0:1, ::127.0.0.1 and ::ffff:7f00:1 supplied somehow by an attacker | ||||
| would all bypass a naive filter and could allow access to undesired local | ||||
| resources.  IPv6 also has special address blocks like link-local and site-local | ||||
| that generally shouldn't be accessed by a server-side libcurl-using | ||||
| application.  A poorly-configured firewall installed in a data center, | ||||
| organization or server may also be configured to limit IPv4 connections but | ||||
| leave IPv6 connections wide open.  In some cases, the CURL_IPRESOLVE_V4 option | ||||
| can be used to limit resolved addresses to IPv4 only and bypass these issues. | ||||
|  | ||||
| .IP Uploads | ||||
| When uploading, a redirect can cause a local (or remote) file to be | ||||
| overwritten.  Apps must not allow any unsanitized URL to be passed in | ||||
| @@ -1250,7 +1263,7 @@ using the Content-disposition: header to generate a file name.  An application | ||||
| could also use CURLINFO_EFFECTIVE_URL to generate a file name from a | ||||
| server-supplied redirect URL. Special care must be taken to sanitize such | ||||
| names to avoid the possibility of a malicious server supplying one like | ||||
| "/etc/passwd", "\autoexec.bat" or even ".bashrc". | ||||
| "/etc/passwd", "\\autoexec.bat", "prn:" or even ".bashrc". | ||||
|  | ||||
| .IP "Server Certificates" | ||||
| A secure application should never use the CURLOPT_SSL_VERIFYPEER option to | ||||
| @@ -1263,10 +1276,15 @@ validated certificates is potentially as insecure as a plain HTTP connection. | ||||
| On a related issue, be aware that even in situations like when you have | ||||
| problems with libcurl and ask someone for help, everything you reveal in order | ||||
| to get best possible help might also impose certain security related | ||||
| risks. Host names, user names, paths, operating system specifics, etc (not to | ||||
| risks. Host names, user names, paths, operating system specifics, etc. (not to | ||||
| mention passwords of course) may in fact be used by intruders to gain | ||||
| additional information of a potential target. | ||||
|  | ||||
| Be sure to limit access to application logs if they could hold private or | ||||
| security-related data.  Besides the obvious candidates like user names and | ||||
| passwords, things like URLs, cookies or even file names could also hold | ||||
| sensitive data. | ||||
|  | ||||
| To avoid this problem, you must of course use your common sense. Often, you | ||||
| can just edit out the sensitive data or just search/replace your true | ||||
| information with faked data. | ||||
| @@ -1347,10 +1365,10 @@ automatically share a lot of the data that otherwise would be kept on a | ||||
| per-easy handle basis when the easy interface is used. | ||||
|  | ||||
| The DNS cache is shared between handles within a multi handle, making | ||||
| subsequent name resolvings faster and the connection pool that is kept to | ||||
| better allow persistent connections and connection re-use is shared. If you're | ||||
| using the easy interface, you can still share these between specific easy | ||||
| handles by using the share interface, see \fIlibcurl-share(3)\fP. | ||||
| subsequent name resolving faster, and the connection pool that is kept to | ||||
| better allow persistent connections and connection re-use is also shared. If | ||||
| you're using the easy interface, you can still share these between specific | ||||
| easy handles by using the share interface, see \fIlibcurl-share(3)\fP. | ||||
|  | ||||
| Some things are never shared automatically, not within multi handles, like for | ||||
| example cookies so the only way to share that is with the share interface. | ||||
|   | ||||
| @@ -428,7 +428,7 @@ CURLOPT_POSTREDIR               7.19.1 | ||||
| CURLOPT_PREQUOTE                7.9.5 | ||||
| CURLOPT_PRIVATE                 7.10.3 | ||||
| CURLOPT_PROGRESSDATA            7.1 | ||||
| CURLOPT_PROGRESSFUNCTION        7.1 | ||||
| CURLOPT_PROGRESSFUNCTION        7.1           7.32.0 | ||||
| CURLOPT_PROTOCOLS               7.19.4 | ||||
| CURLOPT_PROXY                   7.1 | ||||
| CURLOPT_PROXYAUTH               7.10.7 | ||||
| @@ -456,6 +456,7 @@ CURLOPT_RTSP_SERVER_CSEQ        7.20.0 | ||||
| CURLOPT_RTSP_SESSION_ID         7.20.0 | ||||
| CURLOPT_RTSP_STREAM_URI         7.20.0 | ||||
| CURLOPT_RTSP_TRANSPORT          7.20.0 | ||||
| CURLOPT_SASL_IR                 7.31.0 | ||||
| CURLOPT_SEEKDATA                7.18.0 | ||||
| CURLOPT_SEEKFUNCTION            7.18.0 | ||||
| CURLOPT_SERVER_RESPONSE_TIMEOUT 7.20.0 | ||||
| @@ -524,6 +525,8 @@ CURLOPT_WRITEDATA               7.9.7 | ||||
| CURLOPT_WRITEFUNCTION           7.1 | ||||
| CURLOPT_WRITEHEADER             7.1 | ||||
| CURLOPT_WRITEINFO               7.1 | ||||
| CURLOPT_XFERINFODATA            7.32.0 | ||||
| CURLOPT_XFERINFOFUNCTION        7.32.0 | ||||
| CURLPAUSE_ALL                   7.18.0 | ||||
| CURLPAUSE_CONT                  7.18.0 | ||||
| CURLPAUSE_RECV                  7.18.0 | ||||
|   | ||||
| @@ -60,11 +60,16 @@ unlink (remove) certdata.txt after processing | ||||
| be verbose and print out processed CAs | ||||
| .SH EXIT STATUS | ||||
| Returns 0 on success. Returns 1 if it fails to download data. | ||||
| .SH CERTDATA FORMAT | ||||
| The file format used by Mozilla for this trust information seems to be documented here: | ||||
| .nf | ||||
| http://p11-glue.freedesktop.org/doc/storing-trust-policy/storing-trust-existing.html | ||||
| .fi | ||||
| .SH SEE ALSO | ||||
| .BR curl (1) | ||||
| .SH HISTORY | ||||
| \fBmk-ca-bundle\fP is a command line tool that is shipped as part of every | ||||
| curl and libcurl release (see http://curl.haxx.se/). It was originally based | ||||
| on the parse-certs script written by Roland Krikava and was later much | ||||
| improved by Guenter Knauf.  This manual page was written by Jan Schaumann | ||||
| \&<jschauma@netmeister.org>. | ||||
| improved by Guenter Knauf.  This manual page was initially written by Jan | ||||
| Schaumann \&<jschauma@netmeister.org>. | ||||
|   | ||||
| @@ -156,12 +156,22 @@ struct curl_httppost { | ||||
|                                        HTTPPOST_CALLBACK posts */ | ||||
| }; | ||||
|  | ||||
| /* This is the CURLOPT_PROGRESSFUNCTION callback proto. It is now considered | ||||
|    deprecated but was the only choice up until 7.31.0 */ | ||||
| typedef int (*curl_progress_callback)(void *clientp, | ||||
|                                       double dltotal, | ||||
|                                       double dlnow, | ||||
|                                       double ultotal, | ||||
|                                       double ulnow); | ||||
|  | ||||
| /* This is the CURLOPT_XFERINFOFUNCTION callback proto. It was introduced in | ||||
|    7.32.0, it avoids floating point and provides more detailed information. */ | ||||
| typedef int (*curl_xferinfo_callback)(void *clientp, | ||||
|                                       curl_off_t dltotal, | ||||
|                                       curl_off_t dlnow, | ||||
|                                       curl_off_t ultotal, | ||||
|                                       curl_off_t ulnow); | ||||
|  | ||||
| #ifndef CURL_MAX_WRITE_SIZE | ||||
|   /* Tests have proven that 20K is a very bad buffer size for uploads on | ||||
|      Windows, while 16K for some odd reason performed a lot better. | ||||
| @@ -968,13 +978,16 @@ typedef enum { | ||||
|  | ||||
|   /* 55 = OBSOLETE */ | ||||
|  | ||||
|   /* Function that will be called instead of the internal progress display | ||||
|   /* DEPRECATED | ||||
|    * Function that will be called instead of the internal progress display | ||||
|    * function. This function should be defined as the curl_progress_callback | ||||
|    * prototype defines. */ | ||||
|   CINIT(PROGRESSFUNCTION, FUNCTIONPOINT, 56), | ||||
|  | ||||
|   /* Data passed to the progress callback */ | ||||
|   /* Data passed to the CURLOPT_PROGRESSFUNCTION and CURLOPT_XFERINFOFUNCTION | ||||
|      callbacks */ | ||||
|   CINIT(PROGRESSDATA, OBJECTPOINT, 57), | ||||
| #define CURLOPT_XFERINFODATA CURLOPT_PROGRESSDATA | ||||
|  | ||||
|   /* We want the referrer field set automatically when following locations */ | ||||
|   CINIT(AUTOREFERER, LONG, 58), | ||||
| @@ -1527,9 +1540,17 @@ typedef enum { | ||||
|   /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */ | ||||
|   CINIT(SSL_OPTIONS, LONG, 216), | ||||
|  | ||||
|   /* set the SMTP auth originator */ | ||||
|   /* Set the SMTP auth originator */ | ||||
|   CINIT(MAIL_AUTH, OBJECTPOINT, 217), | ||||
|  | ||||
|   /* Enable/disable SASL initial response */ | ||||
|   CINIT(SASL_IR, LONG, 218), | ||||
|  | ||||
|   /* Function that will be called instead of the internal progress display | ||||
|    * function. This function should be defined as the curl_xferinfo_callback | ||||
|    * prototype defines. (Deprecates CURLOPT_PROGRESSFUNCTION) */ | ||||
|   CINIT(XFERINFOFUNCTION, FUNCTIONPOINT, 219), | ||||
|  | ||||
|   CURLOPT_LASTENTRY /* the last unused */ | ||||
| } CURLoption; | ||||
|  | ||||
|   | ||||
| @@ -30,12 +30,12 @@ | ||||
|  | ||||
| /* This is the version number of the libcurl package from which this header | ||||
|    file origins: */ | ||||
| #define LIBCURL_VERSION "7.30.0-DEV" | ||||
| #define LIBCURL_VERSION "7.32.0-DEV" | ||||
|  | ||||
| /* The numeric version number is also available "in parts" by using these | ||||
|    defines: */ | ||||
| #define LIBCURL_VERSION_MAJOR 7 | ||||
| #define LIBCURL_VERSION_MINOR 30 | ||||
| #define LIBCURL_VERSION_MINOR 32 | ||||
| #define LIBCURL_VERSION_PATCH 0 | ||||
|  | ||||
| /* This is the numeric version of the libcurl version number, meant for easier | ||||
| @@ -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 0x071e00 | ||||
| #define LIBCURL_VERSION_NUM 0x072000 | ||||
|  | ||||
| /* | ||||
|  * This is the date and time when the full source package was created. The | ||||
|   | ||||
| @@ -94,6 +94,10 @@ add_library( | ||||
|   ${HHEADERS} ${CSOURCES} | ||||
|   ) | ||||
|  | ||||
| if(MSVC AND CURL_STATICLIB) | ||||
|   set_target_properties(${LIB_NAME} PROPERTIES STATIC_LIBRARY_FLAGS ${CMAKE_EXE_LINKER_FLAGS}) | ||||
| endif() | ||||
|  | ||||
| target_link_libraries(${LIB_NAME} ${CURL_LIBS}) | ||||
|  | ||||
| if(WIN32) | ||||
| @@ -108,14 +112,6 @@ setup_curl_dependencies(${LIB_NAME}) | ||||
| set_target_properties(${LIB_NAME} PROPERTIES PREFIX "") | ||||
| set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "") | ||||
|  | ||||
| if(MSVC) | ||||
|   if(NOT BUILD_RELEASE_DEBUG_DIRS) | ||||
|     # Ugly workaround to remove the "/debug" or "/release" in each output | ||||
|     set_target_properties(${LIB_NAME} PROPERTIES PREFIX "../") | ||||
|     set_target_properties(${LIB_NAME} PROPERTIES IMPORT_PREFIX "../") | ||||
|   endif() | ||||
| endif() | ||||
|  | ||||
| if(WIN32) | ||||
|   if(NOT CURL_STATICLIB) | ||||
|     # Add "_imp" as a suffix before the extension to avoid conflicting with the statically linked "libcurl.lib" | ||||
|   | ||||
| @@ -83,7 +83,7 @@ CFLAGS += -dWANT_IDN_PROTOTYPES | ||||
| !ifdef %zlib_root | ||||
| ZLIB_ROOT = $(%zlib_root) | ||||
| !else | ||||
| ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.7 | ||||
| ZLIB_ROOT = ..$(DS)..$(DS)zlib-1.2.8 | ||||
| !endif | ||||
|  | ||||
| !ifdef %libssh2_root | ||||
|   | ||||
| @@ -141,7 +141,7 @@ libcurl_la_CFLAGS_EXTRA += $(CFLAG_CURL_SYMBOL_HIDING) | ||||
| endif | ||||
|  | ||||
| libcurl_la_CPPFLAGS = $(AM_CPPFLAGS) $(libcurl_la_CPPFLAGS_EXTRA) | ||||
| libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LIBCURL_LIBS) | ||||
| libcurl_la_LDFLAGS = $(AM_LDFLAGS) $(libcurl_la_LDFLAGS_EXTRA) $(LDFLAGS) $(LIBCURL_LIBS) | ||||
| libcurl_la_CFLAGS = $(AM_CFLAGS) $(libcurl_la_CFLAGS_EXTRA) | ||||
|  | ||||
| libcurlu_la_CPPFLAGS = $(AM_CPPFLAGS) -DCURL_STATICLIB -DUNITTESTS | ||||
|   | ||||
| @@ -22,7 +22,7 @@ BCCDIR = $(MAKEDIR)\.. | ||||
|  | ||||
| # Edit the path below to point to the base of your Zlib sources. | ||||
| !ifndef ZLIB_PATH | ||||
| ZLIB_PATH = ..\..\zlib-1.2.7 | ||||
| ZLIB_PATH = ..\..\zlib-1.2.8 | ||||
| !endif | ||||
|  | ||||
| # Edit the path below to point to the base of your OpenSSL package. | ||||
| @@ -52,7 +52,7 @@ LDFLAGS  = -q -lq -laa -tWD | ||||
| SRCDIR   = . | ||||
| OBJDIR   = .\BCC_objs | ||||
| INCDIRS  = -I.;..\include | ||||
| LINKLIB  = $(BCCDIR)\lib\cw32mt.lib | ||||
| LINKLIB  = $(BCCDIR)\lib\cw32mt.lib $(BCCDIR)\lib\ws2_32.lib | ||||
| DEFINES  = -DNDEBUG -DWIN32 -DBUILDING_LIBCURL | ||||
|  | ||||
| # By default SSPI support is enabled for BCC | ||||
| @@ -88,8 +88,24 @@ LINKLIB  = $(LINKLIB) $(OPENSSL_PATH)\out32\ssleay32.lib $(OPENSSL_PATH)\out32\l | ||||
| # Makefile.inc provides the CSOURCES and HHEADERS defines | ||||
| !include Makefile.inc | ||||
|  | ||||
| OBJECTS = $(CSOURCES:.c=.obj) | ||||
| PREPROCESSED = $(CSOURCES:.c=.int) | ||||
| # Borland's command line librarian program TLIB version 4.5 is not capable | ||||
| # of building a library when any of its objects contains an hypen in its | ||||
| # name, due to a command line parsing bug. In order to workaround this, we | ||||
| # build source files with hyphens in their name as objects with underscores | ||||
| # using explicit compilation build rules instead of implicit ones. | ||||
|  | ||||
| NOHYPHEN = $(CSOURCES:-=_) | ||||
|  | ||||
| OBJECTS = $(NOHYPHEN:.c=.obj) | ||||
| PREPROCESSED = $(NOHYPHEN:.c=.int) | ||||
|  | ||||
| # Borland's command line compiler (BCC32) version 5.5.1 integrated | ||||
| # preprocessor has a bug which results in silently generating wrong | ||||
| # definitions for libcurl macros such as CURL_OFF_T_C, on the other | ||||
| # hand Borland's command line preprocessor (CPP32) version 5.5.1 does | ||||
| # not have the bug and achieves proper results. In order to avoid the | ||||
| # silent bug we first preprocess source files and later compile the | ||||
| # preprocessed result. | ||||
|  | ||||
| .c.obj: | ||||
| 	@-$(RM) $(@R).int | ||||
| @@ -98,6 +114,21 @@ PREPROCESSED = $(CSOURCES:.c=.int) | ||||
|  | ||||
| all:	$(OBJDIR) $(LIBCURL_LIB) $(LIBCURL_DLL) | ||||
|  | ||||
| asyn_ares.obj: asyn-ares.c | ||||
| 	@-$(RM) $(@R).int | ||||
| 	$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) | ||||
| 	$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int | ||||
|  | ||||
| asyn_thread.obj: asyn-thread.c | ||||
| 	@-$(RM) $(@R).int | ||||
| 	$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) | ||||
| 	$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int | ||||
|  | ||||
| non_ascii.obj: non-ascii.c | ||||
| 	@-$(RM) $(@R).int | ||||
| 	$(PP_CMD) $(CC_FLAGS) $(INCDIRS) $(DEFINES) -o$(@R).int $(?) | ||||
| 	$(CC_CMD) $(CC_FLAGS) -o$(@) $(@R).int | ||||
|  | ||||
| clean: | ||||
| 	cd $(OBJDIR) | ||||
| 	@-$(RM) $(OBJECTS) | ||||
| @@ -122,7 +153,10 @@ $(LIBCURL_LIB): $(OBJECTS) | ||||
| $(LIBCURL_DLL) $(LIBCURL_IMPLIB): $(OBJECTS) $(LINKLIB) | ||||
| 	@-$(RM) $(LIBCURL_DLL) | ||||
| 	@-$(RM) $(LIBCURL_IMPLIB) | ||||
| 	$(LD) $(LDFLAGS) -e$(LIBCURL_DLL) $** | ||||
| 	$(LD) $(LDFLAGS) -e$(LIBCURL_DLL) @&&! | ||||
| $(**: = ^ | ||||
| ) | ||||
| ! | ||||
| 	$(IMPLIB) $(LIBCURL_IMPLIB) $(LIBCURL_DLL) | ||||
|  | ||||
|  | ||||
|   | ||||
| @@ -13,7 +13,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c	\ | ||||
|   netrc.c getinfo.c transfer.c strequal.c easy.c security.c krb4.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	\ | ||||
|   content_encoding.c share.c http_digest.c md4.c md5.c	\ | ||||
|   http_negotiate.c inet_pton.c strtoofft.c strerror.c amigaos.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	\ | ||||
| @@ -25,12 +25,13 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c	\ | ||||
|   http_proxy.c non-ascii.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		\ | ||||
|   curl_sasl.c curl_schannel.c curl_multibyte.c curl_darwinssl.c		\ | ||||
|   hostcheck.c bundles.c conncache.c pipeline.c | ||||
|   hostcheck.c bundles.c conncache.c pipeline.c dotdot.c x509asn1.c      \ | ||||
|   gskit.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	\ | ||||
|   if2ip.h speedcheck.h urldata.h curl_ldap.h ssluse.h escape.h telnet.h	\ | ||||
|   getinfo.h strequal.h krb4.h memdebug.h http_chunks.h curl_rand.h	\ | ||||
|   getinfo.h strequal.h krb4.h memdebug.h http_chunks.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 inet_pton.h amigaos.h	\ | ||||
| @@ -44,4 +45,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h	\ | ||||
|   asyn.h curl_ntlm.h curl_gssapi.h curl_ntlm_wb.h curl_ntlm_core.h	\ | ||||
|   curl_ntlm_msgs.h curl_sasl.h curl_schannel.h curl_multibyte.h		\ | ||||
|   curl_darwinssl.h hostcheck.h bundles.h conncache.h curl_setup_once.h	\ | ||||
|   multihandle.h setup-vms.h pipeline.h | ||||
|   multihandle.h setup-vms.h pipeline.h dotdot.h x509asn1.h gskit.h | ||||
|   | ||||
| @@ -7,14 +7,14 @@ | ||||
| ## Example: mingw32-make -f Makefile.m32 CFG=-zlib-ssl-sspi-winidn | ||||
| ## | ||||
| ## Hint: you can also set environment vars to control the build, f.e.: | ||||
| ## set ZLIB_PATH=c:/zlib-1.2.7 | ||||
| ## set ZLIB_PATH=c:/zlib-1.2.8 | ||||
| ## set ZLIB=1 | ||||
| # | ||||
| ########################################################################### | ||||
|  | ||||
| # Edit the path below to point to the base of your Zlib sources. | ||||
| ifndef ZLIB_PATH | ||||
| ZLIB_PATH = ../../zlib-1.2.7 | ||||
| ZLIB_PATH = ../../zlib-1.2.8 | ||||
| endif | ||||
| # Edit the path below to point to the base of your OpenSSL package. | ||||
| ifndef OPENSSL_PATH | ||||
|   | ||||
| @@ -14,7 +14,7 @@ endif | ||||
|  | ||||
| # Edit the path below to point to the base of your Zlib sources. | ||||
| ifndef ZLIB_PATH | ||||
| ZLIB_PATH = ../../zlib-1.2.7 | ||||
| ZLIB_PATH = ../../zlib-1.2.8 | ||||
| endif | ||||
|  | ||||
| # Edit the path below to point to the base of your OpenSSL package. | ||||
|   | ||||
| @@ -73,7 +73,7 @@ LIBSSH2_PATH   = ../../libssh2-1.4.3 | ||||
| !ENDIF | ||||
|  | ||||
| !IFNDEF ZLIB_PATH | ||||
| ZLIB_PATH  = ../../zlib-1.2.7 | ||||
| ZLIB_PATH  = ../../zlib-1.2.8 | ||||
| !ENDIF | ||||
|  | ||||
| !IFNDEF MACHINE | ||||
| @@ -103,23 +103,24 @@ WINDOWS_SDK_PATH = "$(PROGRAMFILES)\Microsoft SDK" | ||||
| ############################################################# | ||||
| ## Nothing more to do below this line! | ||||
|  | ||||
| CCNODBG    = cl.exe /O2 /DNDEBUG | ||||
| CCDEBUG    = cl.exe /Od /Gm /Zi /D_DEBUG /GZ | ||||
| CFLAGSSSL  = /DUSE_SSLEAY /DUSE_OPENSSL /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 | ||||
| LNKDLL     = link.exe /DLL | ||||
| LNKLIB     = link.exe /lib | ||||
| LFLAGS     = /nologo /machine:$(MACHINE) | ||||
| SSLLIBS    = libeay32.lib ssleay32.lib | ||||
| ZLIBLIBSDLL= zdll.lib | ||||
| ZLIBLIBS   = zlib.lib | ||||
| WINLIBS    = ws2_32.lib wldap32.lib advapi32.lib | ||||
| CFLAGS     = $(CFLAGS) | ||||
| CCNODBG      = cl.exe /O2 /DNDEBUG | ||||
| CCDEBUG      = cl.exe /Od /Gm /Zi /D_DEBUG /GZ | ||||
| CFLAGSSSL    = /DUSE_SSLEAY /DUSE_OPENSSL /I "$(OPENSSL_PATH)/inc32" /I "$(OPENSSL_PATH)/inc32/openssl" | ||||
| CFLAGSWINSSL = /DUSE_SCHANNEL | ||||
| 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 | ||||
| LNKDLL       = link.exe /DLL | ||||
| LNKLIB       = link.exe /lib | ||||
| LFLAGS       = /nologo /machine:$(MACHINE) | ||||
| SSLLIBS      = libeay32.lib ssleay32.lib | ||||
| ZLIBLIBSDLL  = zdll.lib | ||||
| ZLIBLIBS     = zlib.lib | ||||
| WINLIBS      = ws2_32.lib wldap32.lib advapi32.lib | ||||
| CFLAGS       = $(CFLAGS) | ||||
|  | ||||
| CFGSET     = FALSE | ||||
| CFGSET       = FALSE | ||||
|  | ||||
| !IFDEF WINDOWS_SSPI | ||||
| CFLAGS = $(CFLAGS) /DUSE_WINDOWS_SSPI /I$(WINDOWS_SDK_PATH)\include | ||||
| @@ -189,6 +190,18 @@ CC       = $(CCNODBG) $(RTLIB) $(CFLAGSSSL) $(CFLAGSZLIB) $(CFLAGSLIB) | ||||
| CFGSET   = TRUE | ||||
| !ENDIF | ||||
|  | ||||
| ###################### | ||||
| # release-winssl-zlib | ||||
|  | ||||
| !IF "$(CFG)" == "release-winssl-zlib" | ||||
| TARGET   = $(LIBCURL_STA_LIB_REL) | ||||
| DIROBJ   = $(CFG) | ||||
| LFLAGSZLIB = "/LIBPATH:$(ZLIB_PATH)" | ||||
| LNK      = $(LNKLIB) $(LFLAGSZLIB) /out:$(DIROBJ)\$(TARGET) | ||||
| CC       = $(CCNODBG) $(RTLIB) $(CFLAGSWINSSL) $(CFLAGSZLIB) $(CFLAGSLIB) | ||||
| CFGSET   = TRUE | ||||
| !ENDIF | ||||
|  | ||||
| ###################### | ||||
| # release-ssl-ssh2-zlib | ||||
|  | ||||
| @@ -515,7 +528,6 @@ X_OBJS= \ | ||||
| 	$(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_sasl.obj \ | ||||
| 	$(DIROBJ)\curl_schannel.obj \ | ||||
| @@ -523,6 +535,7 @@ X_OBJS= \ | ||||
| 	$(DIROBJ)\curl_threads.obj \ | ||||
| 	$(DIROBJ)\cyassl.obj \ | ||||
| 	$(DIROBJ)\dict.obj \ | ||||
| 	$(DIROBJ)\dotdot.obj \ | ||||
| 	$(DIROBJ)\easy.obj \ | ||||
| 	$(DIROBJ)\escape.obj \ | ||||
| 	$(DIROBJ)\file.obj \ | ||||
|   | ||||
| @@ -35,8 +35,8 @@ USER_CFLAGS:= | ||||
| # directories where to seek for includes and libraries | ||||
| OPENSSL_INC := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3/include | ||||
| OPENSSL_LIB := D:/libraries/openssl/openssl-0.9.8y-vxWorks6.3 | ||||
| ZLIB_INC    := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/zlib-1.2.7 | ||||
| ZLIB_LIB    := D:/libraries/zlib/zlib-1.2.7-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib | ||||
| ZLIB_INC    := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/zlib-1.2.8 | ||||
| ZLIB_LIB    := D:/libraries/zlib/zlib-1.2.8-VxWorks6.3/binaries/vxworks_3.1_gnu/Debug/lib | ||||
| ARES_INC    := | ||||
| ARES_LIB    := | ||||
|  | ||||
|   | ||||
| @@ -315,6 +315,7 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct ResolverResults *res = (struct ResolverResults *) | ||||
|     conn->async.os_specific; | ||||
|   CURLcode rc = CURLE_OK; | ||||
|  | ||||
|   *dns = NULL; | ||||
|  | ||||
| @@ -325,19 +326,19 @@ CURLcode Curl_resolver_is_resolved(struct connectdata *conn, | ||||
|     /* temp_ai ownership is moved to the connection, so we need not free-up | ||||
|        them */ | ||||
|     res->temp_ai = NULL; | ||||
|     destroy_async_data(&conn->async); | ||||
|     if(!conn->async.dns) { | ||||
|       failf(data, "Could not resolve %s: %s (%s)", | ||||
|             conn->bits.proxy?"proxy":"host", | ||||
|             conn->host.dispname, | ||||
|             ares_strerror(conn->async.status)); | ||||
|       return conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: | ||||
|       failf(data, "Could not resolve: %s (%s)", | ||||
|             conn->async.hostname, ares_strerror(conn->async.status)); | ||||
|       rc = conn->bits.proxy?CURLE_COULDNT_RESOLVE_PROXY: | ||||
|         CURLE_COULDNT_RESOLVE_HOST; | ||||
|     } | ||||
|     *dns = conn->async.dns; | ||||
|     else | ||||
|       *dns = conn->async.dns; | ||||
|  | ||||
|     destroy_async_data(&conn->async); | ||||
|   } | ||||
|  | ||||
|   return CURLE_OK; | ||||
|   return rc; | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -415,37 +416,12 @@ CURLcode Curl_resolver_wait_resolv(struct connectdata *conn, | ||||
|   if(entry) | ||||
|     *entry = conn->async.dns; | ||||
|  | ||||
|   if(!conn->async.dns) { | ||||
|     /* a name was not resolved */ | ||||
|     if((timeout < 0) || (conn->async.status == ARES_ETIMEOUT)) { | ||||
|       if(conn->bits.proxy) { | ||||
|         failf(data, "Resolving proxy timed out: %s", conn->proxy.dispname); | ||||
|         rc = CURLE_COULDNT_RESOLVE_PROXY; | ||||
|       } | ||||
|       else { | ||||
|         failf(data, "Resolving host timed out: %s", conn->host.dispname); | ||||
|         rc = CURLE_COULDNT_RESOLVE_HOST; | ||||
|       } | ||||
|     } | ||||
|     else if(conn->async.done) { | ||||
|       if(conn->bits.proxy) { | ||||
|         failf(data, "Could not resolve proxy: %s (%s)", conn->proxy.dispname, | ||||
|               ares_strerror(conn->async.status)); | ||||
|         rc = CURLE_COULDNT_RESOLVE_PROXY; | ||||
|       } | ||||
|       else { | ||||
|         failf(data, "Could not resolve host: %s (%s)", conn->host.dispname, | ||||
|               ares_strerror(conn->async.status)); | ||||
|         rc = CURLE_COULDNT_RESOLVE_HOST; | ||||
|       } | ||||
|     } | ||||
|     else | ||||
|       rc = CURLE_OPERATION_TIMEDOUT; | ||||
|  | ||||
|   if(rc) | ||||
|     /* close the connection, since we can't return failure here without | ||||
|        cleaning up this connection properly */ | ||||
|        cleaning up this connection properly. | ||||
|        TODO: remove this action from here, it is not a name resolver decision. | ||||
|     */ | ||||
|     conn->bits.close = TRUE; | ||||
|   } | ||||
|  | ||||
|   return rc; | ||||
| } | ||||
| @@ -614,8 +590,19 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, | ||||
|                               char *servers) | ||||
| { | ||||
|   CURLcode result = CURLE_NOT_BUILT_IN; | ||||
|   int ares_result; | ||||
|  | ||||
|   /* If server is NULL or empty, this would purge all DNS servers | ||||
|    * from ares library, which will cause any and all queries to fail. | ||||
|    * So, just return OK if none are configured and don't actually make | ||||
|    * any changes to c-ares.  This lets c-ares use it's defaults, which | ||||
|    * it gets from the OS (for instance from /etc/resolv.conf on Linux). | ||||
|    */ | ||||
|   if(!(servers && servers[0])) | ||||
|     return CURLE_OK; | ||||
|  | ||||
| #if (ARES_VERSION >= 0x010704) | ||||
|   int ares_result = ares_set_servers_csv(data->state.resolver, servers); | ||||
|   ares_result = ares_set_servers_csv(data->state.resolver, servers); | ||||
|   switch(ares_result) { | ||||
|   case ARES_SUCCESS: | ||||
|     result = CURLE_OK; | ||||
| @@ -632,7 +619,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, | ||||
|   } | ||||
| #else /* too old c-ares version! */ | ||||
|   (void)data; | ||||
|   (void)servers; | ||||
|   (void)(ares_result); | ||||
| #endif | ||||
|   return result; | ||||
| } | ||||
|   | ||||
							
								
								
									
										272
									
								
								lib/axtls.c
									
									
									
									
									
								
							
							
						
						
									
										272
									
								
								lib/axtls.c
									
									
									
									
									
								
							| @@ -41,26 +41,12 @@ | ||||
| #define _MPRINTF_REPLACE /* use our functions only */ | ||||
| #include <curl/mprintf.h> | ||||
| #include "curl_memory.h" | ||||
| #include <unistd.h> | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
| #include "hostcheck.h" | ||||
|  | ||||
|  | ||||
| /* SSL_read is opied from axTLS compat layer */ | ||||
| static int SSL_read(SSL *ssl, void *buf, int num) | ||||
| { | ||||
|   uint8_t *read_buf; | ||||
|   int ret; | ||||
|  | ||||
|   while((ret = ssl_read(ssl, &read_buf)) == SSL_OK); | ||||
|  | ||||
|   if(ret > SSL_OK) { | ||||
|     memcpy(buf, read_buf, ret > num ? num : ret); | ||||
|   } | ||||
|  | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /* Global axTLS init, called from Curl_ssl_init() */ | ||||
| int Curl_axtls_init(void) | ||||
| { | ||||
| @@ -131,31 +117,40 @@ static CURLcode map_error_to_curl(int axtls_err) | ||||
| static Curl_recv axtls_recv; | ||||
| static Curl_send axtls_send; | ||||
|  | ||||
| /* | ||||
|  * This function is called after the TCP connect has completed. Setup the TLS | ||||
|  * layer and do all necessary magic. | ||||
|  */ | ||||
| CURLcode | ||||
| Curl_axtls_connect(struct connectdata *conn, | ||||
|                   int sockindex) | ||||
| static void free_ssl_structs(struct ssl_connect_data *connssl) | ||||
| { | ||||
|   if(connssl->ssl) { | ||||
|     ssl_free (connssl->ssl); | ||||
|     connssl->ssl = NULL; | ||||
|   } | ||||
|   if(connssl->ssl_ctx) { | ||||
|     ssl_ctx_free(connssl->ssl_ctx); | ||||
|     connssl->ssl_ctx = NULL; | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * For both blocking and non-blocking connects, this function sets up the | ||||
|  * ssl context and state.  This function is called after the TCP connect | ||||
|  * has completed. | ||||
|  */ | ||||
| static CURLcode connect_prep(struct connectdata *conn, int sockindex) | ||||
| { | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   SSL_CTX *ssl_ctx; | ||||
|   SSL *ssl; | ||||
|   SSL *ssl = NULL; | ||||
|   int cert_types[] = {SSL_OBJ_X509_CERT, SSL_OBJ_PKCS12, 0}; | ||||
|   int key_types[] = {SSL_OBJ_RSA_KEY, SSL_OBJ_PKCS8, SSL_OBJ_PKCS12, 0}; | ||||
|   int i, ssl_fcn_return; | ||||
|   const uint8_t *ssl_sessionid; | ||||
|   size_t ssl_idsize; | ||||
|   const char *peer_CN; | ||||
|   uint32_t dns_altname_index; | ||||
|   const char *dns_altname; | ||||
|   int8_t found_subject_alt_names = 0; | ||||
|   int8_t found_subject_alt_name_matching_conn = 0; | ||||
|  | ||||
|   /* Assuming users will not compile in custom key/cert to axTLS */ | ||||
|   uint32_t client_option = SSL_NO_DEFAULT_KEY|SSL_SERVER_VERIFY_LATER; | ||||
|   /* Assuming users will not compile in custom key/cert to axTLS. | ||||
|   *  Also, even for blocking connects, use axTLS non-blocking feature. | ||||
|   */ | ||||
|   uint32_t client_option = SSL_NO_DEFAULT_KEY | | ||||
|     SSL_SERVER_VERIFY_LATER | | ||||
|     SSL_CONNECT_IN_PARTS; | ||||
|  | ||||
|   if(conn->ssl[sockindex].state == ssl_connection_complete) | ||||
|     /* to make us tolerant against being called more than once for the | ||||
| @@ -184,6 +179,9 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|     return CURLE_SSL_CONNECT_ERROR; | ||||
|   } | ||||
|  | ||||
|   conn->ssl[sockindex].ssl_ctx = ssl_ctx; | ||||
|   conn->ssl[sockindex].ssl = NULL; | ||||
|  | ||||
|   /* 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) | ||||
| @@ -191,7 +189,6 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|       infof(data, "error reading ca cert file %s \n", | ||||
|             data->set.ssl.CAfile); | ||||
|       if(data->set.ssl.verifypeer) { | ||||
|         Curl_axtls_close(conn, sockindex); | ||||
|         return CURLE_SSL_CACERT_BADFILE; | ||||
|       } | ||||
|     } | ||||
| @@ -225,7 +222,6 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|     if(cert_types[i] == 0) { | ||||
|       failf(data, "%s is not x509 or pkcs12 format", | ||||
|             data->set.str[STRING_CERT]); | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       return CURLE_SSL_CERTPROBLEM; | ||||
|     } | ||||
|   } | ||||
| @@ -250,7 +246,6 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|     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); | ||||
|       return CURLE_SSL_CONNECT_ERROR; | ||||
|     } | ||||
|   } | ||||
| @@ -271,14 +266,25 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|   else | ||||
|     ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0); | ||||
|  | ||||
|   /* Check to make sure handshake was ok. */ | ||||
|   ssl_fcn_return = ssl_handshake_status(ssl); | ||||
|   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); | ||||
|   } | ||||
|   infof (data, "handshake completed successfully\n"); | ||||
|   conn->ssl[sockindex].ssl = ssl; | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * For both blocking and non-blocking connects, this function finalizes the | ||||
|  * SSL connection. | ||||
|  */ | ||||
| static CURLcode connect_finish(struct connectdata *conn, int sockindex) | ||||
| { | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   SSL *ssl = conn->ssl[sockindex].ssl; | ||||
|   const uint8_t *ssl_sessionid; | ||||
|   size_t ssl_idsize; | ||||
|   const char *peer_CN; | ||||
|   uint32_t dns_altname_index; | ||||
|   const char *dns_altname; | ||||
|   int8_t found_subject_alt_names = 0; | ||||
|   int8_t found_subject_alt_name_matching_conn = 0; | ||||
|  | ||||
|   /* Here, gtls.c gets the peer certificates and fails out depending on | ||||
|    * settings in "data."  axTLS api doesn't have get cert chain fcn, so omit? | ||||
| @@ -289,7 +295,7 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|     if(ssl_verify_cert(ssl) != SSL_OK) { | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       failf(data, "server cert verify failed"); | ||||
|       return CURLE_SSL_CONNECT_ERROR; | ||||
|       return CURLE_PEER_FAILED_VERIFICATION; | ||||
|     } | ||||
|   } | ||||
|   else | ||||
| @@ -306,7 +312,6 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|    *    this, but a couple fields are available. | ||||
|    */ | ||||
|  | ||||
|  | ||||
|   /* There is no (DNS) Altnames count in the version 1.4.8 API. There is a | ||||
|      risk of an inifite loop */ | ||||
|   for(dns_altname_index = 0; ; dns_altname_index++) { | ||||
| @@ -326,20 +331,29 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|  | ||||
|   /* RFC2818 checks */ | ||||
|   if(found_subject_alt_names && !found_subject_alt_name_matching_conn) { | ||||
|     /* Break connection ! */ | ||||
|     Curl_axtls_close(conn, sockindex); | ||||
|     failf(data, "\tsubjectAltName(s) do not match %s\n", conn->host.dispname); | ||||
|     return CURLE_PEER_FAILED_VERIFICATION; | ||||
|     if(data->set.ssl.verifyhost) { | ||||
|       /* Break connection ! */ | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       failf(data, "\tsubjectAltName(s) do not match %s\n", | ||||
|             conn->host.dispname); | ||||
|       return CURLE_PEER_FAILED_VERIFICATION; | ||||
|     } | ||||
|     else | ||||
|       infof(data, "\tsubjectAltName(s) do not match %s\n", | ||||
|             conn->host.dispname); | ||||
|   } | ||||
|   else if(found_subject_alt_names == 0) { | ||||
|     /* Per RFC2818, when no Subject Alt Names were available, examine the peer | ||||
|        CN as a legacy fallback */ | ||||
|     peer_CN = ssl_get_cert_dn(ssl, SSL_X509_CERT_COMMON_NAME); | ||||
|     if(peer_CN == NULL) { | ||||
|       /* Similar behaviour to the OpenSSL interface */ | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       failf(data, "unable to obtain common name from peer certificate"); | ||||
|       return CURLE_PEER_FAILED_VERIFICATION; | ||||
|       if(data->set.ssl.verifyhost) { | ||||
|         Curl_axtls_close(conn, sockindex); | ||||
|         failf(data, "unable to obtain common name from peer certificate"); | ||||
|         return CURLE_PEER_FAILED_VERIFICATION; | ||||
|       } | ||||
|       else | ||||
|         infof(data, "unable to obtain common name from peer certificate"); | ||||
|     } | ||||
|     else { | ||||
|       if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) { | ||||
| @@ -359,8 +373,6 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|  | ||||
|   /* General housekeeping */ | ||||
|   conn->ssl[sockindex].state = ssl_connection_complete; | ||||
|   conn->ssl[sockindex].ssl = ssl; | ||||
|   conn->ssl[sockindex].ssl_ctx = ssl_ctx; | ||||
|   conn->recv[sockindex] = axtls_recv; | ||||
|   conn->send[sockindex] = axtls_send; | ||||
|  | ||||
| @@ -374,6 +386,107 @@ Curl_axtls_connect(struct connectdata *conn, | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Use axTLS's non-blocking connection feature to open an SSL connection. | ||||
|  * This is called after a TCP connection is already established. | ||||
| */ | ||||
| CURLcode Curl_axtls_connect_nonblocking( | ||||
|     struct connectdata *conn, | ||||
|     int sockindex, | ||||
|     bool *done) | ||||
| { | ||||
|   CURLcode conn_step; | ||||
|   int ssl_fcn_return; | ||||
|  | ||||
|  *done = FALSE; | ||||
|   /* connectdata is calloc'd and connecting_state is only changed in this | ||||
|      function, so this is safe, as the state is effectively initialized. */ | ||||
|   if(conn->ssl[sockindex].connecting_state == ssl_connect_1) { | ||||
|     conn_step = connect_prep(conn, sockindex); | ||||
|     if(conn_step != CURLE_OK) { | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       return conn_step; | ||||
|     } | ||||
|     conn->ssl[sockindex].connecting_state = ssl_connect_2; | ||||
|   } | ||||
|  | ||||
|   if(conn->ssl[sockindex].connecting_state == ssl_connect_2) { | ||||
|     /* Check to make sure handshake was ok. */ | ||||
|     if(ssl_handshake_status(conn->ssl[sockindex].ssl) != SSL_OK) { | ||||
|       ssl_fcn_return = ssl_read(conn->ssl[sockindex].ssl, NULL); | ||||
|       if(ssl_fcn_return < 0) { | ||||
|         Curl_axtls_close(conn, sockindex); | ||||
|         ssl_display_error(ssl_fcn_return); /* goes to stdout. */ | ||||
|         return map_error_to_curl(ssl_fcn_return); | ||||
|       } | ||||
|       else { | ||||
|         return CURLE_OK; /* Return control to caller for retries */ | ||||
|       } | ||||
|     } | ||||
|     infof (conn->data, "handshake completed successfully\n"); | ||||
|     conn->ssl[sockindex].connecting_state = ssl_connect_3; | ||||
|   } | ||||
|  | ||||
|   if(conn->ssl[sockindex].connecting_state == ssl_connect_3) { | ||||
|     conn_step = connect_finish(conn, sockindex); | ||||
|     if(conn_step != CURLE_OK) { | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       return conn_step; | ||||
|     } | ||||
|  | ||||
|     /* Reset connect state */ | ||||
|     conn->ssl[sockindex].connecting_state = ssl_connect_1; | ||||
|  | ||||
|     *done = TRUE; | ||||
|     return CURLE_OK; | ||||
|   } | ||||
|  | ||||
|   /* Unrecognized state.  Things are very bad. */ | ||||
|   conn->ssl[sockindex].state  = ssl_connection_none; | ||||
|   conn->ssl[sockindex].connecting_state = ssl_connect_1; | ||||
|   /* Return value perhaps not strictly correct, but distinguishes the issue.*/ | ||||
|   return CURLE_BAD_FUNCTION_ARGUMENT; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * This function is called after the TCP connect has completed. Setup the TLS | ||||
|  * layer and do all necessary magic for a blocking connect. | ||||
|  */ | ||||
| CURLcode | ||||
| Curl_axtls_connect(struct connectdata *conn, | ||||
|                   int sockindex) | ||||
|  | ||||
| { | ||||
|   CURLcode conn_step = connect_prep(conn, sockindex); | ||||
|   int ssl_fcn_return; | ||||
|   SSL *ssl = conn->ssl[sockindex].ssl; | ||||
|  | ||||
|   if(conn_step != CURLE_OK) { | ||||
|     Curl_axtls_close(conn, sockindex); | ||||
|     return conn_step; | ||||
|   } | ||||
|  | ||||
|   /* Check to make sure handshake was ok. */ | ||||
|   while(ssl_handshake_status(ssl) != SSL_OK) { | ||||
|     ssl_fcn_return = ssl_read(ssl, NULL); | ||||
|     if(ssl_fcn_return < 0) { | ||||
|       Curl_axtls_close(conn, sockindex); | ||||
|       ssl_display_error(ssl_fcn_return); /* goes to stdout. */ | ||||
|       return map_error_to_curl(ssl_fcn_return); | ||||
|     } | ||||
|     usleep(10000); | ||||
|   } | ||||
|   infof (conn->data, "handshake completed successfully\n"); | ||||
|  | ||||
|   conn_step = connect_finish(conn, sockindex); | ||||
|   if(conn_step != CURLE_OK) { | ||||
|     Curl_axtls_close(conn, sockindex); | ||||
|     return conn_step; | ||||
|   } | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* return number of sent (non-SSL) bytes */ | ||||
| static ssize_t axtls_send(struct connectdata *conn, | ||||
| @@ -407,7 +520,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex) | ||||
|   struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | ||||
|  | ||||
|   infof(conn->data, "  Curl_axtls_close\n"); | ||||
|   if(connssl->ssl) { | ||||
|  | ||||
|     /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl); | ||||
|        axTLS compat layer does nothing for SSL_shutdown */ | ||||
|  | ||||
| @@ -415,13 +528,7 @@ void Curl_axtls_close(struct connectdata *conn, int sockindex) | ||||
|        equivalent.  ssl_free and ssl_ctx_free close things. | ||||
|        SSL_set_connect_state(connssl->handle); */ | ||||
|  | ||||
|     ssl_free (connssl->ssl); | ||||
|     connssl->ssl = NULL; | ||||
|   } | ||||
|   if(connssl->ssl_ctx) { | ||||
|     ssl_ctx_free (connssl->ssl_ctx); | ||||
|     connssl->ssl_ctx = NULL; | ||||
|   } | ||||
|   free_ssl_structs(connssl); | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -436,8 +543,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) | ||||
|   int retval = 0; | ||||
|   struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   char buf[120]; /* We will use this for the OpenSSL error buffer, so it has | ||||
|                     to be at least 120 bytes long. */ | ||||
|   uint8_t *buf; | ||||
|   ssize_t nread; | ||||
|  | ||||
|   infof(conn->data, "  Curl_axtls_shutdown\n"); | ||||
| @@ -457,9 +563,10 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) | ||||
|                                  CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); | ||||
|     if(what > 0) { | ||||
|       /* Something to read, let's do it and hope that it is the close | ||||
|          notify alert from the server */ | ||||
|       nread = (ssize_t)SSL_read(conn->ssl[sockindex].ssl, buf, | ||||
|                                 sizeof(buf)); | ||||
|          notify alert from the server.  buf is managed internally by | ||||
|          axTLS and will be released upon calling ssl_free via | ||||
|          free_ssl_structs. */ | ||||
|       nread = (ssize_t)ssl_read(connssl->ssl, &buf); | ||||
|  | ||||
|       if(nread < SSL_OK) { | ||||
|         failf(data, "close notify alert not received during shutdown"); | ||||
| @@ -476,8 +583,7 @@ int Curl_axtls_shutdown(struct connectdata *conn, int sockindex) | ||||
|       retval = -1; | ||||
|     } | ||||
|  | ||||
|     ssl_free (connssl->ssl); | ||||
|     connssl->ssl = NULL; | ||||
|     free_ssl_structs(connssl); | ||||
|   } | ||||
|   return retval; | ||||
| } | ||||
| @@ -490,26 +596,36 @@ static ssize_t axtls_recv(struct connectdata *conn, /* connection data */ | ||||
| { | ||||
|   struct ssl_connect_data *connssl = &conn->ssl[num]; | ||||
|   ssize_t ret = 0; | ||||
|   uint8_t *read_buf; | ||||
|  | ||||
|   infof(conn->data, "  axtls_recv\n"); | ||||
|  | ||||
|   *err = CURLE_OK; | ||||
|   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 ) { | ||||
|     ret = ssl_read(connssl->ssl, &read_buf); | ||||
|     if(ret > SSL_OK) { | ||||
|       /* ssl_read returns SSL_OK if there is more data to read, so if it is | ||||
|          larger, then all data has been read already.  */ | ||||
|       memcpy(buf, read_buf, | ||||
|              (size_t)ret > buffersize ? buffersize : (size_t)ret); | ||||
|     } | ||||
|     else if(ret == SSL_OK) { | ||||
|       /* more data to be read, signal caller to call again */ | ||||
|       *err = CURLE_AGAIN; | ||||
|       ret = -1; | ||||
|     } | ||||
|     else if(ret == -3) { | ||||
|       /* With patched axTLS, SSL_CLOSE_NOTIFY=-3.  Hard-coding until axTLS | ||||
|          team approves proposed fix. */ | ||||
|       Curl_axtls_close(conn, num); | ||||
|     } | ||||
|     else if(ret < 0) { | ||||
|       failf(conn->data, "axTLS recv error (%d)", (int)ret); | ||||
|     else { | ||||
|       failf(conn->data, "axTLS recv error (%d)", ret); | ||||
|       *err = map_error_to_curl(ret); | ||||
|       return -1; | ||||
|       ret = -1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   *err = CURLE_OK; | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -30,6 +30,10 @@ | ||||
| int Curl_axtls_init(void); | ||||
| int Curl_axtls_cleanup(void); | ||||
| CURLcode Curl_axtls_connect(struct connectdata *conn, int sockindex); | ||||
| CURLcode Curl_axtls_connect_nonblocking( | ||||
|     struct connectdata *conn, | ||||
|     int sockindex, | ||||
|     bool *done); | ||||
|  | ||||
| /* tell axTLS to close down all open information regarding connections (and | ||||
|    thus session ID caching etc) */ | ||||
| @@ -47,6 +51,7 @@ int Curl_axtls_check_cxn(struct connectdata *conn); | ||||
| #define curlssl_init Curl_axtls_init | ||||
| #define curlssl_cleanup Curl_axtls_cleanup | ||||
| #define curlssl_connect Curl_axtls_connect | ||||
| #define curlssl_connect_nonblocking Curl_axtls_connect_nonblocking | ||||
| #define curlssl_session_free(x)  Curl_axtls_session_free(x) | ||||
| #define curlssl_close_all Curl_axtls_close_all | ||||
| #define curlssl_close Curl_axtls_close | ||||
|   | ||||
| @@ -277,21 +277,27 @@ | ||||
| /* Define if you have the <stdlib.h> header file. */ | ||||
| #define HAVE_STDLIB_H | ||||
|  | ||||
|  | ||||
| /* The following define is needed on OS400 to enable strcmpi(), stricmp() and | ||||
|    strdup(). */ | ||||
| #define __cplusplus__strings__ | ||||
|  | ||||
| /* Define if you have the `strcasecmp' function. */ | ||||
| #undef HAVE_STRCASECMP | ||||
|  | ||||
| /* Define if you have the `strcmpi' function. */ | ||||
| #undef HAVE_STRCMPI | ||||
| #define HAVE_STRCMPI | ||||
|  | ||||
| /* Define if you have the `stricmp' function. */ | ||||
| #define HAVE_STRICMP | ||||
|  | ||||
| /* Define if you have the `strdup' function. */ | ||||
| #undef HAVE_STRDUP | ||||
| #define HAVE_STRDUP | ||||
|  | ||||
|  | ||||
| /* Define if you have the `strftime' function. */ | ||||
| #define HAVE_STRFTIME | ||||
|  | ||||
| /* Define if you have the `stricmp' function. */ | ||||
| #undef HAVE_STRICMP | ||||
|  | ||||
| /* Define if you have the <strings.h> header file. */ | ||||
| #define HAVE_STRINGS_H | ||||
|  | ||||
| @@ -525,6 +531,9 @@ | ||||
| /* Define to use the QsoSSL package. */ | ||||
| #define USE_QSOSSL | ||||
|  | ||||
| /* Define to use the GSKit package. */ | ||||
| #undef USE_GSKIT | ||||
|  | ||||
| /* Use the system keyring as the default CA bundle. */ | ||||
| #define CURL_CA_BUNDLE  "/QIBM/UserData/ICSS/Cert/Server/DEFAULT.KDB" | ||||
|  | ||||
|   | ||||
| @@ -38,8 +38,6 @@ | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| #define CONNECTION_HASH_SIZE 97 | ||||
|  | ||||
| static void free_bundle_hash_entry(void *freethis) | ||||
| { | ||||
|   struct connectbundle *b = (struct connectbundle *) freethis; | ||||
| @@ -47,7 +45,7 @@ static void free_bundle_hash_entry(void *freethis) | ||||
|   Curl_bundle_destroy(b); | ||||
| } | ||||
|  | ||||
| struct conncache *Curl_conncache_init(void) | ||||
| struct conncache *Curl_conncache_init(int size) | ||||
| { | ||||
|   struct conncache *connc; | ||||
|  | ||||
| @@ -55,7 +53,7 @@ struct conncache *Curl_conncache_init(void) | ||||
|   if(!connc) | ||||
|     return NULL; | ||||
|  | ||||
|   connc->hash = Curl_hash_alloc(CONNECTION_HASH_SIZE, Curl_hash_str, | ||||
|   connc->hash = Curl_hash_alloc(size, Curl_hash_str, | ||||
|                                 Curl_str_key_compare, free_bundle_hash_entry); | ||||
|  | ||||
|   if(!connc->hash) { | ||||
|   | ||||
| @@ -27,7 +27,7 @@ struct conncache { | ||||
|   size_t num_connections; | ||||
| }; | ||||
|  | ||||
| struct conncache *Curl_conncache_init(void); | ||||
| struct conncache *Curl_conncache_init(int size); | ||||
|  | ||||
| void Curl_conncache_destroy(struct conncache *connc); | ||||
|  | ||||
|   | ||||
| @@ -413,23 +413,22 @@ static CURLcode bindlocal(struct connectdata *conn, | ||||
|       if(af == AF_INET6) { | ||||
| #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID | ||||
|         char *scope_ptr = strchr(myhost, '%'); | ||||
|  | ||||
|         if(scope_ptr) *(scope_ptr++) = 0; | ||||
|         if(scope_ptr) | ||||
|           *(scope_ptr++) = 0; | ||||
| #endif | ||||
|         if(Curl_inet_pton(AF_INET6, myhost, &si6->sin6_addr) > 0) { | ||||
|           si6->sin6_family = AF_INET6; | ||||
|           si6->sin6_port = htons(port); | ||||
| #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID | ||||
|           if(scope_ptr) { | ||||
|             /* The "myhost" string either comes from Curl_if2ip or | ||||
|                from Curl_printable_address. The latter returns only | ||||
|                numeric scope IDs and the former returns none at all. | ||||
|                So the scope ID, if present, is known to be numeric */ | ||||
|           if(scope_ptr) | ||||
|             /* The "myhost" string either comes from Curl_if2ip or from | ||||
|                Curl_printable_address. The latter returns only numeric scope | ||||
|                IDs and the former returns none at all.  So the scope ID, if | ||||
|                present, is known to be numeric */ | ||||
|             si6->sin6_scope_id = atoi(scope_ptr); | ||||
|           } | ||||
|         } | ||||
| #endif | ||||
|           sizeof_sa = sizeof(struct sockaddr_in6); | ||||
|         } | ||||
|         sizeof_sa = sizeof(struct sockaddr_in6); | ||||
|       } | ||||
|       else | ||||
| #endif | ||||
| @@ -1145,7 +1144,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */ | ||||
|  | ||||
|   if(sockfd == CURL_SOCKET_BAD) { | ||||
|     /* no good connect was made */ | ||||
|     failf(data, "couldn't connect to %s at %s:%d", | ||||
|     failf(data, "couldn't connect to %s at %s:%ld", | ||||
|           conn->bits.proxy?"proxy":"host", | ||||
|           conn->bits.proxy?conn->proxy.name:conn->host.name, conn->port); | ||||
|     return CURLE_COULDNT_CONNECT; | ||||
| @@ -1240,7 +1239,7 @@ curl_socket_t Curl_getconnectinfo(struct SessionHandle *data, | ||||
|  * 'conn' can be NULL, beware! | ||||
|  */ | ||||
| int Curl_closesocket(struct connectdata *conn, | ||||
|                      curl_socket_t sock) | ||||
|                       curl_socket_t sock) | ||||
| { | ||||
|   if(conn && conn->fclosesocket) { | ||||
|     if((sock == conn->sock[SECONDARYSOCKET]) && | ||||
| @@ -1252,7 +1251,13 @@ int Curl_closesocket(struct connectdata *conn, | ||||
|     else | ||||
|       return conn->fclosesocket(conn->closesocket_client, sock); | ||||
|   } | ||||
|   return sclose(sock); | ||||
|   sclose(sock); | ||||
|  | ||||
|   if(conn) | ||||
|     /* tell the multi-socket code about this */ | ||||
|     Curl_multi_closed(conn, sock); | ||||
|  | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|   | ||||
							
								
								
									
										234
									
								
								lib/cookie.c
									
									
									
									
									
								
							
							
						
						
									
										234
									
								
								lib/cookie.c
									
									
									
									
									
								
							| @@ -89,6 +89,7 @@ Example set of cookies: | ||||
| #include "strequal.h" | ||||
| #include "strtok.h" | ||||
| #include "sendf.h" | ||||
| #include "slist.h" | ||||
| #include "curl_memory.h" | ||||
| #include "share.h" | ||||
| #include "strtoofft.h" | ||||
| @@ -106,6 +107,8 @@ static void freecookie(struct Cookie *co) | ||||
|     free(co->domain); | ||||
|   if(co->path) | ||||
|     free(co->path); | ||||
|   if(co->spath) | ||||
|     free(co->spath); | ||||
|   if(co->name) | ||||
|     free(co->name); | ||||
|   if(co->value) | ||||
| @@ -143,6 +146,116 @@ static bool tailmatch(const char *cooke_domain, const char *hostname) | ||||
|   return FALSE; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * matching cookie path and url path | ||||
|  * RFC6265 5.1.4 Paths and Path-Match | ||||
|  */ | ||||
| static bool pathmatch(const char* cookie_path, const char* request_uri) | ||||
| { | ||||
|   size_t cookie_path_len; | ||||
|   size_t uri_path_len; | ||||
|   char* uri_path = NULL; | ||||
|   char* pos; | ||||
|   bool ret = FALSE; | ||||
|  | ||||
|   /* cookie_path must not have last '/' separator. ex: /sample */ | ||||
|   cookie_path_len = strlen(cookie_path); | ||||
|   if(1 == cookie_path_len) { | ||||
|     /* cookie_path must be '/' */ | ||||
|     return TRUE; | ||||
|   } | ||||
|  | ||||
|   uri_path = strdup(request_uri); | ||||
|   if(!uri_path) | ||||
|     return FALSE; | ||||
|   pos = strchr(uri_path, '?'); | ||||
|   if(pos) | ||||
|     *pos = 0x0; | ||||
|  | ||||
|   /* #-fragments are already cut off! */ | ||||
|   if(0 == strlen(uri_path) || uri_path[0] != '/') { | ||||
|     free(uri_path); | ||||
|     uri_path = strdup("/"); | ||||
|     if(!uri_path) | ||||
|       return FALSE; | ||||
|   } | ||||
|  | ||||
|   /* here, RFC6265 5.1.4 says | ||||
|      4. Output the characters of the uri-path from the first character up | ||||
|         to, but not including, the right-most %x2F ("/"). | ||||
|      but URL path /hoge?fuga=xxx means /hoge/index.cgi?fuga=xxx in some site | ||||
|      without redirect. | ||||
|      Ignore this algorithm because /hoge is uri path for this case | ||||
|      (uri path is not /). | ||||
|    */ | ||||
|  | ||||
|   uri_path_len = strlen(uri_path); | ||||
|  | ||||
|   if(uri_path_len < cookie_path_len) { | ||||
|     ret = FALSE; | ||||
|     goto pathmatched; | ||||
|   } | ||||
|  | ||||
|   /* not using checkprefix() because matching should be case-sensitive */ | ||||
|   if(strncmp(cookie_path, uri_path, cookie_path_len)) { | ||||
|     ret = FALSE; | ||||
|     goto pathmatched; | ||||
|   } | ||||
|  | ||||
|   /* The cookie-path and the uri-path are identical. */ | ||||
|   if(cookie_path_len == uri_path_len) { | ||||
|     ret = TRUE; | ||||
|     goto pathmatched; | ||||
|   } | ||||
|  | ||||
|   /* here, cookie_path_len < url_path_len */ | ||||
|   if(uri_path[cookie_path_len] == '/') { | ||||
|     ret = TRUE; | ||||
|     goto pathmatched; | ||||
|   } | ||||
|  | ||||
|   ret = FALSE; | ||||
|  | ||||
| pathmatched: | ||||
|   free(uri_path); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * cookie path sanitize | ||||
|  */ | ||||
| static char *sanitize_cookie_path(const char *cookie_path) | ||||
| { | ||||
|   size_t len; | ||||
|   char *new_path = strdup(cookie_path); | ||||
|   if(!new_path) | ||||
|     return NULL; | ||||
|  | ||||
|   /* some stupid site sends path attribute with '"'. */ | ||||
|   if(new_path[0] == '\"') { | ||||
|     memmove((void *)new_path, (const void *)(new_path + 1), strlen(new_path)); | ||||
|   } | ||||
|   if(new_path[strlen(new_path) - 1] == '\"') { | ||||
|     new_path[strlen(new_path) - 1] = 0x0; | ||||
|   } | ||||
|  | ||||
|   /* RFC6265 5.2.4 The Path Attribute */ | ||||
|   if(new_path[0] != '/') { | ||||
|     /* Let cookie-path be the default-path. */ | ||||
|     free(new_path); | ||||
|     new_path = strdup("/"); | ||||
|     return new_path; | ||||
|   } | ||||
|  | ||||
|   /* convert /hoge/ to /hoge */ | ||||
|   len = strlen(new_path); | ||||
|   if(1 < len && new_path[len - 1] == '/') { | ||||
|     new_path[len - 1] = 0x0; | ||||
|   } | ||||
|  | ||||
|   return new_path; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Load cookies from all given cookie files (CURLOPT_COOKIEFILE). | ||||
|  */ | ||||
| @@ -184,6 +297,9 @@ static void strstore(char **str, const char *newstr) | ||||
|  * | ||||
|  * Add a single cookie line to the cookie keeping object. | ||||
|  * | ||||
|  * Be aware that sometimes we get an IP-only host name, and that might also be | ||||
|  * a numerical IPv6 address. | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
|  | ||||
| struct Cookie * | ||||
| @@ -288,72 +404,39 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|             badcookie = TRUE; /* out of memory bad */ | ||||
|             break; | ||||
|           } | ||||
|           co->spath = sanitize_cookie_path(co->path); | ||||
|           if(!co->spath) { | ||||
|             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. */ | ||||
|           /* 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++; | ||||
|             whatptr++; /* ignore preceding dot */ | ||||
|  | ||||
|           do { | ||||
|             nextptr = strchr(domptr, '.'); | ||||
|             if(nextptr) { | ||||
|               if(domptr != nextptr) | ||||
|                 dotcount++; | ||||
|               domptr = nextptr+1; | ||||
|           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); | ||||
|             } | ||||
|             /* 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)) { | ||||
| @@ -461,6 +544,9 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|         if(co->path) { | ||||
|           memcpy(co->path, path, pathlen); | ||||
|           co->path[pathlen]=0; /* zero terminate */ | ||||
|           co->spath = sanitize_cookie_path(co->path); | ||||
|           if(!co->spath) | ||||
|             badcookie = TRUE; /* out of memory bad */ | ||||
|         } | ||||
|         else | ||||
|           badcookie = TRUE; | ||||
| @@ -512,12 +598,6 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|  | ||||
|     firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */ | ||||
|  | ||||
|     /* Here's a quick check to eliminate normal HTTP-headers from this */ | ||||
|     if(!firstptr || strchr(firstptr, ':')) { | ||||
|       free(co); | ||||
|       return NULL; | ||||
|     } | ||||
|  | ||||
|     /* Now loop through the fields and init the struct we already have | ||||
|        allocated */ | ||||
|     for(ptr=firstptr, fields=0; ptr && !badcookie; | ||||
| @@ -552,12 +632,21 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|           co->path = strdup(ptr); | ||||
|           if(!co->path) | ||||
|             badcookie = TRUE; | ||||
|           else { | ||||
|             co->spath = sanitize_cookie_path(co->path); | ||||
|             if(!co->spath) { | ||||
|               badcookie = TRUE; /* out of memory bad */ | ||||
|             } | ||||
|           } | ||||
|           break; | ||||
|         } | ||||
|         /* this doesn't look like a path, make one up! */ | ||||
|         co->path = strdup("/"); | ||||
|         if(!co->path) | ||||
|           badcookie = TRUE; | ||||
|         co->spath = strdup("/"); | ||||
|         if(!co->spath) | ||||
|           badcookie = TRUE; | ||||
|         fields++; /* add a field and fall down to secure */ | ||||
|         /* FALLTHROUGH */ | ||||
|       case 3: | ||||
| @@ -628,14 +717,14 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|       if(replace_old) { | ||||
|         /* the domains were identical */ | ||||
|  | ||||
|         if(clist->path && co->path) { | ||||
|           if(Curl_raw_equal(clist->path, co->path)) { | ||||
|         if(clist->spath && co->spath) { | ||||
|           if(Curl_raw_equal(clist->spath, co->spath)) { | ||||
|             replace_old = TRUE; | ||||
|           } | ||||
|           else | ||||
|             replace_old = FALSE; | ||||
|         } | ||||
|         else if(!clist->path && !co->path) | ||||
|         else if(!clist->spath && !co->spath) | ||||
|           replace_old = TRUE; | ||||
|         else | ||||
|           replace_old = FALSE; | ||||
| @@ -664,6 +753,8 @@ Curl_cookie_add(struct SessionHandle *data, | ||||
|           free(clist->domain); | ||||
|         if(clist->path) | ||||
|           free(clist->path); | ||||
|         if(clist->spath) | ||||
|           free(clist->spath); | ||||
|         if(clist->expirestr) | ||||
|           free(clist->expirestr); | ||||
|  | ||||
| @@ -858,10 +949,7 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c, | ||||
|  | ||||
|         /* now check the left part of the path with the cookies path | ||||
|            requirement */ | ||||
|         if(!co->path || | ||||
|            /* not using checkprefix() because matching should be | ||||
|               case-sensitive */ | ||||
|            !strncmp(co->path, path, strlen(co->path)) ) { | ||||
|         if(!co->spath || pathmatch(co->spath, path) ) { | ||||
|  | ||||
|           /* and now, we know this is a match and we should create an | ||||
|              entry for the return-linked-list */ | ||||
| @@ -1145,9 +1233,9 @@ struct curl_slist *Curl_cookie_list(struct SessionHandle *data) | ||||
|       curl_slist_free_all(list); | ||||
|       return NULL; | ||||
|     } | ||||
|     beg = curl_slist_append(list, line); | ||||
|     free(line); | ||||
|     beg = Curl_slist_append_nodup(list, line); | ||||
|     if(!beg) { | ||||
|       free(line); | ||||
|       curl_slist_free_all(list); | ||||
|       return NULL; | ||||
|     } | ||||
|   | ||||
| @@ -29,7 +29,8 @@ struct Cookie { | ||||
|   struct Cookie *next; /* next in the chain */ | ||||
|   char *name;        /* <this> = value */ | ||||
|   char *value;       /* name = <this> */ | ||||
|   char *path;         /* path = <this> */ | ||||
|   char *path;         /* path = <this> which is in Set-Cookie: */ | ||||
|   char *spath;        /* sanitized cookie path */ | ||||
|   char *domain;      /* domain = <this> */ | ||||
|   curl_off_t expires;  /* expires = <this> */ | ||||
|   char *expirestr;   /* the plain text version */ | ||||
|   | ||||
| @@ -38,9 +38,54 @@ | ||||
| #include <Security/SecureTransport.h> | ||||
| #include <CoreFoundation/CoreFoundation.h> | ||||
| #include <CommonCrypto/CommonDigest.h> | ||||
|  | ||||
| /* The Security framework has changed greatly between iOS and different OS X | ||||
|    versions, and we will try to support as many of them as we can (back to | ||||
|    Leopard and iOS 5) by using macros and weak-linking. | ||||
|  | ||||
|    IMPORTANT: If TLS 1.1 and 1.2 support are important for you on OS X, then | ||||
|    you must build this project against the 10.8 SDK or later. */ | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
|  | ||||
| #if MAC_OS_X_VERSION_MAX_ALLOWED < 1050 | ||||
| #error "The darwinssl back-end requires Leopard or later." | ||||
| #endif /* MAC_OS_X_VERSION_MAX_ALLOWED < 1050 */ | ||||
|  | ||||
| #define CURL_BUILD_IOS 0 | ||||
| #define CURL_BUILD_MAC 1 | ||||
| /* This is the maximum API level we are allowed to use when building: */ | ||||
| #define CURL_BUILD_MAC_10_5 MAC_OS_X_VERSION_MAX_ALLOWED >= 1050 | ||||
| #define CURL_BUILD_MAC_10_6 MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 | ||||
| #define CURL_BUILD_MAC_10_7 MAC_OS_X_VERSION_MAX_ALLOWED >= 1070 | ||||
| #define CURL_BUILD_MAC_10_8 MAC_OS_X_VERSION_MAX_ALLOWED >= 1080 | ||||
| /* These macros mean "the following code is present to allow runtime backward | ||||
|    compatibility with at least this cat or earlier": | ||||
|    (You set this at build-time by setting the MACOSX_DEPLOYMENT_TARGET | ||||
|    environmental variable.) */ | ||||
| #define CURL_SUPPORT_MAC_10_5 MAC_OS_X_VERSION_MIN_REQUIRED <= 1050 | ||||
| #define CURL_SUPPORT_MAC_10_6 MAC_OS_X_VERSION_MIN_REQUIRED <= 1060 | ||||
| #define CURL_SUPPORT_MAC_10_7 MAC_OS_X_VERSION_MIN_REQUIRED <= 1070 | ||||
| #define CURL_SUPPORT_MAC_10_8 MAC_OS_X_VERSION_MIN_REQUIRED <= 1080 | ||||
|  | ||||
| #elif TARGET_OS_EMBEDDED || TARGET_OS_IPHONE | ||||
| #define CURL_BUILD_IOS 1 | ||||
| #define CURL_BUILD_MAC 0 | ||||
| #define CURL_BUILD_MAC_10_5 0 | ||||
| #define CURL_BUILD_MAC_10_6 0 | ||||
| #define CURL_BUILD_MAC_10_7 0 | ||||
| #define CURL_BUILD_MAC_10_8 0 | ||||
| #define CURL_SUPPORT_MAC_10_5 0 | ||||
| #define CURL_SUPPORT_MAC_10_6 0 | ||||
| #define CURL_SUPPORT_MAC_10_7 0 | ||||
| #define CURL_SUPPORT_MAC_10_8 0 | ||||
|  | ||||
| #else | ||||
| #error "The darwinssl back-end requires iOS or OS X." | ||||
| #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
|  | ||||
| #if CURL_BUILD_MAC | ||||
| #include <sys/sysctl.h> | ||||
| #endif | ||||
| #endif /* CURL_BUILD_MAC */ | ||||
|  | ||||
| #include "urldata.h" | ||||
| #include "sendf.h" | ||||
| @@ -61,16 +106,6 @@ | ||||
| #define ioErr -36 | ||||
| #define paramErr -50 | ||||
|  | ||||
| /* In Mountain Lion and iOS 5, Apple made some changes to the API. They | ||||
|    added TLS 1.1 and 1.2 support, and deprecated and replaced some | ||||
|    functions. You need to build against the Mountain Lion or iOS 5 SDK | ||||
|    or later to get TLS 1.1 or 1.2 support working in cURL. We'll weak-link | ||||
|    to the newer functions and use them if present in the user's OS. | ||||
|  | ||||
|    Builders: If you want TLS 1.1 and 1.2 but still want to retain support | ||||
|    for older cats, don't forget to set the MACOSX_DEPLOYMENT_TARGET | ||||
|    environmental variable prior to building cURL. */ | ||||
|  | ||||
| /* The following two functions were ripped from Apple sample code, | ||||
|  * with some modifications: */ | ||||
| static OSStatus SocketRead(SSLConnectionRef connection, | ||||
| @@ -361,7 +396,7 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { | ||||
|     case TLS_DH_anon_WITH_AES_256_CBC_SHA: | ||||
|       return "TLS_DH_anon_WITH_AES_256_CBC_SHA"; | ||||
|       break; | ||||
| #if defined(__MAC_10_6) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS | ||||
|     /* TLS 1.0 with ECDSA (RFC 4492) */ | ||||
|     case TLS_ECDH_ECDSA_WITH_NULL_SHA: | ||||
|       return "TLS_ECDH_ECDSA_WITH_NULL_SHA"; | ||||
| @@ -438,8 +473,8 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { | ||||
|     case TLS_ECDH_anon_WITH_AES_256_CBC_SHA: | ||||
|       return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA"; | ||||
|       break; | ||||
| #endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ | ||||
| #if defined(__MAC_10_8) || defined(__IPHONE_5_0) | ||||
| #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ | ||||
| #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS | ||||
|     /* TLS 1.2 (RFC 5246) */ | ||||
|     case TLS_RSA_WITH_NULL_MD5: | ||||
|       return "TLS_RSA_WITH_NULL_MD5"; | ||||
| @@ -624,12 +659,12 @@ CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) { | ||||
|     case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA: | ||||
|       return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA"; | ||||
|       break; | ||||
| #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ | ||||
|   } | ||||
|   return "TLS_NULL_WITH_NULL_NULL"; | ||||
| } | ||||
|  | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_BUILD_MAC | ||||
| CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) | ||||
| { | ||||
|   int mib[2]; | ||||
| @@ -658,7 +693,7 @@ CF_INLINE void GetDarwinVersionNumber(int *major, int *minor) | ||||
|   *minor = atoi(os_version_minor); | ||||
|   free(os_version); | ||||
| } | ||||
| #endif | ||||
| #endif /* CURL_BUILD_MAC */ | ||||
|  | ||||
| /* Apple provides a myriad of ways of getting information about a certificate | ||||
|    into a string. Some aren't available under iOS or newer cats. So here's | ||||
| @@ -668,29 +703,122 @@ CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert) | ||||
| { | ||||
|   CFStringRef server_cert_summary = CFSTR("(null)"); | ||||
|  | ||||
| #if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) | ||||
| #if CURL_BUILD_IOS | ||||
|   /* iOS: There's only one way to do this. */ | ||||
|   server_cert_summary = SecCertificateCopySubjectSummary(cert); | ||||
| #else | ||||
| #if defined(__MAC_10_7) | ||||
| #if CURL_BUILD_MAC_10_7 | ||||
|   /* Lion & later: Get the long description if we can. */ | ||||
|   if(SecCertificateCopyLongDescription != NULL) | ||||
|     server_cert_summary = | ||||
|       SecCertificateCopyLongDescription(NULL, cert, NULL); | ||||
|   else | ||||
| #endif /* defined(__MAC_10_7) */ | ||||
| #if defined(__MAC_10_6) | ||||
| #endif /* CURL_BUILD_MAC_10_7 */ | ||||
| #if CURL_BUILD_MAC_10_6 | ||||
|   /* Snow Leopard: Get the certificate summary. */ | ||||
|   if(SecCertificateCopySubjectSummary != NULL) | ||||
|     server_cert_summary = SecCertificateCopySubjectSummary(cert); | ||||
|   else | ||||
| #endif /* defined(__MAC_10_6) */ | ||||
| #endif /* CURL_BUILD_MAC_10_6 */ | ||||
|   /* Leopard is as far back as we go... */ | ||||
|   (void)SecCertificateCopyCommonName(cert, &server_cert_summary); | ||||
| #endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */ | ||||
| #endif /* CURL_BUILD_IOS */ | ||||
|   return server_cert_summary; | ||||
| } | ||||
|  | ||||
| #if CURL_SUPPORT_MAC_10_7 | ||||
| /* The SecKeychainSearch API was deprecated in Lion, and using it will raise | ||||
|    deprecation warnings, so let's not compile this unless it's necessary: */ | ||||
| static OSStatus CopyIdentityWithLabelOldSchool(char *label, | ||||
|                                                SecIdentityRef *out_c_a_k) | ||||
| { | ||||
|   OSStatus status = errSecItemNotFound; | ||||
|   SecKeychainAttributeList attr_list; | ||||
|   SecKeychainAttribute attr; | ||||
|   SecKeychainSearchRef search = NULL; | ||||
|   SecCertificateRef cert = NULL; | ||||
|  | ||||
|   /* Set up the attribute list: */ | ||||
|   attr_list.count = 1L; | ||||
|   attr_list.attr = &attr; | ||||
|  | ||||
|   /* Set up our lone search criterion: */ | ||||
|   attr.tag = kSecLabelItemAttr; | ||||
|   attr.data = label; | ||||
|   attr.length = (UInt32)strlen(label); | ||||
|  | ||||
|   /* Start searching: */ | ||||
|   status = SecKeychainSearchCreateFromAttributes(NULL, | ||||
|                                                  kSecCertificateItemClass, | ||||
|                                                  &attr_list, | ||||
|                                                  &search); | ||||
|   if(status == noErr) { | ||||
|     status = SecKeychainSearchCopyNext(search, | ||||
|                                        (SecKeychainItemRef *)&cert); | ||||
|     if(status == noErr && cert) { | ||||
|       /* If we found a certificate, does it have a private key? */ | ||||
|       status = SecIdentityCreateWithCertificate(NULL, cert, out_c_a_k); | ||||
|       CFRelease(cert); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if(search) | ||||
|     CFRelease(search); | ||||
|   return status; | ||||
| } | ||||
| #endif /* CURL_SUPPORT_MAC_10_7 */ | ||||
|  | ||||
| static OSStatus CopyIdentityWithLabel(char *label, | ||||
|                                       SecIdentityRef *out_cert_and_key) | ||||
| { | ||||
|   OSStatus status = errSecItemNotFound; | ||||
|  | ||||
| #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS | ||||
|   /* SecItemCopyMatching() was introduced in iOS and Snow Leopard. | ||||
|      kSecClassIdentity was introduced in Lion. If both exist, let's use them | ||||
|      to find the certificate. */ | ||||
|   if(SecItemCopyMatching != NULL && kSecClassIdentity != NULL) { | ||||
|     CFTypeRef keys[4]; | ||||
|     CFTypeRef values[4]; | ||||
|     CFDictionaryRef query_dict; | ||||
|     CFStringRef label_cf = CFStringCreateWithCString(NULL, label, | ||||
|       kCFStringEncodingUTF8); | ||||
|  | ||||
|     /* Set up our search criteria and expected results: */ | ||||
|     values[0] = kSecClassIdentity; /* we want a certificate and a key */ | ||||
|     keys[0] = kSecClass; | ||||
|     values[1] = kCFBooleanTrue;    /* we want a reference */ | ||||
|     keys[1] = kSecReturnRef; | ||||
|     values[2] = kSecMatchLimitOne; /* one is enough, thanks */ | ||||
|     keys[2] = kSecMatchLimit; | ||||
|     /* identity searches need a SecPolicyRef in order to work */ | ||||
|     values[3] = SecPolicyCreateSSL(false, label_cf); | ||||
|     keys[3] = kSecMatchPolicy; | ||||
|     query_dict = CFDictionaryCreate(NULL, (const void **)keys, | ||||
|                                    (const void **)values, 4L, | ||||
|                                    &kCFCopyStringDictionaryKeyCallBacks, | ||||
|                                    &kCFTypeDictionaryValueCallBacks); | ||||
|     CFRelease(values[3]); | ||||
|     CFRelease(label_cf); | ||||
|  | ||||
|     /* Do we have a match? */ | ||||
|     status = SecItemCopyMatching(query_dict, (CFTypeRef *)out_cert_and_key); | ||||
|     CFRelease(query_dict); | ||||
|   } | ||||
|   else { | ||||
| #if CURL_SUPPORT_MAC_10_7 | ||||
|     /* On Leopard and Snow Leopard, fall back to SecKeychainSearch. */ | ||||
|     status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); | ||||
| #endif /* CURL_SUPPORT_MAC_10_7 */ | ||||
|   } | ||||
| #elif CURL_SUPPORT_MAC_10_7 | ||||
|   /* For developers building on older cats, we have no choice but to fall back | ||||
|      to SecKeychainSearch. */ | ||||
|   status = CopyIdentityWithLabelOldSchool(label, out_cert_and_key); | ||||
| #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ | ||||
|   return status; | ||||
| } | ||||
|  | ||||
| static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|                                         int sockindex) | ||||
| { | ||||
| @@ -701,17 +829,19 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|   struct in6_addr addr; | ||||
| #else | ||||
|   struct in_addr addr; | ||||
| #endif | ||||
| #endif /* ENABLE_IPV6 */ | ||||
|   size_t all_ciphers_count = 0UL, allowed_ciphers_count = 0UL, i; | ||||
|   SSLCipherSuite *all_ciphers = NULL, *allowed_ciphers = NULL; | ||||
|   char *ssl_sessionid; | ||||
|   size_t ssl_sessionid_len; | ||||
|   OSStatus err = noErr; | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_BUILD_MAC | ||||
|   int darwinver_maj = 0, darwinver_min = 0; | ||||
|  | ||||
|   GetDarwinVersionNumber(&darwinver_maj, &darwinver_min); | ||||
| #endif | ||||
| #endif /* CURL_BUILD_MAC */ | ||||
|  | ||||
| #if defined(__MAC_10_8) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS | ||||
|   if(SSLCreateContext != NULL) {  /* use the newer API if avaialble */ | ||||
|     if(connssl->ssl_ctx) | ||||
|       CFRelease(connssl->ssl_ctx); | ||||
| @@ -723,7 +853,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|   } | ||||
|   else { | ||||
|   /* The old ST API does not exist under iOS, so don't compile it: */ | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_SUPPORT_MAC_10_8 | ||||
|     if(connssl->ssl_ctx) | ||||
|       (void)SSLDisposeContext(connssl->ssl_ctx); | ||||
|     err = SSLNewContext(false, &(connssl->ssl_ctx)); | ||||
| @@ -731,7 +861,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|       failf(data, "SSL: couldn't create a context: OSStatus %d", err); | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     } | ||||
| #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
| #endif /* CURL_SUPPORT_MAC_10_8 */ | ||||
|   } | ||||
| #else | ||||
|   if(connssl->ssl_ctx) | ||||
| @@ -741,11 +871,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|     failf(data, "SSL: couldn't create a context: OSStatus %d", err); | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   } | ||||
| #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ | ||||
|   connssl->ssl_write_buffered_length = 0UL; /* reset buffered write length */ | ||||
|  | ||||
|   /* check to see if we've been told to use an explicit SSL/TLS version */ | ||||
| #if defined(__MAC_10_8) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS | ||||
|   if(SSLSetProtocolVersionMax != NULL) { | ||||
|     switch(data->set.ssl.version) { | ||||
|       case CURL_SSLVERSION_DEFAULT: default: | ||||
| @@ -761,12 +891,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|         (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3); | ||||
|         break; | ||||
|       case CURL_SSLVERSION_SSLv2: | ||||
|         (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); | ||||
|         err = SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol2); | ||||
|         if(err != noErr) { | ||||
|           failf(data, "Your version of the OS does not support SSLv2"); | ||||
|           return CURLE_SSL_CONNECT_ERROR; | ||||
|         } | ||||
|         (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol2); | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_SUPPORT_MAC_10_8 | ||||
|     (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
|                                        kSSLProtocolAll, | ||||
|                                        false); | ||||
| @@ -802,12 +936,16 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|                                            true); | ||||
|         break; | ||||
|       case CURL_SSLVERSION_SSLv2: | ||||
|         (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
|         err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
|                                            kSSLProtocol2, | ||||
|                                            true); | ||||
|         if(err != noErr) { | ||||
|           failf(data, "Your version of the OS does not support SSLv2"); | ||||
|           return CURLE_SSL_CONNECT_ERROR; | ||||
|         } | ||||
|         break; | ||||
|     } | ||||
| #endif  /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
| #endif  /* CURL_SUPPORT_MAC_10_8 */ | ||||
|   } | ||||
| #else | ||||
|   (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false); | ||||
| @@ -827,9 +965,13 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|                                          true); | ||||
|       break; | ||||
|     case CURL_SSLVERSION_SSLv2: | ||||
|       (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
|       err = SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
|                                          kSSLProtocol2, | ||||
|                                          true); | ||||
|       if(err != noErr) { | ||||
|         failf(data, "Your version of the OS does not support SSLv2"); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|       } | ||||
|       break; | ||||
|     case CURL_SSLVERSION_SSLv3: | ||||
|       (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, | ||||
| @@ -837,16 +979,65 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|                                          true); | ||||
|       break; | ||||
|   } | ||||
| #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ | ||||
|  | ||||
|   /* No need to load certificates here. SecureTransport uses the Keychain | ||||
|    * (which is also part of the Security framework) to evaluate trust. */ | ||||
|   if(data->set.str[STRING_KEY]) { | ||||
|     infof(data, "WARNING: SSL: CURLOPT_SSLKEY is ignored by Secure " | ||||
|                 "Transport. The private key must be in the Keychain.\n"); | ||||
|   } | ||||
|  | ||||
|   if(data->set.str[STRING_CERT]) { | ||||
|     SecIdentityRef cert_and_key = NULL; | ||||
|  | ||||
|     /* User wants to authenticate with a client cert. Look for it: */ | ||||
|     err = CopyIdentityWithLabel(data->set.str[STRING_CERT], &cert_and_key); | ||||
|     if(err == noErr) { | ||||
|       SecCertificateRef cert = NULL; | ||||
|       CFTypeRef certs_c[1]; | ||||
|       CFArrayRef certs; | ||||
|  | ||||
|       /* If we found one, print it out: */ | ||||
|       err = SecIdentityCopyCertificate(cert_and_key, &cert); | ||||
|       if(err == noErr) { | ||||
|         CFStringRef cert_summary = CopyCertSubject(cert); | ||||
|         char cert_summary_c[128]; | ||||
|  | ||||
|         if(cert_summary) { | ||||
|           memset(cert_summary_c, 0, 128); | ||||
|           if(CFStringGetCString(cert_summary, | ||||
|                                 cert_summary_c, | ||||
|                                 128, | ||||
|                                 kCFStringEncodingUTF8)) { | ||||
|             infof(data, "Client certificate: %s\n", cert_summary_c); | ||||
|           } | ||||
|           CFRelease(cert_summary); | ||||
|           CFRelease(cert); | ||||
|         } | ||||
|       } | ||||
|       certs_c[0] = cert_and_key; | ||||
|       certs = CFArrayCreate(NULL, (const void **)certs_c, 1L, | ||||
|                             &kCFTypeArrayCallBacks); | ||||
|       err = SSLSetCertificate(connssl->ssl_ctx, certs); | ||||
|       if(certs) | ||||
|         CFRelease(certs); | ||||
|       if(err != noErr) { | ||||
|         failf(data, "SSL: SSLSetCertificate() failed: OSStatus %d", err); | ||||
|         return CURLE_SSL_CERTPROBLEM; | ||||
|       } | ||||
|       CFRelease(cert_and_key); | ||||
|     } | ||||
|     else { | ||||
|       failf(data, "SSL: Can't find the certificate \"%s\" and its private key " | ||||
|                   "in the Keychain.", data->set.str[STRING_CERT]); | ||||
|       return CURLE_SSL_CERTPROBLEM; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* SSL always tries to verify the peer, this only says whether it should | ||||
|    * fail to connect if the verification fails, or if it should continue | ||||
|    * anyway. In the latter case the result of the verification is checked with | ||||
|    * SSL_get_verify_result() below. */ | ||||
| #if defined(__MAC_10_6) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS | ||||
|   /* Snow Leopard introduced the SSLSetSessionOption() function, but due to | ||||
|      a library bug with the way the kSSLSessionOptionBreakOnServerAuth flag | ||||
|      works, it doesn't work as expected under Snow Leopard or Lion. | ||||
| @@ -855,11 +1046,11 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|      (SecureTransport will always validate the certificate chain by | ||||
|      default.) */ | ||||
|   /* (Note: Darwin 12.x.x is Mountain Lion.) */ | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_BUILD_MAC | ||||
|   if(SSLSetSessionOption != NULL && darwinver_maj >= 12) { | ||||
| #else | ||||
|   if(SSLSetSessionOption != NULL) { | ||||
| #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
| #endif /* CURL_BUILD_MAC */ | ||||
|     err = SSLSetSessionOption(connssl->ssl_ctx, | ||||
|                               kSSLSessionOptionBreakOnServerAuth, | ||||
|                               data->set.ssl.verifypeer?false:true); | ||||
| @@ -869,14 +1060,14 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_SUPPORT_MAC_10_8 | ||||
|     err = SSLSetEnableCertVerify(connssl->ssl_ctx, | ||||
|                                  data->set.ssl.verifypeer?true:false); | ||||
|     if(err != noErr) { | ||||
|       failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); | ||||
|       return CURLE_SSL_CONNECT_ERROR; | ||||
|     } | ||||
| #endif /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
| #endif /* CURL_SUPPORT_MAC_10_8 */ | ||||
|   } | ||||
| #else | ||||
|   err = SSLSetEnableCertVerify(connssl->ssl_ctx, | ||||
| @@ -885,7 +1076,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|     failf(data, "SSL: SSLSetEnableCertVerify() failed: OSStatus %d", err); | ||||
|     return CURLE_SSL_CONNECT_ERROR; | ||||
|   } | ||||
| #endif /* defined(__MAC_10_6) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_6 || CURL_BUILD_IOS */ | ||||
|  | ||||
|   /* If this is a domain name and not an IP address, then configure SNI. | ||||
|    * Also: the verifyhost setting influences SNI usage */ | ||||
| @@ -898,7 +1089,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|     err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name, | ||||
|                                strlen(conn->host.name)); | ||||
|     if(err != noErr) { | ||||
|       infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d", | ||||
|       infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n", | ||||
|             err); | ||||
|     } | ||||
|   } | ||||
| @@ -915,7 +1106,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|      SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers, | ||||
|        &all_ciphers_count) == noErr) { | ||||
|     for(i = 0UL ; i < all_ciphers_count ; i++) { | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_BUILD_MAC | ||||
|      /* There's a known bug in early versions of Mountain Lion where ST's ECC | ||||
|         ciphers (cipher suite 0xC001 through 0xC032) simply do not work. | ||||
|         Work around the problem here by disabling those ciphers if we are | ||||
| @@ -924,7 +1115,7 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|          all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) { | ||||
|            continue; | ||||
|       } | ||||
| #endif | ||||
| #endif /* CURL_BUILD_MAC */ | ||||
|       switch(all_ciphers[i]) { | ||||
|         /* Disable NULL ciphersuites: */ | ||||
|         case SSL_NULL_WITH_NULL_NULL: | ||||
| @@ -990,6 +1181,38 @@ static CURLcode darwinssl_connect_step1(struct connectdata *conn, | ||||
|   Curl_safefree(all_ciphers); | ||||
|   Curl_safefree(allowed_ciphers); | ||||
|  | ||||
|   /* Check if there's a cached ID we can/should use here! */ | ||||
|   if(!Curl_ssl_getsessionid(conn, (void **)&ssl_sessionid, | ||||
|     &ssl_sessionid_len)) { | ||||
|     /* we got a session id, use it! */ | ||||
|     err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); | ||||
|     if(err != noErr) { | ||||
|       failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); | ||||
|       return CURLE_SSL_CONNECT_ERROR; | ||||
|     } | ||||
|     /* Informational message */ | ||||
|     infof(data, "SSL re-using session ID\n"); | ||||
|   } | ||||
|   /* If there isn't one, then let's make one up! This has to be done prior | ||||
|      to starting the handshake. */ | ||||
|   else { | ||||
|     CURLcode retcode; | ||||
|  | ||||
|     ssl_sessionid = malloc(256*sizeof(char)); | ||||
|     ssl_sessionid_len = snprintf(ssl_sessionid, 256, "curl:%s:%hu", | ||||
|       conn->host.name, conn->remote_port); | ||||
|     err = SSLSetPeerID(connssl->ssl_ctx, ssl_sessionid, ssl_sessionid_len); | ||||
|     if(err != noErr) { | ||||
|       failf(data, "SSL: SSLSetPeerID() failed: OSStatus %d", err); | ||||
|       return CURLE_SSL_CONNECT_ERROR; | ||||
|     } | ||||
|     retcode = Curl_ssl_addsessionid(conn, ssl_sessionid, ssl_sessionid_len); | ||||
|     if(retcode!= CURLE_OK) { | ||||
|       failf(data, "failed to store ssl session"); | ||||
|       return retcode; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   err = SSLSetIOFuncs(connssl->ssl_ctx, SocketRead, SocketWrite); | ||||
|   if(err != noErr) { | ||||
|     failf(data, "SSL: SSLSetIOFuncs() failed: OSStatus %d", err); | ||||
| @@ -1059,6 +1282,20 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) | ||||
|               "certificate format"); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|  | ||||
|       /* These are all certificate problems with the client: */ | ||||
|       case errSecAuthFailed: | ||||
|         failf(data, "SSL authentication failed"); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|       case errSSLPeerHandshakeFail: | ||||
|         failf(data, "SSL peer handshake failed, the server most likely " | ||||
|               "requires a client certificate to connect"); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|       case errSSLPeerUnknownCA: | ||||
|         failf(data, "SSL server rejected the client certificate due to " | ||||
|               "the certificate being signed by an unknown certificate " | ||||
|               "authority"); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|  | ||||
|       /* This error is raised if the server's cert didn't match the server's | ||||
|          host name: */ | ||||
|       case errSSLHostNameMismatch: | ||||
| @@ -1111,7 +1348,7 @@ darwinssl_connect_step2(struct connectdata *conn, int sockindex) | ||||
|         infof(data, "TLS 1.0 connection using %s\n", | ||||
|               TLSCipherNameForNumber(cipher)); | ||||
|         break; | ||||
| #if defined(__MAC_10_8) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS | ||||
|       case kTLSProtocol11: | ||||
|         infof(data, "TLS 1.1 connection using %s\n", | ||||
|               TLSCipherNameForNumber(cipher)); | ||||
| @@ -1138,20 +1375,22 @@ darwinssl_connect_step3(struct connectdata *conn, | ||||
|   struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | ||||
|   CFStringRef server_cert_summary; | ||||
|   char server_cert_summary_c[128]; | ||||
|   CFArrayRef server_certs; | ||||
|   CFArrayRef server_certs = NULL; | ||||
|   SecCertificateRef server_cert; | ||||
|   OSStatus err; | ||||
|   CFIndex i, count; | ||||
|   SecTrustRef trust; | ||||
|   SecTrustRef trust = NULL; | ||||
|  | ||||
|   /* There is no step 3! | ||||
|    * Well, okay, if verbose mode is on, let's print the details of the | ||||
|    * server certificates. */ | ||||
| #if defined(__MAC_10_7) || defined(__IPHONE_5_0) | ||||
| #if (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) | ||||
| #if CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS | ||||
| #if CURL_BUILD_IOS | ||||
| #pragma unused(server_certs) | ||||
|   err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); | ||||
|   if(err == noErr) { | ||||
|   /* For some reason, SSLCopyPeerTrust() can return noErr and yet return | ||||
|      a null trust, so be on guard for that: */ | ||||
|   if(err == noErr && trust) { | ||||
|     count = SecTrustGetCertificateCount(trust); | ||||
|     for(i = 0L ; i < count ; i++) { | ||||
|       server_cert = SecTrustGetCertificateAtIndex(trust, i); | ||||
| @@ -1177,7 +1416,9 @@ darwinssl_connect_step3(struct connectdata *conn, | ||||
|   if(SecTrustEvaluateAsync != NULL) { | ||||
| #pragma unused(server_certs) | ||||
|     err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust); | ||||
|     if(err == noErr) { | ||||
|     /* For some reason, SSLCopyPeerTrust() can return noErr and yet return | ||||
|        a null trust, so be on guard for that: */ | ||||
|     if(err == noErr && trust) { | ||||
|       count = SecTrustGetCertificateCount(trust); | ||||
|       for(i = 0L ; i < count ; i++) { | ||||
|         server_cert = SecTrustGetCertificateAtIndex(trust, i); | ||||
| @@ -1195,8 +1436,10 @@ darwinssl_connect_step3(struct connectdata *conn, | ||||
|     } | ||||
|   } | ||||
|   else { | ||||
| #if CURL_SUPPORT_MAC_10_8 | ||||
|     err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); | ||||
|     if(err == noErr) { | ||||
|     /* Just in case SSLCopyPeerCertificates() returns null too... */ | ||||
|     if(err == noErr && server_certs) { | ||||
|       count = CFArrayGetCount(server_certs); | ||||
|       for(i = 0L ; i < count ; i++) { | ||||
|         server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, | ||||
| @@ -1214,8 +1457,9 @@ darwinssl_connect_step3(struct connectdata *conn, | ||||
|       } | ||||
|       CFRelease(server_certs); | ||||
|     } | ||||
| #endif /* CURL_SUPPORT_MAC_10_8 */ | ||||
|   } | ||||
| #endif /* (TARGET_OS_EMBEDDED || TARGET_OS_IPHONE) */ | ||||
| #endif /* CURL_BUILD_IOS */ | ||||
| #else | ||||
| #pragma unused(trust) | ||||
|   err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs); | ||||
| @@ -1235,7 +1479,7 @@ darwinssl_connect_step3(struct connectdata *conn, | ||||
|     } | ||||
|     CFRelease(server_certs); | ||||
|   } | ||||
| #endif /* defined(__MAC_10_7) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */ | ||||
|  | ||||
|   connssl->connecting_state = ssl_connect_done; | ||||
|   return CURLE_OK; | ||||
| @@ -1387,16 +1631,16 @@ void Curl_darwinssl_close(struct connectdata *conn, int sockindex) | ||||
|  | ||||
|   if(connssl->ssl_ctx) { | ||||
|     (void)SSLClose(connssl->ssl_ctx); | ||||
| #if defined(__MAC_10_8) || defined(__IPHONE_5_0) | ||||
| #if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS | ||||
|     if(SSLCreateContext != NULL) | ||||
|       CFRelease(connssl->ssl_ctx); | ||||
| #if (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) | ||||
| #if CURL_SUPPORT_MAC_10_8 | ||||
|     else | ||||
|       (void)SSLDisposeContext(connssl->ssl_ctx); | ||||
| #endif  /* (TARGET_OS_MAC && !(TARGET_OS_EMBEDDED || TARGET_OS_IPHONE)) */ | ||||
| #endif  /* CURL_SUPPORT_MAC_10_8 */ | ||||
| #else | ||||
|     (void)SSLDisposeContext(connssl->ssl_ctx); | ||||
| #endif /* defined(__MAC_10_8) || defined(__IPHONE_5_0) */ | ||||
| #endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */ | ||||
|     connssl->ssl_ctx = NULL; | ||||
|   } | ||||
|   connssl->ssl_sockfd = 0; | ||||
| @@ -1462,6 +1706,17 @@ int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex) | ||||
|   return rc; | ||||
| } | ||||
|  | ||||
| void Curl_darwinssl_session_free(void *ptr) | ||||
| { | ||||
|   /* ST, as of iOS 5 and Mountain Lion, has no public method of deleting a | ||||
|      cached session ID inside the Security framework. There is a private | ||||
|      function that does this, but I don't want to have to explain to you why I | ||||
|      got your application rejected from the App Store due to the use of a | ||||
|      private API, so the best we can do is free up our own char array that we | ||||
|      created way back in darwinssl_connect_step1... */ | ||||
|   Curl_safefree(ptr); | ||||
| } | ||||
|  | ||||
| size_t Curl_darwinssl_version(char *buffer, size_t size) | ||||
| { | ||||
|   return snprintf(buffer, size, "SecureTransport"); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 2012, Nick Zitzmann, <nickzman@gmail.com>. | ||||
|  * Copyright (C) 2012 - 2013, Nick Zitzmann, <nickzman@gmail.com>. | ||||
|  * | ||||
|  * This software is licensed as described in the file COPYING, which | ||||
|  * you should have received as part of this distribution. The terms | ||||
| @@ -37,6 +37,7 @@ void Curl_darwinssl_close_all(struct SessionHandle *data); | ||||
| /* close a SSL connection */ | ||||
| void Curl_darwinssl_close(struct connectdata *conn, int sockindex); | ||||
|  | ||||
| void Curl_darwinssl_session_free(void *ptr); | ||||
| size_t Curl_darwinssl_version(char *buffer, size_t size); | ||||
| int Curl_darwinssl_shutdown(struct connectdata *conn, int sockindex); | ||||
| int Curl_darwinssl_check_cxn(struct connectdata *conn); | ||||
| @@ -51,12 +52,16 @@ void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */ | ||||
|                            unsigned char *md5sum, /* output */ | ||||
|                            size_t md5len); | ||||
|  | ||||
| /* this backend provides these functions: */ | ||||
| #define have_curlssl_random 1 | ||||
| #define have_curlssl_md5sum 1 | ||||
|  | ||||
| /* API setup for SecureTransport */ | ||||
| #define curlssl_init() (1) | ||||
| #define curlssl_cleanup() Curl_nop_stmt | ||||
| #define curlssl_connect Curl_darwinssl_connect | ||||
| #define curlssl_connect_nonblocking Curl_darwinssl_connect_nonblocking | ||||
| #define curlssl_session_free(x) Curl_nop_stmt | ||||
| #define curlssl_session_free(x) Curl_darwinssl_session_free(x) | ||||
| #define curlssl_close_all Curl_darwinssl_close_all | ||||
| #define curlssl_close Curl_darwinssl_close | ||||
| #define curlssl_shutdown(x,y) 0 | ||||
|   | ||||
| @@ -87,7 +87,7 @@ extern curl_free_callback Curl_cfree; | ||||
| extern curl_realloc_callback Curl_crealloc; | ||||
| extern curl_strdup_callback Curl_cstrdup; | ||||
| extern curl_calloc_callback Curl_ccalloc; | ||||
| #ifdef WIN32 | ||||
| #if defined(WIN32) && defined(UNICODE) | ||||
| extern curl_wcsdup_callback Curl_cwcsdup; | ||||
| #endif | ||||
|  | ||||
| @@ -114,14 +114,15 @@ extern curl_wcsdup_callback Curl_cwcsdup; | ||||
| #define free(ptr) Curl_cfree(ptr) | ||||
|  | ||||
| #ifdef WIN32 | ||||
| #  undef wcsdup | ||||
| #  define wcsdup(ptr) Curl_cwcsdup(ptr) | ||||
| #  undef _wcsdup | ||||
| #  define _wcsdup(ptr) Curl_cwcsdup(ptr) | ||||
| #  undef _tcsdup | ||||
| #  ifdef UNICODE | ||||
| #    undef wcsdup | ||||
| #    define wcsdup(ptr) Curl_cwcsdup(ptr) | ||||
| #    undef _wcsdup | ||||
| #    define _wcsdup(ptr) Curl_cwcsdup(ptr) | ||||
| #    undef _tcsdup | ||||
| #    define _tcsdup(ptr) Curl_cwcsdup(ptr) | ||||
| #  else | ||||
| #    undef _tcsdup | ||||
| #    define _tcsdup(ptr) Curl_cstrdup(ptr) | ||||
| #  endif | ||||
| #endif | ||||
|   | ||||
| @@ -1,61 +0,0 @@ | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2009, 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 "curl_setup.h" | ||||
|  | ||||
| #include <curl/curl.h> | ||||
|  | ||||
| #include "curl_rand.h" | ||||
|  | ||||
| #define _MPRINTF_REPLACE /* use our functions only */ | ||||
| #include <curl/mprintf.h> | ||||
|  | ||||
| #include "curl_memory.h" | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| /* Private pseudo-random number seed. Unsigned integer >= 32bit. Threads | ||||
|    mutual exclusion is not implemented to acess it since we do not require | ||||
|    high quality random numbers (only used in form boudary generation). */ | ||||
|  | ||||
| static unsigned int randseed; | ||||
|  | ||||
| /* Pseudo-random number support. */ | ||||
|  | ||||
| unsigned int Curl_rand(void) | ||||
| { | ||||
|   unsigned int r; | ||||
|   /* Return an unsigned 32-bit pseudo-random number. */ | ||||
|   r = randseed = randseed * 1103515245 + 12345; | ||||
|   return (r << 16) | ((r >> 16) & 0xFFFF); | ||||
| } | ||||
|  | ||||
| void Curl_srand(void) | ||||
| { | ||||
|   /* Randomize pseudo-random number sequence. */ | ||||
|  | ||||
|   randseed = (unsigned int) time(NULL); | ||||
|   Curl_rand(); | ||||
|   Curl_rand(); | ||||
|   Curl_rand(); | ||||
| } | ||||
|  | ||||
| @@ -32,7 +32,7 @@ | ||||
|  | ||||
| #include "curl_base64.h" | ||||
| #include "curl_md5.h" | ||||
| #include "curl_rand.h" | ||||
| #include "sslgen.h" | ||||
| #include "curl_hmac.h" | ||||
| #include "curl_ntlm_msgs.h" | ||||
| #include "curl_sasl.h" | ||||
| @@ -314,7 +314,7 @@ CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data, | ||||
|  | ||||
|   /* Generate 64 bits of random data */ | ||||
|   for(i = 0; i < 8; i++) | ||||
|     cnonce[i] = table16[Curl_rand()%16]; | ||||
|     cnonce[i] = table16[Curl_rand(data)%16]; | ||||
|  | ||||
|   /* So far so good, now calculate A1 and H(A1) according to RFC 2831 */ | ||||
|   ctxt = Curl_MD5_init(Curl_DIGEST_MD5); | ||||
|   | ||||
| @@ -25,13 +25,17 @@ | ||||
| #include "pingpong.h" | ||||
|  | ||||
| /* Authentication mechanism flags */ | ||||
| #define SASL_MECH_LOGIN         0x0001 | ||||
| #define SASL_MECH_PLAIN         0x0002 | ||||
| #define SASL_MECH_CRAM_MD5      0x0004 | ||||
| #define SASL_MECH_DIGEST_MD5    0x0008 | ||||
| #define SASL_MECH_GSSAPI        0x0010 | ||||
| #define SASL_MECH_EXTERNAL      0x0020 | ||||
| #define SASL_MECH_NTLM          0x0040 | ||||
| #define SASL_MECH_LOGIN         (1 << 0) | ||||
| #define SASL_MECH_PLAIN         (1 << 1) | ||||
| #define SASL_MECH_CRAM_MD5      (1 << 2) | ||||
| #define SASL_MECH_DIGEST_MD5    (1 << 3) | ||||
| #define SASL_MECH_GSSAPI        (1 << 4) | ||||
| #define SASL_MECH_EXTERNAL      (1 << 5) | ||||
| #define SASL_MECH_NTLM          (1 << 6) | ||||
|  | ||||
| /* Authentication mechanism values */ | ||||
| #define SASL_AUTH_NONE          0 | ||||
| #define SASL_AUTH_ANY           ~0 | ||||
|  | ||||
| /* This is used to generate a base64 encoded PLAIN authentication message */ | ||||
| CURLcode Curl_sasl_create_plain_message(struct SessionHandle *data, | ||||
|   | ||||
| @@ -534,6 +534,7 @@ schannel_connect_step3(struct connectdata *conn, int sockindex) | ||||
|       return retcode; | ||||
|     } | ||||
|     else { | ||||
|       connssl->cred->cached = TRUE; | ||||
|       infof(data, "schannel: stored credential handle in session cache\n"); | ||||
|     } | ||||
|   } | ||||
| @@ -1063,7 +1064,6 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) | ||||
|    */ | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct ssl_connect_data *connssl = &conn->ssl[sockindex]; | ||||
|   struct curl_schannel_cred *cached_cred = NULL; | ||||
|  | ||||
|   infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n", | ||||
|         conn->host.name, conn->remote_port); | ||||
| @@ -1141,17 +1141,11 @@ int Curl_schannel_shutdown(struct connectdata *conn, int sockindex) | ||||
|               connssl->cred->refcount); | ||||
|       } | ||||
|  | ||||
|       /* if the handle refcount is zero, check if we have not cached it */ | ||||
|       if(connssl->cred->refcount == 0) { | ||||
|         if(Curl_ssl_getsessionid(conn, (void**)&cached_cred, NULL)) { | ||||
|           cached_cred = NULL; | ||||
|         } | ||||
|         /* if the handle was not cached, it is stale to be freed */ | ||||
|         if(connssl->cred != cached_cred) { | ||||
|           infof(data, "schannel: clear credential handle\n"); | ||||
|           s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); | ||||
|           Curl_safefree(connssl->cred); | ||||
|         } | ||||
|       /* if the handle was not cached and the refcount is zero */ | ||||
|       if(!connssl->cred->cached && connssl->cred->refcount == 0) { | ||||
|         infof(data, "schannel: clear credential handle\n"); | ||||
|         s_pSecFn->FreeCredentialsHandle(&connssl->cred->cred_handle); | ||||
|         Curl_safefree(connssl->cred); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -1177,7 +1171,7 @@ void Curl_schannel_session_free(void *ptr) | ||||
| { | ||||
|   struct curl_schannel_cred *cred = ptr; | ||||
|  | ||||
|   if(cred && cred->refcount == 0) { | ||||
|   if(cred && cred->cached && cred->refcount == 0) { | ||||
|     s_pSecFn->FreeCredentialsHandle(&cred->cred_handle); | ||||
|     Curl_safefree(cred); | ||||
|   } | ||||
|   | ||||
| @@ -270,7 +270,9 @@ | ||||
| #    endif | ||||
| #  endif | ||||
| #  include <tchar.h> | ||||
|    typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); | ||||
| #  ifdef UNICODE | ||||
|      typedef wchar_t *(*curl_wcsdup_callback)(const wchar_t *str); | ||||
| #  endif | ||||
| #endif | ||||
|  | ||||
| /* | ||||
| @@ -369,7 +371,9 @@ | ||||
| #  include <sys/stat.h> | ||||
| #  undef  lseek | ||||
| #  define lseek(fdes,offset,whence)  _lseeki64(fdes, offset, whence) | ||||
| #  undef  fstat | ||||
| #  define fstat(fdes,stp)            _fstati64(fdes, stp) | ||||
| #  undef  stat | ||||
| #  define stat(fname,stp)            _stati64(fname, stp) | ||||
| #  define struct_stat                struct _stati64 | ||||
| #  define LSEEK_ERROR                (__int64)-1 | ||||
| @@ -616,7 +620,7 @@ int netware_init(void); | ||||
| #if defined(USE_GNUTLS) || defined(USE_SSLEAY) || defined(USE_NSS) || \ | ||||
|     defined(USE_QSOSSL) || defined(USE_POLARSSL) || defined(USE_AXTLS) || \ | ||||
|     defined(USE_CYASSL) || defined(USE_SCHANNEL) || \ | ||||
|     defined(USE_DARWINSSL) | ||||
|     defined(USE_DARWINSSL) || defined(USE_GSKIT) | ||||
| #define USE_SSL    /* SSL support has been enabled */ | ||||
| #endif | ||||
|  | ||||
|   | ||||
							
								
								
									
										170
									
								
								lib/dotdot.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										170
									
								
								lib/dotdot.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,170 @@ | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2013, 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 "curl_setup.h" | ||||
|  | ||||
| #include "dotdot.h" | ||||
|  | ||||
| #include "curl_memory.h" | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| /* | ||||
|  * "Remove Dot Segments" | ||||
|  * http://tools.ietf.org/html/rfc3986#section-5.2.4 | ||||
|  */ | ||||
|  | ||||
| /* | ||||
|  * Curl_dedotdotify() | ||||
|  * | ||||
|  * This function gets a zero-terminated path with dot and dotdot sequences | ||||
|  * passed in and strips them off according to the rules in RFC 3986 section | ||||
|  * 5.2.4. | ||||
|  * | ||||
|  * The function handles a query part ('?' + stuff) appended but it expects | ||||
|  * that fragments ('#' + stuff) have already been cut off. | ||||
|  * | ||||
|  * RETURNS | ||||
|  * | ||||
|  * an allocated dedotdotified output string | ||||
|  */ | ||||
| char *Curl_dedotdotify(char *input) | ||||
| { | ||||
|   size_t inlen = strlen(input); | ||||
|   char *clone; | ||||
|   size_t clen = inlen; /* the length of the cloned input */ | ||||
|   char *out = malloc(inlen+1); | ||||
|   char *outptr; | ||||
|   char *orgclone; | ||||
|   char *queryp; | ||||
|   if(!out) | ||||
|     return NULL; /* out of memory */ | ||||
|  | ||||
|   /* get a cloned copy of the input */ | ||||
|   clone = strdup(input); | ||||
|   if(!clone) { | ||||
|     free(out); | ||||
|     return NULL; | ||||
|   } | ||||
|   orgclone = clone; | ||||
|   outptr = out; | ||||
|  | ||||
|   /* | ||||
|    * To handle query-parts properly, we must find it and remove it during the | ||||
|    * dotdot-operation and then append it again at the end to the output | ||||
|    * string. | ||||
|    */ | ||||
|   queryp = strchr(clone, '?'); | ||||
|   if(queryp) | ||||
|     *queryp = 0; | ||||
|  | ||||
|   do { | ||||
|  | ||||
|     /*  A.  If the input buffer begins with a prefix of "../" or "./", then | ||||
|         remove that prefix from the input buffer; otherwise, */ | ||||
|  | ||||
|     if(!strncmp("./", clone, 2)) { | ||||
|       clone+=2; | ||||
|       clen-=2; | ||||
|     } | ||||
|     else if(!strncmp("../", clone, 3)) { | ||||
|       clone+=3; | ||||
|       clen-=3; | ||||
|     } | ||||
|  | ||||
|     /*  B.  if the input buffer begins with a prefix of "/./" or "/.", where | ||||
|         "."  is a complete path segment, then replace that prefix with "/" in | ||||
|         the input buffer; otherwise, */ | ||||
|     else if(!strncmp("/./", clone, 3)) { | ||||
|       clone+=2; | ||||
|       clen-=2; | ||||
|     } | ||||
|     else if(!strcmp("/.", clone)) { | ||||
|       clone[1]='/'; | ||||
|       clone++; | ||||
|       clen-=1; | ||||
|     } | ||||
|  | ||||
|     /*  C.  if the input buffer begins with a prefix of "/../" or "/..", where | ||||
|         ".." is a complete path segment, then replace that prefix with "/" in | ||||
|         the input buffer and remove the last segment and its preceding "/" (if | ||||
|         any) from the output buffer; otherwise, */ | ||||
|  | ||||
|     else if(!strncmp("/../", clone, 4)) { | ||||
|       clone+=3; | ||||
|       clen-=3; | ||||
|       /* remove the last segment from the output buffer */ | ||||
|       while(outptr > out) { | ||||
|         outptr--; | ||||
|         if(*outptr == '/') | ||||
|           break; | ||||
|       } | ||||
|       *outptr = 0; /* zero-terminate where it stops */ | ||||
|     } | ||||
|     else if(!strcmp("/..", clone)) { | ||||
|       clone[2]='/'; | ||||
|       clone+=2; | ||||
|       clen-=2; | ||||
|       /* remove the last segment from the output buffer */ | ||||
|       while(outptr > out) { | ||||
|         outptr--; | ||||
|         if(*outptr == '/') | ||||
|           break; | ||||
|       } | ||||
|       *outptr = 0; /* zero-terminate where it stops */ | ||||
|     } | ||||
|  | ||||
|     /*  D.  if the input buffer consists only of "." or "..", then remove | ||||
|         that from the input buffer; otherwise, */ | ||||
|  | ||||
|     else if(!strcmp(".", clone) || !strcmp("..", clone)) { | ||||
|       *clone=0; | ||||
|     } | ||||
|  | ||||
|     else { | ||||
|       /*  E.  move the first path segment in the input buffer to the end of | ||||
|           the output buffer, including the initial "/" character (if any) and | ||||
|           any subsequent characters up to, but not including, the next "/" | ||||
|           character or the end of the input buffer. */ | ||||
|  | ||||
|       do { | ||||
|         *outptr++ = *clone++; | ||||
|         clen--; | ||||
|       } while(*clone && (*clone != '/')); | ||||
|       *outptr = 0; | ||||
|     } | ||||
|  | ||||
|   } while(*clone); | ||||
|  | ||||
|   if(queryp) { | ||||
|     size_t qlen; | ||||
|     /* There was a query part, append that to the output. The 'clone' string | ||||
|        may now have been altered so we copy from the original input string | ||||
|        from the correct index. */ | ||||
|     size_t oindex = queryp - orgclone; | ||||
|     qlen = strlen(&input[oindex]); | ||||
|     memcpy(outptr, &input[oindex], qlen+1); /* include the ending zero byte */ | ||||
|   } | ||||
|  | ||||
|   free(orgclone); | ||||
|   return out; | ||||
| } | ||||
| @@ -1,5 +1,5 @@ | ||||
| #ifndef HEADER_CURL_RAND_H | ||||
| #define HEADER_CURL_RAND_H | ||||
| #ifndef HEADER_CURL_DOTDOT_H | ||||
| #define HEADER_CURL_DOTDOT_H | ||||
| /***************************************************************************
 | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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,9 +21,5 @@ | ||||
|  * KIND, either express or implied. | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| 
 | ||||
| void Curl_srand(void); | ||||
| 
 | ||||
| unsigned int Curl_rand(void); | ||||
| 
 | ||||
| #endif /* HEADER_CURL_RAND_H */ | ||||
| char *Curl_dedotdotify(char *input); | ||||
| #endif | ||||
							
								
								
									
										119
									
								
								lib/easy.c
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								lib/easy.c
									
									
									
									
									
								
							| @@ -50,6 +50,11 @@ | ||||
| #include <sys/param.h> | ||||
| #endif | ||||
|  | ||||
| #if defined(HAVE_SIGNAL_H) && defined(HAVE_SIGACTION) && defined(USE_OPENSSL) | ||||
| #define SIGPIPE_IGNORE 1 | ||||
| #include <signal.h> | ||||
| #endif | ||||
|  | ||||
| #include "strequal.h" | ||||
| #include "urldata.h" | ||||
| #include <curl/curl.h> | ||||
| @@ -69,10 +74,10 @@ | ||||
| #include "connect.h" /* for Curl_getconnectinfo */ | ||||
| #include "slist.h" | ||||
| #include "amigaos.h" | ||||
| #include "curl_rand.h" | ||||
| #include "non-ascii.h" | ||||
| #include "warnless.h" | ||||
| #include "conncache.h" | ||||
| #include "multiif.h" | ||||
|  | ||||
| #define _MPRINTF_REPLACE /* use our functions only */ | ||||
| #include <curl/mprintf.h> | ||||
| @@ -80,6 +85,56 @@ | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| #ifdef SIGPIPE_IGNORE | ||||
| struct sigpipe_ignore { | ||||
|   struct sigaction old_pipe_act; | ||||
|   bool no_signal; | ||||
| }; | ||||
|  | ||||
| #define SIGPIPE_VARIABLE(x) struct sigpipe_ignore x | ||||
|  | ||||
| /* | ||||
|  * sigpipe_ignore() makes sure we ignore SIGPIPE while running libcurl | ||||
|  * internals, and then sigpipe_restore() will restore the situation when we | ||||
|  * return from libcurl again. | ||||
|  */ | ||||
| static void sigpipe_ignore(struct SessionHandle *data, | ||||
|                            struct sigpipe_ignore *ig) | ||||
| { | ||||
|   /* get a local copy of no_signal because the SessionHandle might not be | ||||
|      around when we restore */ | ||||
|   ig->no_signal = data->set.no_signal; | ||||
|   if(!data->set.no_signal) { | ||||
|     struct sigaction action; | ||||
|     /* first, extract the existing situation */ | ||||
|     memset(&ig->old_pipe_act, 0, sizeof(struct sigaction)); | ||||
|     sigaction(SIGPIPE, NULL, &ig->old_pipe_act); | ||||
|     action = ig->old_pipe_act; | ||||
|     /* ignore this signal */ | ||||
|     action.sa_handler = SIG_IGN; | ||||
|     sigaction(SIGPIPE, &action, NULL); | ||||
|   } | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * sigpipe_restore() puts back the outside world's opinion of signal handler | ||||
|  * and SIGPIPE handling. It MUST only be called after a corresponding | ||||
|  * sigpipe_ignore() was used. | ||||
|  */ | ||||
| static void sigpipe_restore(struct sigpipe_ignore *ig) | ||||
| { | ||||
|   if(!ig->no_signal) | ||||
|     /* restore the outside state */ | ||||
|     sigaction(SIGPIPE, &ig->old_pipe_act, NULL); | ||||
| } | ||||
|  | ||||
| #else | ||||
| /* for systems without sigaction */ | ||||
| #define sigpipe_ignore(x,y) Curl_nop_stmt | ||||
| #define sigpipe_restore(x)  Curl_nop_stmt | ||||
| #define SIGPIPE_VARIABLE(x) | ||||
| #endif | ||||
|  | ||||
| /* win32_cleanup() is for win32 socket cleanup functionality, the opposite | ||||
|    of win32_init() */ | ||||
| static void win32_cleanup(void) | ||||
| @@ -197,8 +252,8 @@ curl_free_callback Curl_cfree = (curl_free_callback)free; | ||||
| curl_realloc_callback Curl_crealloc = (curl_realloc_callback)realloc; | ||||
| curl_strdup_callback Curl_cstrdup = (curl_strdup_callback)system_strdup; | ||||
| curl_calloc_callback Curl_ccalloc = (curl_calloc_callback)calloc; | ||||
| #ifdef WIN32 | ||||
| curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)wcsdup; | ||||
| #if defined(WIN32) && defined(UNICODE) | ||||
| curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; | ||||
| #endif | ||||
| #else | ||||
| /* | ||||
| @@ -231,8 +286,8 @@ CURLcode curl_global_init(long flags) | ||||
|   Curl_crealloc = (curl_realloc_callback)realloc; | ||||
|   Curl_cstrdup = (curl_strdup_callback)system_strdup; | ||||
|   Curl_ccalloc = (curl_calloc_callback)calloc; | ||||
| #ifdef WIN32 | ||||
|   Curl_cwcsdup = (curl_wcsdup_callback)wcsdup; | ||||
| #if defined(WIN32) && defined(UNICODE) | ||||
|   Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup; | ||||
| #endif | ||||
|  | ||||
|   if(flags & CURL_GLOBAL_SSL) | ||||
| @@ -281,10 +336,6 @@ CURLcode curl_global_init(long flags) | ||||
|  | ||||
|   init_flags  = flags; | ||||
|  | ||||
|   /* Preset pseudo-random number sequence. */ | ||||
|  | ||||
|   Curl_srand(); | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| @@ -425,6 +476,10 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|   bool done = FALSE; | ||||
|   int rc; | ||||
|   struct SessionHandle *data = easy; | ||||
|   int without_fds = 0;  /* count number of consecutive returns from | ||||
|                            curl_multi_wait() without any filedescriptors */ | ||||
|   struct timeval before; | ||||
|   SIGPIPE_VARIABLE(pipe_st); | ||||
|  | ||||
|   if(!easy) | ||||
|     return CURLE_BAD_FUNCTION_ARGUMENT; | ||||
| @@ -437,7 +492,9 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|   if(data->multi_easy) | ||||
|     multi = data->multi_easy; | ||||
|   else { | ||||
|     multi = curl_multi_init(); | ||||
|     /* this multi handle will only ever have a single easy handled attached | ||||
|        to it, so make it use minimal hashes */ | ||||
|     multi = Curl_multi_handle(1, 3); | ||||
|     if(!multi) | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     data->multi_easy = multi; | ||||
| @@ -455,6 +512,8 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|       return CURLE_FAILED_INIT; | ||||
|   } | ||||
|  | ||||
|   sigpipe_ignore(data, &pipe_st); | ||||
|  | ||||
|   /* assign this after curl_multi_add_handle() since that function checks for | ||||
|      it and rejects this handle otherwise */ | ||||
|   data->multi = multi; | ||||
| @@ -463,6 +522,7 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|     int still_running; | ||||
|     int ret; | ||||
|  | ||||
|     before = curlx_tvnow(); | ||||
|     mcode = curl_multi_wait(multi, NULL, 0, 1000, &ret); | ||||
|  | ||||
|     if(mcode == CURLM_OK) { | ||||
| @@ -471,6 +531,25 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|         code = CURLE_RECV_ERROR; | ||||
|         break; | ||||
|       } | ||||
|       else if(ret == 0) { | ||||
|         struct timeval after = curlx_tvnow(); | ||||
|         /* If it returns without any filedescriptor instantly, we need to | ||||
|            avoid busy-looping during periods where it has nothing particular | ||||
|            to wait for */ | ||||
|         if(curlx_tvdiff(after, before) <= 10) { | ||||
|           without_fds++; | ||||
|           if(without_fds > 2) { | ||||
|             int sleep_ms = without_fds < 10 ? (1 << (without_fds-1)): 1000; | ||||
|             Curl_wait_ms(sleep_ms); | ||||
|           } | ||||
|         } | ||||
|         else | ||||
|           /* it wasn't "instant", restart counter */ | ||||
|           without_fds = 0; | ||||
|       } | ||||
|       else | ||||
|         /* got file descriptor, restart counter */ | ||||
|         without_fds = 0; | ||||
|  | ||||
|       mcode = curl_multi_perform(multi, &still_running); | ||||
|     } | ||||
| @@ -489,6 +568,8 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
|      a failure here, room for future improvement! */ | ||||
|   (void)curl_multi_remove_handle(multi, easy); | ||||
|  | ||||
|   sigpipe_restore(&pipe_st); | ||||
|  | ||||
|   /* The multi handle is kept alive, owned by the easy handle */ | ||||
|   return code; | ||||
| } | ||||
| @@ -500,11 +581,14 @@ CURLcode curl_easy_perform(CURL *easy) | ||||
| void curl_easy_cleanup(CURL *curl) | ||||
| { | ||||
|   struct SessionHandle *data = (struct SessionHandle *)curl; | ||||
|   SIGPIPE_VARIABLE(pipe_st); | ||||
|  | ||||
|   if(!data) | ||||
|     return; | ||||
|  | ||||
|   sigpipe_ignore(data, &pipe_st); | ||||
|   Curl_close(data); | ||||
|   sigpipe_restore(&pipe_st); | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -532,12 +616,16 @@ CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...) | ||||
| { | ||||
|   va_list arg; | ||||
|   void *paramp; | ||||
|   CURLcode ret; | ||||
|   struct SessionHandle *data = (struct SessionHandle *)curl; | ||||
|  | ||||
|   va_start(arg, info); | ||||
|   paramp = va_arg(arg, void *); | ||||
|  | ||||
|   return Curl_getinfo(data, info, paramp); | ||||
|   ret = Curl_getinfo(data, info, paramp); | ||||
|  | ||||
|   va_end(arg); | ||||
|   return ret; | ||||
| } | ||||
|  | ||||
| /* | ||||
| @@ -724,7 +812,7 @@ CURLcode curl_easy_pause(CURL *curl, int action) | ||||
|     do { | ||||
|       chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize; | ||||
|  | ||||
|       result = Curl_client_write(data->state.current_conn, | ||||
|       result = Curl_client_write(data->easy_conn, | ||||
|                                  temptype, tempwrite, chunklen); | ||||
|       if(result) | ||||
|         /* failures abort the loop at once */ | ||||
| @@ -766,6 +854,13 @@ CURLcode curl_easy_pause(CURL *curl, int action) | ||||
|     free(freewrite); /* this is unconditionally no longer used */ | ||||
|   } | ||||
|  | ||||
|   /* if there's no error and we're not pausing both directions, we want | ||||
|      to have this handle checked soon */ | ||||
|   if(!result && | ||||
|      ((newstate&(KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) != | ||||
|       (KEEP_RECV_PAUSE|KEEP_SEND_PAUSE)) ) | ||||
|     Curl_expire(data, 1); /* get this handle going again */ | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -159,7 +159,8 @@ CURLcode Curl_urldecode(struct SessionHandle *data, | ||||
|  | ||||
|   while(--alloc > 0) { | ||||
|     in = *string; | ||||
|     if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { | ||||
|     if(('%' == in) && (alloc > 2) && | ||||
|        ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { | ||||
|       /* this is two hexadecimal digits following a '%' */ | ||||
|       char hexstr[3]; | ||||
|       char *ptr; | ||||
|   | ||||
							
								
								
									
										147
									
								
								lib/formdata.c
									
									
									
									
									
								
							
							
						
						
									
										147
									
								
								lib/formdata.c
									
									
									
									
									
								
							| @@ -24,9 +24,6 @@ | ||||
|  | ||||
| #include <curl/curl.h> | ||||
|  | ||||
| /* Length of the random boundary string. */ | ||||
| #define BOUNDARY_LENGTH 40 | ||||
|  | ||||
| #if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) | ||||
|  | ||||
| #if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME) | ||||
| @@ -35,7 +32,7 @@ | ||||
|  | ||||
| #include "urldata.h" /* for struct SessionHandle */ | ||||
| #include "formdata.h" | ||||
| #include "curl_rand.h" | ||||
| #include "sslgen.h" | ||||
| #include "strequal.h" | ||||
| #include "curl_memory.h" | ||||
| #include "sendf.h" | ||||
| @@ -56,7 +53,7 @@ static char *Curl_basename(char *path); | ||||
| #endif | ||||
|  | ||||
| static size_t readfromfile(struct Form *form, char *buffer, size_t size); | ||||
| static char *formboundary(void); | ||||
| static char *formboundary(struct SessionHandle *data); | ||||
|  | ||||
| /* What kind of Content-Type to use on un-specified files with unrecognized | ||||
|    extensions. */ | ||||
| @@ -171,8 +168,8 @@ static FormInfo * AddFormInfo(char *value, | ||||
|  * Returns some valid contenttype for filename. | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
| static const char * ContentTypeForFilename (const char *filename, | ||||
|                                             const char *prevtype) | ||||
| static const char *ContentTypeForFilename(const char *filename, | ||||
|                                           const char *prevtype) | ||||
| { | ||||
|   const char *contenttype = NULL; | ||||
|   unsigned int i; | ||||
| @@ -181,7 +178,7 @@ static const char * ContentTypeForFilename (const char *filename, | ||||
|    * extensions and pick the first we match! | ||||
|    */ | ||||
|   struct ContentType { | ||||
|     char extension[6]; | ||||
|     const char *extension; | ||||
|     const char *type; | ||||
|   }; | ||||
|   static const struct ContentType ctts[]={ | ||||
| @@ -429,7 +426,7 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, | ||||
|  | ||||
|       /* Get contents from a given file name */ | ||||
|     case CURLFORM_FILECONTENT: | ||||
|       if(current_form->flags != 0) | ||||
|       if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE)) | ||||
|         return_value = CURL_FORMADD_OPTION_TWICE; | ||||
|       else { | ||||
|         const char *filename = array_state? | ||||
| @@ -670,9 +667,11 @@ CURLFORMcode FormAdd(struct curl_httppost **httppost, | ||||
|         if(((form->flags & HTTPPOST_FILENAME) || | ||||
|             (form->flags & HTTPPOST_BUFFER)) && | ||||
|            !form->contenttype ) { | ||||
|           char *f = form->flags & HTTPPOST_BUFFER? | ||||
|             form->showfilename : form->value; | ||||
|  | ||||
|           /* our contenttype is missing */ | ||||
|           form->contenttype | ||||
|             = strdup(ContentTypeForFilename(form->value, prevtype)); | ||||
|           form->contenttype = strdup(ContentTypeForFilename(f, prevtype)); | ||||
|           if(!form->contenttype) { | ||||
|             return_value = CURL_FORMADD_MEMORY; | ||||
|             break; | ||||
| @@ -777,6 +776,70 @@ CURLFORMcode curl_formadd(struct curl_httppost **httppost, | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| #ifdef __VMS | ||||
| #include <fabdef.h> | ||||
| /* | ||||
|  * get_vms_file_size does what it takes to get the real size of the file | ||||
|  * | ||||
|  * For fixed files, find out the size of the EOF block and adjust. | ||||
|  * | ||||
|  * For all others, have to read the entire file in, discarding the contents. | ||||
|  * Most posted text files will be small, and binary files like zlib archives | ||||
|  * and CD/DVD images should be either a STREAM_LF format or a fixed format. | ||||
|  * | ||||
|  */ | ||||
| curl_off_t VmsRealFileSize(const char * name, | ||||
|                            const struct_stat * stat_buf) | ||||
| { | ||||
|   char buffer[8192]; | ||||
|   curl_off_t count; | ||||
|   int ret_stat; | ||||
|   FILE * file; | ||||
|  | ||||
|   file = fopen(name, "r"); | ||||
|   if(file == NULL) | ||||
|     return 0; | ||||
|  | ||||
|   count = 0; | ||||
|   ret_stat = 1; | ||||
|   while(ret_stat > 0) { | ||||
|     ret_stat = fread(buffer, 1, sizeof(buffer), file); | ||||
|     if(ret_stat != 0) | ||||
|       count += ret_stat; | ||||
|   } | ||||
|   fclose(file); | ||||
|  | ||||
|   return count; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * | ||||
|  *  VmsSpecialSize checks to see if the stat st_size can be trusted and | ||||
|  *  if not to call a routine to get the correct size. | ||||
|  * | ||||
|  */ | ||||
| static curl_off_t VmsSpecialSize(const char * name, | ||||
|                                  const struct_stat * stat_buf) | ||||
| { | ||||
|   switch(stat_buf->st_fab_rfm) { | ||||
|   case FAB$C_VAR: | ||||
|   case FAB$C_VFC: | ||||
|     return VmsRealFileSize(name, stat_buf); | ||||
|     break; | ||||
|   default: | ||||
|     return stat_buf->st_size; | ||||
|   } | ||||
| } | ||||
|  | ||||
| #endif | ||||
|  | ||||
| #ifndef __VMS | ||||
| #define filesize(name, stat_data) (stat_data.st_size) | ||||
| #else | ||||
|     /* Getting the expected file size needs help on VMS */ | ||||
| #define filesize(name, stat_data) VmsSpecialSize(name, &stat_data) | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * AddFormData() adds a chunk of data to the FormData linked list. | ||||
|  * | ||||
| @@ -832,7 +895,7 @@ static CURLcode AddFormData(struct FormData **formp, | ||||
|       if(!strequal("-", newform->line)) { | ||||
|         struct_stat file; | ||||
|         if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode)) | ||||
|           *size += file.st_size; | ||||
|           *size += filesize(newform->line, file); | ||||
|         else | ||||
|           return CURLE_BAD_FUNCTION_ARGUMENT; | ||||
|       } | ||||
| @@ -1101,7 +1164,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, | ||||
|   if(!post) | ||||
|     return result; /* no input => no output! */ | ||||
|  | ||||
|   boundary = formboundary(); | ||||
|   boundary = formboundary(data); | ||||
|   if(!boundary) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
| @@ -1157,7 +1220,7 @@ CURLcode Curl_getformdata(struct SessionHandle *data, | ||||
|          the magic to include several files with the same field name */ | ||||
|  | ||||
|       Curl_safefree(fileboundary); | ||||
|       fileboundary = formboundary(); | ||||
|       fileboundary = formboundary(data); | ||||
|       if(!fileboundary) { | ||||
|         result = CURLE_OUT_OF_MEMORY; | ||||
|         break; | ||||
| @@ -1343,6 +1406,36 @@ int Curl_FormInit(struct Form *form, struct FormData *formdata ) | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| #ifndef __VMS | ||||
| # define fopen_read fopen | ||||
| #else | ||||
|   /* | ||||
|    * vmsfopenread | ||||
|    * | ||||
|    * For upload to work as expected on VMS, different optional | ||||
|    * parameters must be added to the fopen command based on | ||||
|    * record format of the file. | ||||
|    * | ||||
|    */ | ||||
| # define fopen_read vmsfopenread | ||||
| static FILE * vmsfopenread(const char *file, const char *mode) { | ||||
|   struct_stat statbuf; | ||||
|   int result; | ||||
|  | ||||
|   result = stat(file, &statbuf); | ||||
|  | ||||
|   switch (statbuf.st_fab_rfm) { | ||||
|   case FAB$C_VAR: | ||||
|   case FAB$C_VFC: | ||||
|   case FAB$C_STMCR: | ||||
|     return fopen(file, "r"); | ||||
|     break; | ||||
|   default: | ||||
|     return fopen(file, "r", "rfm=stmlf", "ctx=stm"); | ||||
|   } | ||||
| } | ||||
| #endif | ||||
|  | ||||
| /* | ||||
|  * readfromfile() | ||||
|  * | ||||
| @@ -1365,7 +1458,7 @@ static size_t readfromfile(struct Form *form, char *buffer, | ||||
|   else { | ||||
|     if(!form->fp) { | ||||
|       /* this file hasn't yet been opened */ | ||||
|       form->fp = fopen(form->data->line, "rb"); /* b is for binary */ | ||||
|       form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */ | ||||
|       if(!form->fp) | ||||
|         return (size_t)-1; /* failure */ | ||||
|     } | ||||
| @@ -1464,28 +1557,12 @@ char *Curl_formpostheader(void *formp, size_t *len) | ||||
|  * formboundary() creates a suitable boundary string and returns an allocated | ||||
|  * one. | ||||
|  */ | ||||
| static char *formboundary(void) | ||||
| static char *formboundary(struct SessionHandle *data) | ||||
| { | ||||
|   char *retstring; | ||||
|   size_t i; | ||||
|  | ||||
|   static const char table16[]="0123456789abcdef"; | ||||
|  | ||||
|   retstring = malloc(BOUNDARY_LENGTH+1); | ||||
|  | ||||
|   if(!retstring) | ||||
|     return NULL; /* failed */ | ||||
|  | ||||
|   strcpy(retstring, "----------------------------"); | ||||
|  | ||||
|   for(i=strlen(retstring); i<BOUNDARY_LENGTH; i++) | ||||
|     retstring[i] = table16[Curl_rand()%16]; | ||||
|  | ||||
|   /* 28 dashes and 12 hexadecimal digits makes 12^16 (184884258895036416) | ||||
|   /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615) | ||||
|      combinations */ | ||||
|   retstring[BOUNDARY_LENGTH]=0; /* zero terminate */ | ||||
|  | ||||
|   return retstring; | ||||
|   return aprintf("------------------------%08x%08x", | ||||
|                  Curl_rand(data), Curl_rand(data)); | ||||
| } | ||||
|  | ||||
| #else  /* CURL_DISABLE_HTTP */ | ||||
|   | ||||
							
								
								
									
										183
									
								
								lib/ftp.c
									
									
									
									
									
								
							
							
						
						
									
										183
									
								
								lib/ftp.c
									
									
									
									
									
								
							| @@ -123,8 +123,8 @@ static void ftp_pasv_verbose(struct connectdata *conn, | ||||
|                              char *newhost, /* ascii version */ | ||||
|                              int port); | ||||
| #endif | ||||
| static CURLcode ftp_state_post_rest(struct connectdata *conn); | ||||
| static CURLcode ftp_state_post_cwd(struct connectdata *conn); | ||||
| static CURLcode ftp_state_prepare_transfer(struct connectdata *conn); | ||||
| static CURLcode ftp_state_mdtm(struct connectdata *conn); | ||||
| static CURLcode ftp_state_quote(struct connectdata *conn, | ||||
|                                 bool init, ftpstate instate); | ||||
| static CURLcode ftp_nb_type(struct connectdata *conn, | ||||
| @@ -136,7 +136,7 @@ static CURLcode ftp_done(struct connectdata *conn, | ||||
|                          CURLcode, bool premature); | ||||
| static CURLcode ftp_connect(struct connectdata *conn, bool *done); | ||||
| static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection); | ||||
| static CURLcode ftp_do_more(struct connectdata *conn, bool *completed); | ||||
| static CURLcode ftp_do_more(struct connectdata *conn, int *completed); | ||||
| static CURLcode ftp_multi_statemach(struct connectdata *conn, bool *done); | ||||
| static int ftp_getsock(struct connectdata *conn, curl_socket_t *socks, | ||||
|                        int numsocks); | ||||
| @@ -151,8 +151,7 @@ static CURLcode wc_statemach(struct connectdata *conn); | ||||
|  | ||||
| static void wc_data_dtor(void *ptr); | ||||
|  | ||||
| static CURLcode ftp_state_post_retr_size(struct connectdata *conn, | ||||
|                                          curl_off_t filesize); | ||||
| static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize); | ||||
|  | ||||
| static CURLcode ftp_readresp(curl_socket_t sockfd, | ||||
|                              struct pingpong *pp, | ||||
| @@ -828,7 +827,7 @@ static void _state(struct connectdata *conn, | ||||
| #if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS) | ||||
|   if(ftpc->state != newstate) | ||||
|     infof(conn->data, "FTP %p (line %d) state change from %s to %s\n", | ||||
|           ftpc, lineno, names[ftpc->state], names[newstate]); | ||||
|           (void *)ftpc, lineno, names[ftpc->state], names[newstate]); | ||||
| #endif | ||||
|   ftpc->state = newstate; | ||||
| } | ||||
| @@ -851,7 +850,7 @@ static CURLcode ftp_state_pwd(struct connectdata *conn) | ||||
|   CURLcode result; | ||||
|  | ||||
|   /* send PWD to discover our entry point */ | ||||
|   PPSENDF(&conn->proto.ftpc.pp, "PWD", NULL); | ||||
|   PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD"); | ||||
|   state(conn, FTP_PWD); | ||||
|  | ||||
|   return CURLE_OK; | ||||
| @@ -915,7 +914,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) | ||||
|  | ||||
|   if(ftpc->cwddone) | ||||
|     /* already done and fine */ | ||||
|     result = ftp_state_post_cwd(conn); | ||||
|     result = ftp_state_mdtm(conn); | ||||
|   else { | ||||
|     ftpc->count2 = 0; /* count2 counts failed CWDs */ | ||||
|  | ||||
| @@ -943,7 +942,7 @@ static CURLcode ftp_state_cwd(struct connectdata *conn) | ||||
|       } | ||||
|       else { | ||||
|         /* No CWD necessary */ | ||||
|         result = ftp_state_post_cwd(conn); | ||||
|         result = ftp_state_mdtm(conn); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| @@ -1373,10 +1372,14 @@ static CURLcode ftp_state_use_pasv(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* REST is the last command in the chain of commands when a "head"-like | ||||
|    request is made. Thus, if an actual transfer is to be made this is where | ||||
|    we take off for real. */ | ||||
| static CURLcode ftp_state_post_rest(struct connectdata *conn) | ||||
| /* | ||||
|  * ftp_state_prepare_transfer() starts PORT, PASV or PRET etc. | ||||
|  * | ||||
|  * REST is the last command in the chain of commands when a "head"-like | ||||
|  * request is made. Thus, if an actual transfer is to be made this is where we | ||||
|  * take off for real. | ||||
|  */ | ||||
| static CURLcode ftp_state_prepare_transfer(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct FTP *ftp = conn->data->state.proto.ftp; | ||||
| @@ -1419,7 +1422,7 @@ static CURLcode ftp_state_post_rest(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_size(struct connectdata *conn) | ||||
| static CURLcode ftp_state_rest(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct FTP *ftp = conn->data->state.proto.ftp; | ||||
| @@ -1435,12 +1438,12 @@ static CURLcode ftp_state_post_size(struct connectdata *conn) | ||||
|     state(conn, FTP_REST); | ||||
|   } | ||||
|   else | ||||
|     result = ftp_state_post_rest(conn); | ||||
|     result = ftp_state_prepare_transfer(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_type(struct connectdata *conn) | ||||
| static CURLcode ftp_state_size(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct FTP *ftp = conn->data->state.proto.ftp; | ||||
| @@ -1455,12 +1458,12 @@ static CURLcode ftp_state_post_type(struct connectdata *conn) | ||||
|     state(conn, FTP_SIZE); | ||||
|   } | ||||
|   else | ||||
|     result = ftp_state_post_size(conn); | ||||
|     result = ftp_state_rest(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_listtype(struct connectdata *conn) | ||||
| static CURLcode ftp_state_list(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
| @@ -1529,7 +1532,7 @@ static CURLcode ftp_state_post_listtype(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_retrtype(struct connectdata *conn) | ||||
| static CURLcode ftp_state_retr_prequote(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
| @@ -1540,7 +1543,7 @@ static CURLcode ftp_state_post_retrtype(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_stortype(struct connectdata *conn) | ||||
| static CURLcode ftp_state_stor_prequote(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
| @@ -1551,7 +1554,7 @@ static CURLcode ftp_state_post_stortype(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_mdtm(struct connectdata *conn) | ||||
| static CURLcode ftp_state_type(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct FTP *ftp = conn->data->state.proto.ftp; | ||||
| @@ -1577,14 +1580,14 @@ static CURLcode ftp_state_post_mdtm(struct connectdata *conn) | ||||
|       return result; | ||||
|   } | ||||
|   else | ||||
|     result = ftp_state_post_type(conn); | ||||
|     result = ftp_state_size(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* This is called after the CWD commands have been done in the beginning of | ||||
|    the DO phase */ | ||||
| static CURLcode ftp_state_post_cwd(struct connectdata *conn) | ||||
| static CURLcode ftp_state_mdtm(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
| @@ -1600,7 +1603,7 @@ static CURLcode ftp_state_post_cwd(struct connectdata *conn) | ||||
|     state(conn, FTP_MDTM); | ||||
|   } | ||||
|   else | ||||
|     result = ftp_state_post_mdtm(conn); | ||||
|     result = ftp_state_type(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
| @@ -1775,7 +1778,7 @@ static CURLcode ftp_state_quote(struct connectdata *conn, | ||||
|       else { | ||||
|         if(ftpc->known_filesize != -1) { | ||||
|           Curl_pgrsSetDownloadSize(data, ftpc->known_filesize); | ||||
|           result = ftp_state_post_retr_size(conn, ftpc->known_filesize); | ||||
|           result = ftp_state_retr(conn, ftpc->known_filesize); | ||||
|         } | ||||
|         else { | ||||
|           PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file); | ||||
| @@ -1799,15 +1802,15 @@ static CURLcode ftp_state_quote(struct connectdata *conn, | ||||
| static CURLcode ftp_epsv_disable(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   infof(conn->data, "got positive EPSV response, but can't connect. " | ||||
|         "Disabling EPSV\n"); | ||||
|   infof(conn->data, "Failed EPSV attempt. Disabling EPSV\n"); | ||||
|   /* disable it for next transfer */ | ||||
|   conn->bits.ftp_use_epsv = FALSE; | ||||
|   conn->data->state.errorbuf = FALSE; /* allow error message to get | ||||
|                                          rewritten */ | ||||
|   PPSENDF(&conn->proto.ftpc.pp, "PASV", NULL); | ||||
|   PPSENDF(&conn->proto.ftpc.pp, "%s", "PASV"); | ||||
|   conn->proto.ftpc.count1++; | ||||
|   /* remain in the FTP_PASV state */ | ||||
|   /* remain in/go to the FTP_PASV state */ | ||||
|   state(conn, FTP_PASV); | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| @@ -1936,28 +1939,18 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, | ||||
|   } | ||||
|   else if(ftpc->count1 == 0) { | ||||
|     /* EPSV failed, move on to PASV */ | ||||
|  | ||||
|     /* disable it for next transfer */ | ||||
|     conn->bits.ftp_use_epsv = FALSE; | ||||
|     infof(data, "disabling EPSV usage\n"); | ||||
|  | ||||
|     PPSENDF(&ftpc->pp, "PASV", NULL); | ||||
|     ftpc->count1++; | ||||
|     /* remain in the FTP_PASV state */ | ||||
|     return result; | ||||
|     return ftp_epsv_disable(conn); | ||||
|   } | ||||
|   else { | ||||
|     failf(data, "Bad PASV/EPSV response: %03d", ftpcode); | ||||
|     return CURLE_FTP_WEIRD_PASV_REPLY; | ||||
|   } | ||||
|  | ||||
|   if(data->set.str[STRING_PROXY] && *data->set.str[STRING_PROXY]) { | ||||
|   if(conn->bits.proxy) { | ||||
|     /* | ||||
|      * This is a tunnel through a http proxy and we need to connect to the | ||||
|      * proxy again here. | ||||
|      * | ||||
|      * We don't want to rely on a former host lookup that might've expired | ||||
|      * now, instead we remake the lookup here and now! | ||||
|      * This connection uses a proxy and we need to connect to the proxy again | ||||
|      * here. We don't want to rely on a former host lookup that might've | ||||
|      * expired now, instead we remake the lookup here and now! | ||||
|      */ | ||||
|     rc = Curl_resolv(conn, conn->proxy.name, (int)conn->port, &addr); | ||||
|     if(rc == CURLRESOLV_PENDING) | ||||
| @@ -2023,14 +2016,17 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, | ||||
|   case CURLPROXY_SOCKS5_HOSTNAME: | ||||
|     result = Curl_SOCKS5(conn->proxyuser, conn->proxypasswd, newhost, newport, | ||||
|                          SECONDARYSOCKET, conn); | ||||
|     connected = TRUE; | ||||
|     break; | ||||
|   case CURLPROXY_SOCKS4: | ||||
|     result = Curl_SOCKS4(conn->proxyuser, newhost, newport, | ||||
|                          SECONDARYSOCKET, conn, FALSE); | ||||
|     connected = TRUE; | ||||
|     break; | ||||
|   case CURLPROXY_SOCKS4A: | ||||
|     result = Curl_SOCKS4(conn->proxyuser, newhost, newport, | ||||
|                          SECONDARYSOCKET, conn, TRUE); | ||||
|     connected = TRUE; | ||||
|     break; | ||||
|   case CURLPROXY_HTTP: | ||||
|   case CURLPROXY_HTTP_1_0: | ||||
| @@ -2082,8 +2078,7 @@ static CURLcode ftp_state_pasv_resp(struct connectdata *conn, | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE; | ||||
|  | ||||
|   conn->bits.tcpconnect[SECONDARYSOCKET] = connected; | ||||
|   conn->bits.do_more = TRUE; | ||||
|   state(conn, FTP_STOP); /* this phase is completed */ | ||||
|  | ||||
| @@ -2223,7 +2218,7 @@ static CURLcode ftp_state_mdtm_resp(struct connectdata *conn, | ||||
|   } | ||||
|  | ||||
|   if(!result) | ||||
|     result = ftp_state_post_mdtm(conn); | ||||
|     result = ftp_state_type(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
| @@ -2247,18 +2242,18 @@ static CURLcode ftp_state_type_resp(struct connectdata *conn, | ||||
|           ftpcode); | ||||
|  | ||||
|   if(instate == FTP_TYPE) | ||||
|     result = ftp_state_post_type(conn); | ||||
|     result = ftp_state_size(conn); | ||||
|   else if(instate == FTP_LIST_TYPE) | ||||
|     result = ftp_state_post_listtype(conn); | ||||
|     result = ftp_state_list(conn); | ||||
|   else if(instate == FTP_RETR_TYPE) | ||||
|     result = ftp_state_post_retrtype(conn); | ||||
|     result = ftp_state_retr_prequote(conn); | ||||
|   else if(instate == FTP_STOR_TYPE) | ||||
|     result = ftp_state_post_stortype(conn); | ||||
|     result = ftp_state_stor_prequote(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode ftp_state_post_retr_size(struct connectdata *conn, | ||||
| static CURLcode ftp_state_retr(struct connectdata *conn, | ||||
|                                          curl_off_t filesize) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
| @@ -2363,11 +2358,11 @@ static CURLcode ftp_state_size_resp(struct connectdata *conn, | ||||
|     } | ||||
| #endif | ||||
|     Curl_pgrsSetDownloadSize(data, filesize); | ||||
|     result = ftp_state_post_size(conn); | ||||
|     result = ftp_state_rest(conn); | ||||
|   } | ||||
|   else if(instate == FTP_RETR_SIZE) { | ||||
|     Curl_pgrsSetDownloadSize(data, filesize); | ||||
|     result = ftp_state_post_retr_size(conn, filesize); | ||||
|     result = ftp_state_retr(conn, filesize); | ||||
|   } | ||||
|   else if(instate == FTP_STOR_SIZE) { | ||||
|     data->state.resume_from = filesize; | ||||
| @@ -2395,7 +2390,7 @@ static CURLcode ftp_state_rest_resp(struct connectdata *conn, | ||||
|         return result; | ||||
|     } | ||||
| #endif | ||||
|     result = ftp_state_post_rest(conn); | ||||
|     result = ftp_state_prepare_transfer(conn); | ||||
|     break; | ||||
|  | ||||
|   case FTP_RETR_REST: | ||||
| @@ -2711,7 +2706,10 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) | ||||
|     /* we have now received a full FTP server response */ | ||||
|     switch(ftpc->state) { | ||||
|     case FTP_WAIT220: | ||||
|       if(ftpcode != 220) { | ||||
|       if(ftpcode == 230) | ||||
|         /* 230 User logged in - already! */ | ||||
|         return ftp_state_user_resp(conn, ftpcode, ftpc->state); | ||||
|       else if(ftpcode != 220) { | ||||
|         failf(data, "Got a %03d ftp-server response when 220 was expected", | ||||
|               ftpcode); | ||||
|         return CURLE_FTP_WEIRD_SERVER_REPLY; | ||||
| @@ -2833,7 +2831,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) | ||||
|       if(data->set.ftp_ccc) { | ||||
|         /* CCC - Clear Command Channel | ||||
|          */ | ||||
|         PPSENDF(&ftpc->pp, "CCC", NULL); | ||||
|         PPSENDF(&ftpc->pp, "%s", "CCC"); | ||||
|         state(conn, FTP_CCC); | ||||
|       } | ||||
|       else { | ||||
| @@ -2920,7 +2918,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) | ||||
|  | ||||
|           if(!ftpc->server_os && dir[0] != '/') { | ||||
|  | ||||
|             result = Curl_pp_sendf(&ftpc->pp, "SYST", NULL); | ||||
|             result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST"); | ||||
|             if(result != CURLE_OK) { | ||||
|               free(dir); | ||||
|               return result; | ||||
| @@ -2973,7 +2971,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) | ||||
|  | ||||
|         if(strequal(os, "OS/400")) { | ||||
|           /* Force OS400 name format 1. */ | ||||
|           result = Curl_pp_sendf(&ftpc->pp, "SITE NAMEFMT 1", NULL); | ||||
|           result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1"); | ||||
|           if(result != CURLE_OK) { | ||||
|             free(os); | ||||
|             return result; | ||||
| @@ -3051,7 +3049,7 @@ static CURLcode ftp_statemach_act(struct connectdata *conn) | ||||
|           PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]); | ||||
|         } | ||||
|         else { | ||||
|           result = ftp_state_post_cwd(conn); | ||||
|           result = ftp_state_mdtm(conn); | ||||
|           if(result) | ||||
|             return result; | ||||
|         } | ||||
| @@ -3215,8 +3213,8 @@ static CURLcode ftp_init(struct connectdata *conn) | ||||
|  * 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. | ||||
|  * phase is done when this function returns, or FALSE if not. | ||||
|  * | ||||
|  */ | ||||
| static CURLcode ftp_connect(struct connectdata *conn, | ||||
|                                  bool *done) /* see description above */ | ||||
| @@ -3382,7 +3380,7 @@ static CURLcode ftp_done(struct connectdata *conn, CURLcode status, | ||||
|   if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) { | ||||
|     if(!result && ftpc->dont_check && data->req.maxdownload > 0) { | ||||
|       /* partial download completed */ | ||||
|       result = Curl_pp_sendf(pp, "ABOR"); | ||||
|       result = Curl_pp_sendf(pp, "%s", "ABOR"); | ||||
|       if(result) { | ||||
|         failf(data, "Failure sending ABOR command: %s", | ||||
|               curl_easy_strerror(result)); | ||||
| @@ -3676,20 +3674,23 @@ static CURLcode ftp_range(struct connectdata *conn) | ||||
|  * | ||||
|  * This function shall be called when the second FTP (data) connection is | ||||
|  * connected. | ||||
|  * | ||||
|  * 'complete' can return 0 for incomplete, 1 for done and -1 for go back | ||||
|  * (which basically is only for when PASV is being sent to retry a failed | ||||
|  * EPSV). | ||||
|  */ | ||||
|  | ||||
| static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
| static CURLcode ftp_do_more(struct connectdata *conn, int *completep) | ||||
| { | ||||
|   struct SessionHandle *data=conn->data; | ||||
|   struct ftp_conn *ftpc = &conn->proto.ftpc; | ||||
|   CURLcode result = CURLE_OK; | ||||
|   bool connected = FALSE; | ||||
|   bool complete = FALSE; | ||||
|  | ||||
|   /* the ftp struct is inited in ftp_connect() */ | ||||
|   struct FTP *ftp = data->state.proto.ftp; | ||||
|  | ||||
|   *complete = FALSE; | ||||
|  | ||||
|   /* if the second connection isn't done yet, wait for it */ | ||||
|   if(!conn->bits.tcpconnect[SECONDARYSOCKET]) { | ||||
|     if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) { | ||||
| @@ -3706,14 +3707,22 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|     if(connected) { | ||||
|       DEBUGF(infof(data, "DO-MORE connected phase starts\n")); | ||||
|     } | ||||
|     else | ||||
|     else { | ||||
|       if(result && (ftpc->count1 == 0)) { | ||||
|         *completep = -1; /* go back to DOING please */ | ||||
|         /* this is a EPSV connect failing, try PASV instead */ | ||||
|         return ftp_epsv_disable(conn); | ||||
|       } | ||||
|       return result; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if(ftpc->state) { | ||||
|     /* already in a state so skip the intial commands. | ||||
|        They are only done to kickstart the do_more state */ | ||||
|     result = ftp_multi_statemach(conn, complete); | ||||
|     result = ftp_multi_statemach(conn, &complete); | ||||
|  | ||||
|     *completep = (int)complete; | ||||
|  | ||||
|     /* if we got an error or if we don't wait for a data connection return | ||||
|        immediately */ | ||||
| @@ -3724,7 +3733,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|       /* if we reach the end of the FTP state machine here, *complete will be | ||||
|          TRUE but so is ftpc->wait_data_conn, which says we need to wait for | ||||
|          the data connection and therefore we're not actually complete */ | ||||
|       *complete = FALSE; | ||||
|       *completep = 0; | ||||
|   } | ||||
|  | ||||
|   if(ftp->transfer <= FTPTRANSFER_INFO) { | ||||
| @@ -3747,6 +3756,9 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|  | ||||
|         if(result) | ||||
|           return result; | ||||
|  | ||||
|         *completep = 1; /* this state is now complete when the server has | ||||
|                            connected back to us */ | ||||
|       } | ||||
|     } | ||||
|     else if(data->set.upload) { | ||||
| @@ -3754,7 +3766,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|       if(result) | ||||
|         return result; | ||||
|  | ||||
|       result = ftp_multi_statemach(conn, complete); | ||||
|       result = ftp_multi_statemach(conn, &complete); | ||||
|       *completep = (int)complete; | ||||
|     } | ||||
|     else { | ||||
|       /* download */ | ||||
| @@ -3782,7 +3795,8 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|           return result; | ||||
|       } | ||||
|  | ||||
|       result = ftp_multi_statemach(conn, complete); | ||||
|       result = ftp_multi_statemach(conn, &complete); | ||||
|       *completep = (int)complete; | ||||
|     } | ||||
|     return result; | ||||
|   } | ||||
| @@ -3794,7 +3808,7 @@ static CURLcode ftp_do_more(struct connectdata *conn, bool *complete) | ||||
|  | ||||
|   if(!ftpc->wait_data_conn) { | ||||
|     /* no waiting for the data connection so this is now complete */ | ||||
|     *complete = TRUE; | ||||
|     *completep = 1; | ||||
|     DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result)); | ||||
|   } | ||||
|  | ||||
| @@ -3837,7 +3851,9 @@ CURLcode ftp_perform(struct connectdata *conn, | ||||
|   /* run the state-machine */ | ||||
|   result = ftp_multi_statemach(conn, dophase_done); | ||||
|  | ||||
|   *connected = conn->bits.tcpconnect[FIRSTSOCKET]; | ||||
|   *connected = conn->bits.tcpconnect[SECONDARYSOCKET]; | ||||
|  | ||||
|   infof(conn->data, "ftp_perform ends with SECONDARY: %d\n", *connected); | ||||
|  | ||||
|   if(*dophase_done) | ||||
|     DEBUGF(infof(conn->data, "DO phase is complete1\n")); | ||||
| @@ -4188,7 +4204,7 @@ static CURLcode ftp_quit(struct connectdata *conn) | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
|   if(conn->proto.ftpc.ctl_valid) { | ||||
|     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "QUIT", NULL); | ||||
|     result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", "QUIT"); | ||||
|     if(result) { | ||||
|       failf(conn->data, "Failure sending QUIT command: %s", | ||||
|             curl_easy_strerror(result)); | ||||
| @@ -4316,13 +4332,17 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) | ||||
|     } | ||||
|     slash_pos=strrchr(cur_pos, '/'); | ||||
|     if(slash_pos || !*cur_pos) { | ||||
|       size_t dirlen = slash_pos-cur_pos; | ||||
|  | ||||
|       ftpc->dirs = calloc(1, sizeof(ftpc->dirs[0])); | ||||
|       if(!ftpc->dirs) | ||||
|         return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|       if(!dirlen) | ||||
|         dirlen++; | ||||
|  | ||||
|       ftpc->dirs[0] = curl_easy_unescape(conn->data, slash_pos ? cur_pos : "/", | ||||
|                                          slash_pos ? | ||||
|                                          curlx_sztosi(slash_pos-cur_pos) : 1, | ||||
|                                          slash_pos ? curlx_sztosi(dirlen) : 1, | ||||
|                                          NULL); | ||||
|       if(!ftpc->dirs[0]) { | ||||
|         freedirs(ftpc); | ||||
| @@ -4377,6 +4397,15 @@ CURLcode ftp_parse_url_path(struct connectdata *conn) | ||||
|         } | ||||
|         else { | ||||
|           cur_pos = slash_pos + 1; /* jump to the rest of the string */ | ||||
|           if(!ftpc->dirdepth) { | ||||
|             /* path starts with a slash, add that as a directory */ | ||||
|             ftpc->dirs[ftpc->dirdepth] = strdup("/"); | ||||
|             if(!ftpc->dirs[ftpc->dirdepth++]) { /* run out of memory ... */ | ||||
|               failf(data, "no memory"); | ||||
|               freedirs(ftpc); | ||||
|               return CURLE_OUT_OF_MEMORY; | ||||
|             } | ||||
|           } | ||||
|           continue; | ||||
|         } | ||||
|  | ||||
| @@ -4452,7 +4481,7 @@ static CURLcode ftp_dophase_done(struct connectdata *conn, | ||||
|   struct ftp_conn *ftpc = &conn->proto.ftpc; | ||||
|  | ||||
|   if(connected) { | ||||
|     bool completed; | ||||
|     int completed; | ||||
|     CURLcode result = ftp_do_more(conn, &completed); | ||||
|  | ||||
|     if(result) { | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -53,8 +53,9 @@ CURLcode Curl_initinfo(struct SessionHandle *data) | ||||
|   pro->t_redirect = 0; | ||||
|  | ||||
|   info->httpcode = 0; | ||||
|   info->httpversion=0; | ||||
|   info->filetime=-1; /* -1 is an illegal time and thus means unknown */ | ||||
|   info->httpversion = 0; | ||||
|   info->filetime = -1; /* -1 is an illegal time and thus means unknown */ | ||||
|   info->timecond = FALSE; | ||||
|  | ||||
|   if(info->contenttype) | ||||
|     free(info->contenttype); | ||||
| @@ -185,7 +186,7 @@ static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info, | ||||
|     break; | ||||
|   case CURLINFO_CONDITION_UNMET: | ||||
|     /* return if the condition prevented the document to get transferred */ | ||||
|     *param_longp = data->info.timecond; | ||||
|     *param_longp = data->info.timecond ? 1L : 0L; | ||||
|     break; | ||||
|   case CURLINFO_RTSP_CLIENT_CSEQ: | ||||
|     *param_longp = data->state.rtsp_next_client_CSeq; | ||||
|   | ||||
							
								
								
									
										906
									
								
								lib/gskit.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										906
									
								
								lib/gskit.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,906 @@ | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2013, 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 "curl_setup.h" | ||||
|  | ||||
| #ifdef USE_GSKIT | ||||
|  | ||||
| #include <gskssl.h> | ||||
| #include <qsoasync.h> | ||||
|  | ||||
| /* Some symbols are undefined/unsupported on OS400 versions < V7R1. */ | ||||
| #ifndef GSK_SSL_EXTN_SERVERNAME_REQUEST | ||||
| #define GSK_SSL_EXTN_SERVERNAME_REQUEST                 230 | ||||
| #endif | ||||
|  | ||||
| #ifdef HAVE_LIMITS_H | ||||
| #  include <limits.h> | ||||
| #endif | ||||
|  | ||||
| #include <curl/curl.h> | ||||
| #include "urldata.h" | ||||
| #include "sendf.h" | ||||
| #include "gskit.h" | ||||
| #include "sslgen.h" | ||||
| #include "connect.h" /* for the connect timeout */ | ||||
| #include "select.h" | ||||
| #include "strequal.h" | ||||
| #include "x509asn1.h" | ||||
|  | ||||
| #define _MPRINTF_REPLACE /* use our functions only */ | ||||
| #include <curl/mprintf.h> | ||||
|  | ||||
| #include "curl_memory.h" | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
|  | ||||
|  | ||||
| /* Supported ciphers. */ | ||||
| typedef struct { | ||||
|   const char *  name;           /* Cipher name. */ | ||||
|   const char *  gsktoken;       /* Corresponding token for GSKit String. */ | ||||
|   int           sslver;         /* SSL version. */ | ||||
| }  gskit_cipher; | ||||
|  | ||||
| static const gskit_cipher  ciphertable[] = { | ||||
|   { "null-md5",         "01",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "null-sha",         "02",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "exp-rc4-md5",      "03",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "rc4-md5",          "04",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "rc4-sha",          "05",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "exp-rc2-cbc-md5",  "06",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "exp-des-cbc-sha",  "09",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "des-cbc3-sha",     "0A",   CURL_SSLVERSION_SSLv3 }, | ||||
|   { "aes128-sha",       "2F",   CURL_SSLVERSION_TLSv1 }, | ||||
|   { "aes256-sha",       "35",   CURL_SSLVERSION_TLSv1 }, | ||||
|   { "rc4-md5",          "1",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { "exp-rc4-md5",      "2",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { "rc2-md5",          "3",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { "exp-rc2-md5",      "4",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { "des-cbc-md5",      "6",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { "des-cbc3-md5",     "7",    CURL_SSLVERSION_SSLv2 }, | ||||
|   { (const char *) NULL, (const char *) NULL, 0       } | ||||
| }; | ||||
|  | ||||
|  | ||||
| static bool is_separator(char c) | ||||
| { | ||||
|   /* Return whether character is a cipher list separator. */ | ||||
|   switch (c) { | ||||
|   case ' ': | ||||
|   case '\t': | ||||
|   case ':': | ||||
|   case ',': | ||||
|   case ';': | ||||
|     return true; | ||||
|   } | ||||
|   return false; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode gskit_status(struct SessionHandle * data, int rc, | ||||
|                              const char * procname, CURLcode defcode) | ||||
| { | ||||
|   CURLcode cc; | ||||
|  | ||||
|   /* Process GSKit status and map it to a CURLcode. */ | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|   case GSK_OS400_ASYNCHRONOUS_SOC_INIT: | ||||
|     return CURLE_OK; | ||||
|   case GSK_KEYRING_OPEN_ERROR: | ||||
|   case GSK_OS400_ERROR_NO_ACCESS: | ||||
|     return CURLE_SSL_CACERT_BADFILE; | ||||
|   case GSK_INSUFFICIENT_STORAGE: | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   case GSK_ERROR_BAD_V2_CIPHER: | ||||
|   case GSK_ERROR_BAD_V3_CIPHER: | ||||
|   case GSK_ERROR_NO_CIPHERS: | ||||
|     return CURLE_SSL_CIPHER; | ||||
|   case GSK_OS400_ERROR_NOT_TRUSTED_ROOT: | ||||
|   case GSK_ERROR_CERT_VALIDATION: | ||||
|     return CURLE_PEER_FAILED_VERIFICATION; | ||||
|   case GSK_OS400_ERROR_TIMED_OUT: | ||||
|     return CURLE_OPERATION_TIMEDOUT; | ||||
|   case GSK_WOULD_BLOCK: | ||||
|     return CURLE_AGAIN; | ||||
|   case GSK_OS400_ERROR_NOT_REGISTERED: | ||||
|     break; | ||||
|   case GSK_ERROR_IO: | ||||
|     switch (errno) { | ||||
|     case ENOMEM: | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     default: | ||||
|       failf(data, "%s I/O error: %s", procname, strerror(errno)); | ||||
|       break; | ||||
|     } | ||||
|     break; | ||||
|   default: | ||||
|     failf(data, "%s: %s", procname, gsk_strerror(rc)); | ||||
|     break; | ||||
|     } | ||||
|   return defcode; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode set_enum(struct SessionHandle * data, | ||||
|                          gsk_handle h, GSK_ENUM_ID id, GSK_ENUM_VALUE value) | ||||
| { | ||||
|   int rc = gsk_attribute_set_enum(h, id, value); | ||||
|  | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|     return CURLE_OK; | ||||
|   case GSK_ERROR_IO: | ||||
|     failf(data, "gsk_attribute_set_enum() I/O error: %s", strerror(errno)); | ||||
|     break; | ||||
|   default: | ||||
|     failf(data, "gsk_attribute_set_enum(): %s", gsk_strerror(rc)); | ||||
|     break; | ||||
|   } | ||||
|   return CURLE_SSL_CONNECT_ERROR; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode set_buffer(struct SessionHandle * data, | ||||
|                            gsk_handle h, GSK_BUF_ID id, const char * buffer) | ||||
| { | ||||
|   int rc = gsk_attribute_set_buffer(h, id, buffer, 0); | ||||
|  | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|     return CURLE_OK; | ||||
|   case GSK_ERROR_IO: | ||||
|     failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); | ||||
|     break; | ||||
|   default: | ||||
|     failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); | ||||
|     break; | ||||
|   } | ||||
|   return CURLE_SSL_CONNECT_ERROR; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode set_numeric(struct SessionHandle * data, | ||||
|                             gsk_handle h, GSK_NUM_ID id, int value) | ||||
| { | ||||
|   int rc = gsk_attribute_set_numeric_value(h, id, value); | ||||
|  | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|     return CURLE_OK; | ||||
|   case GSK_ERROR_IO: | ||||
|     failf(data, "gsk_attribute_set_numeric_value() I/O error: %s", | ||||
|           strerror(errno)); | ||||
|     break; | ||||
|   default: | ||||
|     failf(data, "gsk_attribute_set_numeric_value(): %s", gsk_strerror(rc)); | ||||
|     break; | ||||
|   } | ||||
|   return CURLE_SSL_CONNECT_ERROR; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode set_callback(struct SessionHandle * data, | ||||
|                              gsk_handle h, GSK_CALLBACK_ID id, void * info) | ||||
| { | ||||
|   int rc = gsk_attribute_set_callback(h, id, info); | ||||
|  | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|     return CURLE_OK; | ||||
|   case GSK_ERROR_IO: | ||||
|     failf(data, "gsk_attribute_set_callback() I/O error: %s", strerror(errno)); | ||||
|     break; | ||||
|   default: | ||||
|     failf(data, "gsk_attribute_set_callback(): %s", gsk_strerror(rc)); | ||||
|     break; | ||||
|   } | ||||
|   return CURLE_SSL_CONNECT_ERROR; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode set_ciphers(struct SessionHandle * data, gsk_handle h) | ||||
| { | ||||
|   const char * cipherlist = data->set.str[STRING_SSL_CIPHER_LIST]; | ||||
|   char * sslv2ciphers; | ||||
|   char * sslv3ciphers; | ||||
|   const char * clp; | ||||
|   const gskit_cipher * ctp; | ||||
|   char * v2p; | ||||
|   char * v3p; | ||||
|   int i; | ||||
|   CURLcode cc; | ||||
|  | ||||
|   /* Compile cipher list into GSKit-compatible cipher lists. */ | ||||
|  | ||||
|   if(!cipherlist) | ||||
|     return CURLE_OK; | ||||
|   while(is_separator(*cipherlist))     /* Skip initial separators. */ | ||||
|     cipherlist++; | ||||
|   if(!*cipherlist) | ||||
|     return CURLE_OK; | ||||
|  | ||||
|   /* We allocate GSKit buffers of the same size as the input string: since | ||||
|      GSKit tokens are always shorter than their cipher names, allocated buffers | ||||
|      will always be large enough to accomodate the result. */ | ||||
|   i = strlen(cipherlist) + 1; | ||||
|   v2p = malloc(i); | ||||
|   if(!v2p) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   v3p = malloc(i); | ||||
|   if(!v3p) { | ||||
|     free(v2p); | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   } | ||||
|   sslv2ciphers = v2p; | ||||
|   sslv3ciphers = v3p; | ||||
|  | ||||
|   /* Process each cipher in input string. */ | ||||
|   for(;;) { | ||||
|     for(clp = cipherlist; *cipherlist && !is_separator(*cipherlist);) | ||||
|       cipherlist++; | ||||
|     i = cipherlist - clp; | ||||
|     if(!i) | ||||
|       break; | ||||
|     /* Search the cipher in our table. */ | ||||
|     for(ctp = ciphertable; ctp->name; ctp++) | ||||
|       if(strnequal(ctp->name, clp, i) && !ctp->name[i]) | ||||
|         break; | ||||
|     if(!ctp->name) | ||||
|       failf(data, "Unknown cipher %.*s: ignored", i, clp); | ||||
|     else { | ||||
|       switch (ctp->sslver) { | ||||
|       case CURL_SSLVERSION_SSLv2: | ||||
|         strcpy(v2p, ctp->gsktoken); | ||||
|         v2p += strlen(v2p); | ||||
|         break; | ||||
|       default: | ||||
|         /* GSKit wants TLSv1 ciphers with SSLv3 ciphers. */ | ||||
|         strcpy(v3p, ctp->gsktoken); | ||||
|         v3p += strlen(v3p); | ||||
|         break; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|    /* Advance to next cipher name or end of string. */ | ||||
|     while(is_separator(*cipherlist)) | ||||
|       cipherlist++; | ||||
|   } | ||||
|   *v2p = '\0'; | ||||
|   *v3p = '\0'; | ||||
|   cc = set_buffer(data, h, GSK_V2_CIPHER_SPECS, sslv2ciphers); | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_buffer(data, h, GSK_V3_CIPHER_SPECS, sslv3ciphers); | ||||
|   free(sslv2ciphers); | ||||
|   free(sslv3ciphers); | ||||
|   return cc; | ||||
| } | ||||
|  | ||||
|  | ||||
| int Curl_gskit_init(void) | ||||
| { | ||||
|   /* No initialisation needed. */ | ||||
|  | ||||
|   return 1; | ||||
| } | ||||
|  | ||||
|  | ||||
| void Curl_gskit_cleanup(void) | ||||
| { | ||||
|   /* Nothing to do. */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode init_environment(struct SessionHandle * data, | ||||
|                                  gsk_handle * envir, const char * appid, | ||||
|                                  const char * file, const char * label, | ||||
|                                  const char * password) | ||||
| { | ||||
|   int rc; | ||||
|   CURLcode c; | ||||
|   gsk_handle h; | ||||
|  | ||||
|   /* Creates the GSKit environment. */ | ||||
|  | ||||
|   rc = gsk_environment_open(&h); | ||||
|   switch (rc) { | ||||
|   case GSK_OK: | ||||
|     break; | ||||
|   case GSK_INSUFFICIENT_STORAGE: | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   default: | ||||
|     failf(data, "gsk_environment_open(): %s", gsk_strerror(rc)); | ||||
|     return CURLE_SSL_CONNECT_ERROR; | ||||
|   } | ||||
|  | ||||
|   c = set_enum(data, h, GSK_SESSION_TYPE, GSK_CLIENT_SESSION); | ||||
|   if(c == CURLE_OK && appid) | ||||
|     c = set_buffer(data, h, GSK_OS400_APPLICATION_ID, appid); | ||||
|   if(c == CURLE_OK && file) | ||||
|     c = set_buffer(data, h, GSK_KEYRING_FILE, file); | ||||
|   if(c == CURLE_OK && label) | ||||
|     c = set_buffer(data, h, GSK_KEYRING_LABEL, label); | ||||
|   if(c == CURLE_OK && password) | ||||
|     c = set_buffer(data, h, GSK_KEYRING_PW, password); | ||||
|  | ||||
|   if(c == CURLE_OK) { | ||||
|     /* Locate CAs, Client certificate and key according to our settings. | ||||
|        Note: this call may be blocking for some tenths of seconds. */ | ||||
|     c = gskit_status(data, gsk_environment_init(h), | ||||
|                      "gsk_environment_init()", CURLE_SSL_CERTPROBLEM); | ||||
|     if(c == CURLE_OK) { | ||||
|       *envir = h; | ||||
|       return c; | ||||
|     } | ||||
|   } | ||||
|   /* Error: rollback. */ | ||||
|   gsk_environment_close(&h); | ||||
|   return c; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void cancel_async_handshake(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   Qso_OverlappedIO_t cstat; | ||||
|  | ||||
|   if(QsoCancelOperation(conn->sock[sockindex], 0) > 0) | ||||
|     QsoWaitForIOCompletion(connssl->iocport, &cstat, (struct timeval *) NULL); | ||||
| } | ||||
|  | ||||
|  | ||||
| static void close_async_handshake(struct ssl_connect_data * connssl) | ||||
| { | ||||
|   QsoDestroyIOCompletionPort(connssl->iocport); | ||||
|   connssl->iocport = -1; | ||||
| } | ||||
|  | ||||
|  | ||||
| static void close_one(struct ssl_connect_data * conn, | ||||
|                       struct SessionHandle * data) | ||||
| { | ||||
|   if(conn->handle) { | ||||
|     gskit_status(data, gsk_secure_soc_close(&conn->handle), | ||||
|               "gsk_secure_soc_close()", 0); | ||||
|     conn->handle = (gsk_handle) NULL; | ||||
|   } | ||||
|   if(conn->iocport >= 0) | ||||
|     close_async_handshake(conn); | ||||
| } | ||||
|  | ||||
|  | ||||
| static ssize_t gskit_send(struct connectdata * conn, int sockindex, | ||||
|                            const void * mem, size_t len, CURLcode * curlcode) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   CURLcode cc; | ||||
|   int written; | ||||
|  | ||||
|   cc = gskit_status(data, | ||||
|                     gsk_secure_soc_write(conn->ssl[sockindex].handle, | ||||
|                                          (char *) mem, (int) len, &written), | ||||
|                     "gsk_secure_soc_write()", CURLE_SEND_ERROR); | ||||
|   if(cc != CURLE_OK) { | ||||
|     *curlcode = cc; | ||||
|     written = -1; | ||||
|   } | ||||
|   return (ssize_t) written; /* number of bytes */ | ||||
| } | ||||
|  | ||||
|  | ||||
| static ssize_t gskit_recv(struct connectdata * conn, int num, char * buf, | ||||
|                            size_t buffersize, CURLcode * curlcode) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   int buffsize; | ||||
|   int nread; | ||||
|   CURLcode cc; | ||||
|  | ||||
|   buffsize = buffersize > (size_t) INT_MAX? INT_MAX: (int) buffersize; | ||||
|   cc = gskit_status(data, gsk_secure_soc_read(conn->ssl[num].handle, | ||||
|                                               buf, buffsize, &nread), | ||||
|                     "gsk_secure_soc_read()", CURLE_RECV_ERROR); | ||||
|   if(cc != CURLE_OK) { | ||||
|     *curlcode = cc; | ||||
|     nread = -1; | ||||
|   } | ||||
|   return (ssize_t) nread; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode gskit_connect_step1(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   gsk_handle envir; | ||||
|   CURLcode cc; | ||||
|   int rc; | ||||
|   char * keyringfile; | ||||
|   char * keyringpwd; | ||||
|   char * keyringlabel; | ||||
|   char * v2ciphers; | ||||
|   char * v3ciphers; | ||||
|   char * sni; | ||||
|   bool sslv2enable, sslv3enable, tlsv1enable; | ||||
|   long timeout; | ||||
|   Qso_OverlappedIO_t commarea; | ||||
|  | ||||
|   /* Create SSL environment, start (preferably asynchronous) handshake. */ | ||||
|  | ||||
|   connssl->handle = (gsk_handle) NULL; | ||||
|   connssl->iocport = -1; | ||||
|  | ||||
|   /* GSKit supports two ways of specifying an SSL context: either by | ||||
|    *  application identifier (that should have been defined at the system | ||||
|    *  level) or by keyring file, password and certificate label. | ||||
|    * Local certificate name (CURLOPT_SSLCERT) is used to hold either the | ||||
|    *  application identifier of the certificate label. | ||||
|    * Key password (CURLOPT_KEYPASSWD) holds the keyring password. | ||||
|    * It is not possible to have different keyrings for the CAs and the | ||||
|    *  local certificate. We thus use the CA file (CURLOPT_CAINFO) to identify | ||||
|    *  the keyring file. | ||||
|    * If no key password is given and the keyring is the system keyring, | ||||
|    *  application identifier mode is tried first, as recommended in IBM doc. | ||||
|    */ | ||||
|  | ||||
|   keyringfile = data->set.str[STRING_SSL_CAFILE]; | ||||
|   keyringpwd = data->set.str[STRING_KEY_PASSWD]; | ||||
|   keyringlabel = data->set.str[STRING_CERT]; | ||||
|   envir = (gsk_handle) NULL; | ||||
|  | ||||
|   if(keyringlabel && *keyringlabel && !keyringpwd && | ||||
|       !strcmp(keyringfile, CURL_CA_BUNDLE)) { | ||||
|     /* Try application identifier mode. */ | ||||
|     init_environment(data, &envir, keyringlabel, (const char *) NULL, | ||||
|                      (const char *) NULL, (const char *) NULL); | ||||
|   } | ||||
|  | ||||
|   if(!envir) { | ||||
|     /* Use keyring mode. */ | ||||
|     cc = init_environment(data, &envir, (const char *) NULL, | ||||
|                           keyringfile, keyringlabel, keyringpwd); | ||||
|     if(cc != CURLE_OK) | ||||
|       return cc; | ||||
|   } | ||||
|  | ||||
|   /* Create secure session. */ | ||||
|   cc = gskit_status(data, gsk_secure_soc_open(envir, &connssl->handle), | ||||
|                     "gsk_secure_soc_open()", CURLE_SSL_CONNECT_ERROR); | ||||
|   gsk_environment_close(&envir); | ||||
|   if(cc != CURLE_OK) | ||||
|     return cc; | ||||
|  | ||||
|   /* Determine which SSL/TLS version should be enabled. */ | ||||
|   sslv2enable = sslv3enable = tlsv1enable = false; | ||||
|   sni = conn->host.name; | ||||
|   switch (data->set.ssl.version) { | ||||
|   case CURL_SSLVERSION_SSLv2: | ||||
|     sslv2enable = true; | ||||
|     sni = (char *) NULL; | ||||
|     break; | ||||
|   case CURL_SSLVERSION_SSLv3: | ||||
|     sslv3enable = true; | ||||
|     sni = (char *) NULL; | ||||
|     break; | ||||
|   case CURL_SSLVERSION_TLSv1: | ||||
|     tlsv1enable = true; | ||||
|     break; | ||||
|   default:              /* CURL_SSLVERSION_DEFAULT. */ | ||||
|     sslv3enable = true; | ||||
|     tlsv1enable = true; | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   /* Process SNI. Ignore if not supported (on OS400 < V7R1). */ | ||||
|   if(sni) { | ||||
|     rc = gsk_attribute_set_buffer(connssl->handle, | ||||
|                                   GSK_SSL_EXTN_SERVERNAME_REQUEST, sni, 0); | ||||
|     switch (rc) { | ||||
|     case GSK_OK: | ||||
|     case GSK_ATTRIBUTE_INVALID_ID: | ||||
|       break; | ||||
|     case GSK_ERROR_IO: | ||||
|       failf(data, "gsk_attribute_set_buffer() I/O error: %s", strerror(errno)); | ||||
|       cc = CURLE_SSL_CONNECT_ERROR; | ||||
|       break; | ||||
|     default: | ||||
|       failf(data, "gsk_attribute_set_buffer(): %s", gsk_strerror(rc)); | ||||
|       cc = CURLE_SSL_CONNECT_ERROR; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Set session parameters. */ | ||||
|   if(cc == CURLE_OK) { | ||||
|     /* Compute the handshake timeout. Since GSKit granularity is 1 second, | ||||
|        we round up the required value. */ | ||||
|     timeout = Curl_timeleft(data, NULL, TRUE); | ||||
|     if(timeout < 0) | ||||
|       cc = CURLE_OPERATION_TIMEDOUT; | ||||
|     else | ||||
|       cc = set_numeric(data, connssl->handle, GSK_HANDSHAKE_TIMEOUT, | ||||
|                        (timeout + 999) / 1000); | ||||
|   } | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_numeric(data, connssl->handle, GSK_FD, conn->sock[sockindex]); | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_ciphers(data, connssl->handle); | ||||
|   if(cc == CURLE_OK) | ||||
|       cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV2, | ||||
|                     sslv2enable? GSK_PROTOCOL_SSLV2_ON: | ||||
|                     GSK_PROTOCOL_SSLV2_OFF); | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_enum(data, connssl->handle, GSK_PROTOCOL_SSLV3, | ||||
|                   sslv3enable? GSK_PROTOCOL_SSLV3_ON: | ||||
|                   GSK_PROTOCOL_SSLV3_OFF); | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_enum(data, connssl->handle, GSK_PROTOCOL_TLSV1, | ||||
|                   sslv3enable?  GSK_PROTOCOL_TLSV1_ON: | ||||
|                   GSK_PROTOCOL_TLSV1_OFF); | ||||
|   if(cc == CURLE_OK) | ||||
|     cc = set_enum(data, connssl->handle, GSK_SERVER_AUTH_TYPE, | ||||
|                   data->set.ssl.verifypeer? GSK_SERVER_AUTH_FULL: | ||||
|                   GSK_SERVER_AUTH_PASSTHRU); | ||||
|  | ||||
|   if(cc == CURLE_OK) { | ||||
|     /* Start handshake. Try asynchronous first. */ | ||||
|     memset(&commarea, 0, sizeof commarea); | ||||
|     connssl->iocport = QsoCreateIOCompletionPort(); | ||||
|     if(connssl->iocport != -1) { | ||||
|       cc = gskit_status(data, gsk_secure_soc_startInit(connssl->handle, | ||||
|                         connssl->iocport, &commarea), | ||||
|                         "gsk_secure_soc_startInit()", CURLE_SSL_CONNECT_ERROR); | ||||
|       if(cc == CURLE_OK) { | ||||
|         connssl->connecting_state = ssl_connect_2; | ||||
|         return CURLE_OK; | ||||
|       } | ||||
|       else | ||||
|         close_async_handshake(connssl); | ||||
|     } | ||||
|     else if(errno != ENOBUFS) | ||||
|       cc = gskit_status(data, GSK_ERROR_IO, "QsoCreateIOCompletionPort()", 0); | ||||
|     else { | ||||
|       /* No more completion port available. Use synchronous IO. */ | ||||
|       cc = gskit_status(data, gsk_secure_soc_init(connssl->handle), | ||||
|                        "gsk_secure_soc_init()", CURLE_SSL_CONNECT_ERROR); | ||||
|       if(cc == CURLE_OK) { | ||||
|         connssl->connecting_state = ssl_connect_3; | ||||
|         return CURLE_OK; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Error: rollback. */ | ||||
|   close_one(connssl, data); | ||||
|   return cc; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode gskit_connect_step2(struct connectdata * conn, int sockindex, | ||||
|                                     bool nonblocking) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   Qso_OverlappedIO_t cstat; | ||||
|   long timeout_ms; | ||||
|   struct timeval stmv; | ||||
|   CURLcode cc; | ||||
|  | ||||
|   /* Poll or wait for end of SSL asynchronous handshake. */ | ||||
|  | ||||
|   for(;;) { | ||||
|     timeout_ms = nonblocking? 0: Curl_timeleft(data, NULL, TRUE); | ||||
|     if(timeout_ms < 0) | ||||
|       timeout_ms = 0; | ||||
|     stmv.tv_sec = timeout_ms / 1000; | ||||
|     stmv.tv_usec = (timeout_ms - stmv.tv_sec * 1000) * 1000; | ||||
|     switch (QsoWaitForIOCompletion(connssl->iocport, &cstat, &stmv)) { | ||||
|     case 1:             /* Operation complete. */ | ||||
|       break; | ||||
|     case -1:            /* An error occurred: handshake still in progress. */ | ||||
|       if(errno == EINTR) { | ||||
|         if(nonblocking) | ||||
|           return CURLE_OK; | ||||
|         continue;       /* Retry. */ | ||||
|       } | ||||
|       if(errno != ETIME) { | ||||
|         failf(data, "QsoWaitForIOCompletion() I/O error: %s", strerror(errno)); | ||||
|         cancel_async_handshake(conn, sockindex); | ||||
|         close_async_handshake(connssl); | ||||
|         return CURLE_SSL_CONNECT_ERROR; | ||||
|       } | ||||
|       /* FALL INTO... */ | ||||
|     case 0:             /* Handshake in progress, timeout occurred. */ | ||||
|       if(nonblocking) | ||||
|         return CURLE_OK; | ||||
|       cancel_async_handshake(conn, sockindex); | ||||
|       close_async_handshake(connssl); | ||||
|       return CURLE_OPERATION_TIMEDOUT; | ||||
|     } | ||||
|     break; | ||||
|   } | ||||
|   cc = gskit_status(data, cstat.returnValue, "SSL handshake", | ||||
|                     CURLE_SSL_CONNECT_ERROR); | ||||
|   if(cc == CURLE_OK) | ||||
|     connssl->connecting_state = ssl_connect_3; | ||||
|   close_async_handshake(connssl); | ||||
|   return cc; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode gskit_connect_step3(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   const gsk_cert_data_elem * cdev; | ||||
|   int cdec; | ||||
|   const gsk_cert_data_elem * p; | ||||
|   const char * cert = (const char *) NULL; | ||||
|   const char * certend; | ||||
|   int i; | ||||
|   CURLcode cc; | ||||
|  | ||||
|   /* SSL handshake done: gather certificate info and verify host. */ | ||||
|  | ||||
|   if(gskit_status(data, gsk_attribute_get_cert_info(connssl->handle, | ||||
|                                                     GSK_PARTNER_CERT_INFO, | ||||
|                                                     &cdev, &cdec), | ||||
|                   "gsk_attribute_get_cert_info()", CURLE_SSL_CONNECT_ERROR) == | ||||
|      CURLE_OK) { | ||||
|     infof(data, "Server certificate:\n"); | ||||
|     p = cdev; | ||||
|     for(i = 0; i++ < cdec; p++) | ||||
|       switch (p->cert_data_id) { | ||||
|       case CERT_BODY_DER: | ||||
|         cert = p->cert_data_p; | ||||
|         certend = cert + cdev->cert_data_l; | ||||
|         break; | ||||
|       case CERT_DN_PRINTABLE: | ||||
|         infof(data, "\t subject: %.*s\n", p->cert_data_l, p->cert_data_p); | ||||
|         break; | ||||
|       case CERT_ISSUER_DN_PRINTABLE: | ||||
|         infof(data, "\t issuer: %.*s\n", p->cert_data_l, p->cert_data_p); | ||||
|         break; | ||||
|       case CERT_VALID_FROM: | ||||
|         infof(data, "\t start date: %.*s\n", p->cert_data_l, p->cert_data_p); | ||||
|         break; | ||||
|       case CERT_VALID_TO: | ||||
|         infof(data, "\t expire date: %.*s\n", p->cert_data_l, p->cert_data_p); | ||||
|         break; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   /* Verify host. */ | ||||
|   cc = Curl_verifyhost(conn, cert, certend); | ||||
|   if(cc != CURLE_OK) | ||||
|     return cc; | ||||
|  | ||||
|   /* The only place GSKit can get the whole CA chain is a validation | ||||
|      callback where no user data pointer is available. Therefore it's not | ||||
|      possible to copy this chain into our structures for CAINFO. | ||||
|      However the server certificate may be available, thus we can return | ||||
|      info about it. */ | ||||
|   if(data->set.ssl.certinfo) { | ||||
|     if(Curl_ssl_init_certinfo(data, 1)) | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     if(cert) { | ||||
|       cc = Curl_extract_certinfo(conn, 0, cert, certend); | ||||
|       if(cc != CURLE_OK) | ||||
|         return cc; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   connssl->connecting_state = ssl_connect_done; | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
| static CURLcode gskit_connect_common(struct connectdata * conn, int sockindex, | ||||
|                                      bool nonblocking, bool * done) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   long timeout_ms; | ||||
|   Qso_OverlappedIO_t cstat; | ||||
|   CURLcode cc = CURLE_OK; | ||||
|  | ||||
|   *done = connssl->state == ssl_connection_complete; | ||||
|   if(*done) | ||||
|     return CURLE_OK; | ||||
|  | ||||
|   /* Step 1: create session, start handshake. */ | ||||
|   if(connssl->connecting_state == ssl_connect_1) { | ||||
|     /* check allowed time left */ | ||||
|     timeout_ms = Curl_timeleft(data, NULL, TRUE); | ||||
|  | ||||
|     if(timeout_ms < 0) { | ||||
|       /* no need to continue if time already is up */ | ||||
|       failf(data, "SSL connection timeout"); | ||||
|       cc = CURLE_OPERATION_TIMEDOUT; | ||||
|     } | ||||
|     else | ||||
|       cc = gskit_connect_step1(conn, sockindex); | ||||
|   } | ||||
|  | ||||
|   /* Step 2: check if handshake is over. */ | ||||
|   if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_2) { | ||||
|     /* check allowed time left */ | ||||
|     timeout_ms = Curl_timeleft(data, NULL, TRUE); | ||||
|  | ||||
|     if(timeout_ms < 0) { | ||||
|       /* no need to continue if time already is up */ | ||||
|       failf(data, "SSL connection timeout"); | ||||
|       cc = CURLE_OPERATION_TIMEDOUT; | ||||
|     } | ||||
|     else | ||||
|       cc = gskit_connect_step2(conn, sockindex, nonblocking); | ||||
|   } | ||||
|  | ||||
|   /* Step 3: gather certificate info, verify host. */ | ||||
|   if(cc == CURLE_OK && connssl->connecting_state == ssl_connect_3) | ||||
|     cc = gskit_connect_step3(conn, sockindex); | ||||
|  | ||||
|   if(cc != CURLE_OK) | ||||
|     close_one(connssl, data); | ||||
|   else if(connssl->connecting_state == ssl_connect_done) { | ||||
|     connssl->state = ssl_connection_complete; | ||||
|     connssl->connecting_state = ssl_connect_1; | ||||
|     conn->recv[sockindex] = gskit_recv; | ||||
|     conn->send[sockindex] = gskit_send; | ||||
|     *done = TRUE; | ||||
|   } | ||||
|  | ||||
|   return cc; | ||||
| } | ||||
|  | ||||
|  | ||||
| CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn, | ||||
|                                         int sockindex, | ||||
|                                         bool * done) | ||||
| { | ||||
|   CURLcode cc; | ||||
|  | ||||
|   cc = gskit_connect_common(conn, sockindex, TRUE, done); | ||||
|   if(*done || cc != CURLE_OK) | ||||
|     conn->ssl[sockindex].connecting_state = ssl_connect_1; | ||||
|   return cc; | ||||
| } | ||||
|  | ||||
|  | ||||
| CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   CURLcode retcode; | ||||
|   bool done; | ||||
|  | ||||
|   conn->ssl[sockindex].connecting_state = ssl_connect_1; | ||||
|   retcode = gskit_connect_common(conn, sockindex, FALSE, &done); | ||||
|   if(retcode) | ||||
|     return retcode; | ||||
|  | ||||
|   DEBUGASSERT(done); | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
|  | ||||
| void Curl_gskit_close(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|  | ||||
|   if(connssl->use) | ||||
|     close_one(connssl, data); | ||||
| } | ||||
|  | ||||
|  | ||||
| int Curl_gskit_close_all(struct SessionHandle * data) | ||||
| { | ||||
|   /* Unimplemented. */ | ||||
|   (void) data; | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| int Curl_gskit_shutdown(struct connectdata * conn, int sockindex) | ||||
| { | ||||
|   struct ssl_connect_data * connssl = &conn->ssl[sockindex]; | ||||
|   struct SessionHandle * data = conn->data; | ||||
|   ssize_t nread; | ||||
|   int what; | ||||
|   int rc; | ||||
|   char buf[120]; | ||||
|  | ||||
|   if(!connssl->handle) | ||||
|     return 0; | ||||
|  | ||||
|   if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE) | ||||
|     return 0; | ||||
|  | ||||
|   close_one(connssl, data); | ||||
|   rc = 0; | ||||
|   what = Curl_socket_ready(conn->sock[sockindex], | ||||
|                            CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT); | ||||
|  | ||||
|   for(;;) { | ||||
|     if(what < 0) { | ||||
|       /* anything that gets here is fatally bad */ | ||||
|       failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO); | ||||
|       rc = -1; | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     if(!what) {                                /* timeout */ | ||||
|       failf(data, "SSL shutdown timeout"); | ||||
|       break; | ||||
|     } | ||||
|  | ||||
|     /* Something to read, let's do it and hope that it is the close | ||||
|        notify alert from the server. No way to gsk_secure_soc_read() now, so | ||||
|        use read(). */ | ||||
|  | ||||
|     nread = read(conn->sock[sockindex], buf, sizeof(buf)); | ||||
|  | ||||
|     if(nread < 0) { | ||||
|       failf(data, "read: %s", strerror(errno)); | ||||
|       rc = -1; | ||||
|     } | ||||
|  | ||||
|     if(nread <= 0) | ||||
|       break; | ||||
|  | ||||
|     what = Curl_socket_ready(conn->sock[sockindex], CURL_SOCKET_BAD, 0); | ||||
|   } | ||||
|  | ||||
|   return rc; | ||||
| } | ||||
|  | ||||
|  | ||||
| size_t Curl_gskit_version(char * buffer, size_t size) | ||||
| { | ||||
|   strncpy(buffer, "GSKit", size); | ||||
|   return strlen(buffer); | ||||
| } | ||||
|  | ||||
|  | ||||
| int Curl_gskit_check_cxn(struct connectdata * cxn) | ||||
| { | ||||
|   int err; | ||||
|   int errlen; | ||||
|  | ||||
|   /* The only thing that can be tested here is at the socket level. */ | ||||
|  | ||||
|   if(!cxn->ssl[FIRSTSOCKET].handle) | ||||
|     return 0; /* connection has been closed */ | ||||
|  | ||||
|   err = 0; | ||||
|   errlen = sizeof err; | ||||
|  | ||||
|   if(getsockopt(cxn->sock[FIRSTSOCKET], SOL_SOCKET, SO_ERROR, | ||||
|                  (unsigned char *) &err, &errlen) || | ||||
|      errlen != sizeof err || err) | ||||
|     return 0; /* connection has been closed */ | ||||
|  | ||||
|   return -1;  /* connection status unknown */ | ||||
| } | ||||
|  | ||||
| #endif /* USE_GSKIT */ | ||||
							
								
								
									
										64
									
								
								lib/gskit.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								lib/gskit.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #ifndef HEADER_CURL_GSKIT_H | ||||
| #define HEADER_CURL_GSKIT_H | ||||
| /*************************************************************************** | ||||
|  *                                  _   _ ____  _ | ||||
|  *  Project                     ___| | | |  _ \| | | ||||
|  *                             / __| | | | |_) | | | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2013, 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 "curl_setup.h" | ||||
|  | ||||
| /* | ||||
|  * This header should only be needed to get included by sslgen.c and gskit.c | ||||
|  */ | ||||
|  | ||||
| #include "urldata.h" | ||||
|  | ||||
| #ifdef USE_GSKIT | ||||
| int Curl_gskit_init(void); | ||||
| void Curl_gskit_cleanup(void); | ||||
| CURLcode Curl_gskit_connect(struct connectdata * conn, int sockindex); | ||||
| CURLcode Curl_gskit_connect_nonblocking(struct connectdata * conn, | ||||
|                                         int sockindex, bool * done); | ||||
| void Curl_gskit_close(struct connectdata *conn, int sockindex); | ||||
| int Curl_gskit_close_all(struct SessionHandle * data); | ||||
| int Curl_gskit_shutdown(struct connectdata * conn, int sockindex); | ||||
|  | ||||
| size_t Curl_gskit_version(char * buffer, size_t size); | ||||
| int Curl_gskit_check_cxn(struct connectdata * cxn); | ||||
|  | ||||
| /* API setup for GSKit */ | ||||
| #define curlssl_init Curl_gskit_init | ||||
| #define curlssl_cleanup Curl_gskit_cleanup | ||||
| #define curlssl_connect Curl_gskit_connect | ||||
| #define curlssl_connect_nonblocking Curl_gskit_connect_nonblocking | ||||
|  | ||||
| /*  No session handling for GSKit */ | ||||
| #define curlssl_session_free(x) Curl_nop_stmt | ||||
| #define curlssl_close_all Curl_gskit_close_all | ||||
| #define curlssl_close Curl_gskit_close | ||||
| #define curlssl_shutdown(x,y) Curl_gskit_shutdown(x,y) | ||||
| #define curlssl_set_engine(x,y) CURLE_NOT_BUILT_IN | ||||
| #define curlssl_set_engine_default(x) CURLE_NOT_BUILT_IN | ||||
| #define curlssl_engines_list(x) NULL | ||||
| #define curlssl_version Curl_gskit_version | ||||
| #define curlssl_check_cxn(x) Curl_gskit_check_cxn(x) | ||||
| #define curlssl_data_pending(x,y) 0 | ||||
| #endif /* USE_GSKIT */ | ||||
|  | ||||
| #endif /* HEADER_CURL_GSKIT_H */ | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -55,6 +55,10 @@ void Curl_gtls_md5sum(unsigned char *tmp, /* input */ | ||||
|                       unsigned char *md5sum, /* output */ | ||||
|                       size_t md5len); | ||||
|  | ||||
| /* this backend provides these functions: */ | ||||
| #define have_curlssl_random 1 | ||||
| #define have_curlssl_md5sum 1 | ||||
|  | ||||
| /* API setup for GnuTLS */ | ||||
| #define curlssl_init Curl_gtls_init | ||||
| #define curlssl_cleanup Curl_gtls_cleanup | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -391,7 +391,7 @@ void Curl_hash_print(struct curl_hash *h, | ||||
|     if(func) | ||||
|       func(he->ptr); | ||||
|     else | ||||
|       fprintf(stderr, " [%p]", he->ptr); | ||||
|       fprintf(stderr, " [%p]", (void *)he->ptr); | ||||
|  | ||||
|     he = Curl_hash_next_element(&iter); | ||||
|   } | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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,9 @@ | ||||
|  | ||||
| #include "curl_setup.h" | ||||
|  | ||||
| #if defined(USE_SSLEAY) || defined(USE_AXTLS) | ||||
| /* these two backends use functions from this file */ | ||||
| #if defined(USE_SSLEAY) || defined(USE_AXTLS) || defined(USE_QSOSSL) || \ | ||||
|     defined(USE_GSKIT) | ||||
| /* these backends use functions from this file */ | ||||
|  | ||||
| #include "hostcheck.h" | ||||
| #include "rawstr.h" | ||||
| @@ -93,4 +94,4 @@ int Curl_cert_hostcheck(const char *match_pattern, const char *hostname) | ||||
|   return 0; | ||||
| } | ||||
|  | ||||
| #endif /* SSLEAY or AXTLS */ | ||||
| #endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */ | ||||
|   | ||||
							
								
								
									
										31
									
								
								lib/hostip.c
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								lib/hostip.c
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -140,6 +140,10 @@ struct curl_hash *Curl_global_host_cache_init(void) | ||||
| void Curl_global_host_cache_dtor(void) | ||||
| { | ||||
|   if(host_cache_initialized) { | ||||
|     /* first make sure that any custom "CURLOPT_RESOLVE" names are | ||||
|        cleared off */ | ||||
|     Curl_hostcache_clean(NULL, &hostname_cache); | ||||
|     /* then free the remaining hash completely */ | ||||
|     Curl_hash_clean(&hostname_cache); | ||||
|     host_cache_initialized = 0; | ||||
|   } | ||||
| @@ -681,12 +685,14 @@ clean_up: | ||||
|  * Curl_resolv_unlock() unlocks the given cached DNS entry. When this has been | ||||
|  * made, the struct may be destroyed due to pruning. It is important that only | ||||
|  * one unlock is made for each Curl_resolv() call. | ||||
|  * | ||||
|  * May be called with 'data' == NULL for global cache. | ||||
|  */ | ||||
| void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) | ||||
| { | ||||
|   DEBUGASSERT(dns && (dns->inuse>0)); | ||||
|  | ||||
|   if(data->share) | ||||
|   if(data && data->share) | ||||
|     Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE); | ||||
|  | ||||
|   dns->inuse--; | ||||
| @@ -697,7 +703,7 @@ void Curl_resolv_unlock(struct SessionHandle *data, struct Curl_dns_entry *dns) | ||||
|     free(dns); | ||||
|   } | ||||
|  | ||||
|   if(data->share) | ||||
|   if(data && data->share) | ||||
|     Curl_share_unlock(data, CURL_LOCK_DATA_DNS); | ||||
| } | ||||
|  | ||||
| @@ -734,22 +740,23 @@ static int hostcache_inuse(void *data, void *hc) | ||||
|   return 1; /* free all entries */ | ||||
| } | ||||
|  | ||||
| void Curl_hostcache_clean(struct SessionHandle *data) | ||||
| /* | ||||
|  * Curl_hostcache_clean() | ||||
|  * | ||||
|  * This _can_ be called with 'data' == NULL but then of course no locking | ||||
|  * can be done! | ||||
|  */ | ||||
|  | ||||
| void Curl_hostcache_clean(struct SessionHandle *data, | ||||
|                           struct curl_hash *hash) | ||||
| { | ||||
|   /* Entries added to the hostcache with the CURLOPT_RESOLVE function are | ||||
|    * still present in the cache with the inuse counter set to 1. Detect them | ||||
|    * and cleanup! | ||||
|    */ | ||||
|   Curl_hash_clean_with_criterium(data->dns.hostcache, data, hostcache_inuse); | ||||
|   Curl_hash_clean_with_criterium(hash, data, hostcache_inuse); | ||||
| } | ||||
|  | ||||
| void Curl_hostcache_destroy(struct SessionHandle *data) | ||||
| { | ||||
|   Curl_hostcache_clean(data); | ||||
|   Curl_hash_destroy(data->dns.hostcache); | ||||
|   data->dns.hostcachetype = HCACHE_NONE; | ||||
|   data->dns.hostcache = NULL; | ||||
| } | ||||
|  | ||||
| CURLcode Curl_loadhostpairs(struct SessionHandle *data) | ||||
| { | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -203,7 +203,7 @@ CURLcode Curl_set_dns_servers(struct SessionHandle *data, char *servers); | ||||
| /* | ||||
|  * Clean off entries from the cache | ||||
|  */ | ||||
| void Curl_hostcache_clean(struct SessionHandle *data); | ||||
| void Curl_hostcache_clean(struct SessionHandle *data, struct curl_hash *hash); | ||||
|  | ||||
| /* | ||||
|  * Destroy the hostcache of this handle. | ||||
|   | ||||
| @@ -25,14 +25,13 @@ | ||||
| #if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH) | ||||
|  | ||||
| #include "urldata.h" | ||||
| #include "sendf.h" | ||||
| #include "rawstr.h" | ||||
| #include "curl_base64.h" | ||||
| #include "curl_md5.h" | ||||
| #include "http_digest.h" | ||||
| #include "strtok.h" | ||||
| #include "url.h" /* for Curl_safefree() */ | ||||
| #include "curl_memory.h" | ||||
| #include "sslgen.h" /* for Curl_rand() */ | ||||
| #include "non-ascii.h" /* included for Curl_convert_... prototypes */ | ||||
| #include "warnless.h" | ||||
|  | ||||
| @@ -267,6 +266,38 @@ static void md5_to_ascii(unsigned char *source, /* 16 bytes */ | ||||
|     snprintf((char *)&dest[i*2], 3, "%02x", source[i]); | ||||
| } | ||||
|  | ||||
| /* Perform quoted-string escaping as described in RFC2616 and its errata */ | ||||
| static char *string_quoted(const char *source) | ||||
| { | ||||
|   char *dest, *d; | ||||
|   const char *s = source; | ||||
|   size_t n = 1; /* null terminator */ | ||||
|  | ||||
|   /* Calculate size needed */ | ||||
|   while(*s) { | ||||
|     ++n; | ||||
|     if(*s == '"' || *s == '\\') { | ||||
|       ++n; | ||||
|     } | ||||
|     ++s; | ||||
|   } | ||||
|  | ||||
|   dest = malloc(n); | ||||
|   if(dest) { | ||||
|     s = source; | ||||
|     d = dest; | ||||
|     while(*s) { | ||||
|       if(*s == '"' || *s == '\\') { | ||||
|         *d++ = '\\'; | ||||
|       } | ||||
|       *d++ = *s++; | ||||
|     } | ||||
|     *d = 0; | ||||
|   } | ||||
|  | ||||
|   return dest; | ||||
| } | ||||
|  | ||||
| CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|                             bool proxy, | ||||
|                             const unsigned char *request, | ||||
| @@ -278,17 +309,16 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|   unsigned char md5buf[16]; /* 16 bytes/128 bits */ | ||||
|   unsigned char request_digest[33]; | ||||
|   unsigned char *md5this; | ||||
|   unsigned char *ha1; | ||||
|   unsigned char ha1[33];/* 32 digits and 1 zero byte */ | ||||
|   unsigned char ha2[33];/* 32 digits and 1 zero byte */ | ||||
|   char cnoncebuf[33]; | ||||
|   char *cnonce = NULL; | ||||
|   size_t cnonce_sz = 0; | ||||
|   char *tmp = NULL; | ||||
|   struct timeval now; | ||||
|  | ||||
|   char **allocuserpwd; | ||||
|   size_t userlen; | ||||
|   const char *userp; | ||||
|   char *userp_quoted; | ||||
|   const char *passwdp; | ||||
|   struct auth *authp; | ||||
|  | ||||
| @@ -321,10 +351,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|     authp = &data->state.authhost; | ||||
|   } | ||||
|  | ||||
|   if(*allocuserpwd) { | ||||
|     Curl_safefree(*allocuserpwd); | ||||
|     *allocuserpwd = NULL; | ||||
|   } | ||||
|   Curl_safefree(*allocuserpwd); | ||||
|  | ||||
|   /* not set means empty */ | ||||
|   if(!userp) | ||||
| @@ -343,10 +370,11 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|     d->nc = 1; | ||||
|  | ||||
|   if(!d->cnonce) { | ||||
|     /* Generate a cnonce */ | ||||
|     now = Curl_tvnow(); | ||||
|     snprintf(cnoncebuf, sizeof(cnoncebuf), "%32ld", | ||||
|              (long)now.tv_sec + now.tv_usec); | ||||
|     struct timeval now = Curl_tvnow(); | ||||
|     snprintf(cnoncebuf, sizeof(cnoncebuf), "%08x%08x%08x%08x", | ||||
|              Curl_rand(data), Curl_rand(data), | ||||
|              (unsigned int)now.tv_sec, | ||||
|              (unsigned int)now.tv_usec); | ||||
|  | ||||
|     rc = Curl_base64_encode(data, cnoncebuf, strlen(cnoncebuf), | ||||
|                             &cnonce, &cnonce_sz); | ||||
| @@ -373,12 +401,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|  | ||||
|   CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ | ||||
|   Curl_md5it(md5buf, md5this); | ||||
|   free(md5this); /* free this again */ | ||||
|  | ||||
|   ha1 = malloc(33); /* 32 digits and 1 zero byte */ | ||||
|   if(!ha1) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   Curl_safefree(md5this); | ||||
|   md5_to_ascii(md5buf, ha1); | ||||
|  | ||||
|   if(d->algo == CURLDIGESTALGO_MD5SESS) { | ||||
| @@ -388,7 +411,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */ | ||||
|     Curl_md5it(md5buf, (unsigned char *)tmp); | ||||
|     free(tmp); /* free this again */ | ||||
|     Curl_safefree(tmp); | ||||
|     md5_to_ascii(md5buf, ha1); | ||||
|   } | ||||
|  | ||||
| @@ -425,19 +448,21 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|   else | ||||
|     md5this = (unsigned char *)aprintf("%s:%s", request, uripath); | ||||
|  | ||||
|   if(!md5this) { | ||||
|     free(ha1); | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|   if(d->qop && Curl_raw_equal(d->qop, "auth-int")) { | ||||
|     /* We don't support auth-int for PUT or POST at the moment. | ||||
|        TODO: replace md5 of empty string with entity-body for PUT/POST */ | ||||
|     unsigned char *md5this2 = (unsigned char *) | ||||
|       aprintf("%s:%s", md5this, "d41d8cd98f00b204e9800998ecf8427e"); | ||||
|     Curl_safefree(md5this); | ||||
|     md5this = md5this2; | ||||
|   } | ||||
|  | ||||
|   if(d->qop && Curl_raw_equal(d->qop, "auth-int")) { | ||||
|     /* We don't support auth-int at the moment. I can't see a easy way to get | ||||
|        entity-body here */ | ||||
|     /* TODO: Append H(entity-body)*/ | ||||
|   } | ||||
|   if(!md5this) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ | ||||
|   Curl_md5it(md5buf, md5this); | ||||
|   free(md5this); /* free this again */ | ||||
|   Curl_safefree(md5this); | ||||
|   md5_to_ascii(md5buf, ha2); | ||||
|  | ||||
|   if(d->qop) { | ||||
| @@ -455,20 +480,30 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|                                        d->nonce, | ||||
|                                        ha2); | ||||
|   } | ||||
|   free(ha1); | ||||
|   if(!md5this) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */ | ||||
|   Curl_md5it(md5buf, md5this); | ||||
|   free(md5this); /* free this again */ | ||||
|   Curl_safefree(md5this); | ||||
|   md5_to_ascii(md5buf, request_digest); | ||||
|  | ||||
|   /* for test case 64 (snooped from a Mozilla 1.3a request) | ||||
|  | ||||
|     Authorization: Digest username="testuser", realm="testrealm", \ | ||||
|     nonce="1053604145", uri="/64", response="c55f7f30d83d774a3d2dcacf725abaca" | ||||
|  | ||||
|     Digest parameters are all quoted strings.  Username which is provided by | ||||
|     the user will need double quotes and backslashes within it escaped.  For | ||||
|     the other fields, this shouldn't be an issue.  realm, nonce, and opaque | ||||
|     are copied as is from the server, escapes and all.  cnonce is generated | ||||
|     with web-safe characters.  uri is already percent encoded.  nc is 8 hex | ||||
|     characters.  algorithm and qop with standard values only contain web-safe | ||||
|     chracters. | ||||
|   */ | ||||
|   userp_quoted = string_quoted(userp); | ||||
|   if(!userp_quoted) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   if(d->qop) { | ||||
|     *allocuserpwd = | ||||
| @@ -482,7 +517,7 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|                "qop=%s, " | ||||
|                "response=\"%s\"", | ||||
|                proxy?"Proxy-":"", | ||||
|                userp, | ||||
|                userp_quoted, | ||||
|                d->realm, | ||||
|                d->nonce, | ||||
|                uripath, /* this is the PATH part of the URL */ | ||||
| @@ -505,12 +540,13 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|                "uri=\"%s\", " | ||||
|                "response=\"%s\"", | ||||
|                proxy?"Proxy-":"", | ||||
|                userp, | ||||
|                userp_quoted, | ||||
|                d->realm, | ||||
|                d->nonce, | ||||
|                uripath, /* this is the PATH part of the URL */ | ||||
|                request_digest); | ||||
|   } | ||||
|   Curl_safefree(userp_quoted); | ||||
|   if(!*allocuserpwd) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
| @@ -546,29 +582,12 @@ CURLcode Curl_output_digest(struct connectdata *conn, | ||||
|  | ||||
| static void digest_cleanup_one(struct digestdata *d) | ||||
| { | ||||
|   if(d->nonce) | ||||
|     free(d->nonce); | ||||
|   d->nonce = NULL; | ||||
|  | ||||
|   if(d->cnonce) | ||||
|     free(d->cnonce); | ||||
|   d->cnonce = NULL; | ||||
|  | ||||
|   if(d->realm) | ||||
|     free(d->realm); | ||||
|   d->realm = NULL; | ||||
|  | ||||
|   if(d->opaque) | ||||
|     free(d->opaque); | ||||
|   d->opaque = NULL; | ||||
|  | ||||
|   if(d->qop) | ||||
|     free(d->qop); | ||||
|   d->qop = NULL; | ||||
|  | ||||
|   if(d->algorithm) | ||||
|     free(d->algorithm); | ||||
|   d->algorithm = NULL; | ||||
|   Curl_safefree(d->nonce); | ||||
|   Curl_safefree(d->cnonce); | ||||
|   Curl_safefree(d->realm); | ||||
|   Curl_safefree(d->opaque); | ||||
|   Curl_safefree(d->qop); | ||||
|   Curl_safefree(d->algorithm); | ||||
|  | ||||
|   d->nc = 0; | ||||
|   d->algo = CURLDIGESTALGO_MD5; /* default algorithm */ | ||||
|   | ||||
							
								
								
									
										574
									
								
								lib/imap.c
									
									
									
									
									
								
							
							
						
						
									
										574
									
								
								lib/imap.c
									
									
									
									
									
								
							| @@ -77,6 +77,7 @@ | ||||
| #include "url.h" | ||||
| #include "rawstr.h" | ||||
| #include "curl_sasl.h" | ||||
| #include "warnless.h" | ||||
|  | ||||
| #define _MPRINTF_REPLACE /* use our functions only */ | ||||
| #include <curl/mprintf.h> | ||||
| @@ -86,8 +87,6 @@ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| /* Local API functions */ | ||||
| static CURLcode imap_parse_url_path(struct connectdata *conn); | ||||
| static CURLcode imap_parse_custom_request(struct connectdata *conn); | ||||
| static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done); | ||||
| static CURLcode imap_do(struct connectdata *conn, bool *done); | ||||
| static CURLcode imap_done(struct connectdata *conn, CURLcode status, | ||||
| @@ -99,6 +98,11 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, | ||||
|                         int numsocks); | ||||
| static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done); | ||||
| static CURLcode imap_setup_connection(struct connectdata *conn); | ||||
| static char *imap_atom(const char *str); | ||||
| static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...); | ||||
| static CURLcode imap_parse_url_options(struct connectdata *conn); | ||||
| static CURLcode imap_parse_url_path(struct connectdata *conn); | ||||
| static CURLcode imap_parse_custom_request(struct connectdata *conn); | ||||
|  | ||||
| /* | ||||
|  * IMAP protocol handler. | ||||
| @@ -213,119 +217,6 @@ static void imap_to_imaps(struct connectdata *conn) | ||||
| #define imap_to_imaps(x) Curl_nop_stmt | ||||
| #endif | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_sendf() | ||||
|  * | ||||
|  * Sends the formated string as an IMAP command to the server. | ||||
|  * | ||||
|  * Designed to never block. | ||||
|  */ | ||||
| static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct imap_conn *imapc = &conn->proto.imapc; | ||||
|   char *taggedfmt; | ||||
|   va_list ap; | ||||
|   va_start(ap, fmt); | ||||
|  | ||||
|   /* Calculate the next command ID wrapping at 3 digits */ | ||||
|   imapc->cmdid = (imapc->cmdid + 1) % 1000; | ||||
|  | ||||
|   /* Calculate the tag based on the connection ID and command ID */ | ||||
|   snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", | ||||
|            'A' + (conn->connection_id % 26), imapc->cmdid); | ||||
|  | ||||
|   /* Prefix the format with the tag */ | ||||
|   taggedfmt = aprintf("%s %s", imapc->resptag, fmt); | ||||
|   if(!taggedfmt) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   /* Send the data with the tag */ | ||||
|   result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); | ||||
|  | ||||
|   Curl_safefree(taggedfmt); | ||||
|   va_end(ap); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_atom() | ||||
|  * | ||||
|  * Checks the input string for characters that need escaping and returns an | ||||
|  * atom ready for sending to the server. | ||||
|  * | ||||
|  * The returned string needs to be freed. | ||||
|  * | ||||
|  */ | ||||
| static char *imap_atom(const char *str) | ||||
| { | ||||
|   const char *p1; | ||||
|   char *p2; | ||||
|   size_t backsp_count = 0; | ||||
|   size_t quote_count = 0; | ||||
|   bool space_exists = FALSE; | ||||
|   size_t newlen = 0; | ||||
|   char *newstr = NULL; | ||||
|  | ||||
|   if(!str) | ||||
|     return NULL; | ||||
|  | ||||
|   /* Count any unescapped characters */ | ||||
|   p1 = str; | ||||
|   while(*p1) { | ||||
|     if(*p1 == '\\') | ||||
|       backsp_count++; | ||||
|     else if(*p1 == '"') | ||||
|       quote_count++; | ||||
|     else if(*p1 == ' ') | ||||
|       space_exists = TRUE; | ||||
|  | ||||
|     p1++; | ||||
|   } | ||||
|  | ||||
|   /* Does the input contain any unescapped characters? */ | ||||
|   if(!backsp_count && !quote_count && !space_exists) | ||||
|     return strdup(str); | ||||
|  | ||||
|   /* Calculate the new string length */ | ||||
|   newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0); | ||||
|  | ||||
|   /* Allocate the new string */ | ||||
|   newstr = (char *) malloc((newlen + 1) * sizeof(char)); | ||||
|   if(!newstr) | ||||
|     return NULL; | ||||
|  | ||||
|   /* Surround the string in quotes if necessary */ | ||||
|   p2 = newstr; | ||||
|   if(space_exists) { | ||||
|     newstr[0] = '"'; | ||||
|     newstr[newlen - 1] = '"'; | ||||
|     p2++; | ||||
|   } | ||||
|  | ||||
|   /* Copy the string, escaping backslash and quote characters along the way */ | ||||
|   p1 = str; | ||||
|   while(*p1) { | ||||
|     if(*p1 == '\\' || *p1 == '"') { | ||||
|       *p2 = '\\'; | ||||
|       p2++; | ||||
|     } | ||||
|  | ||||
|    *p2 = *p1; | ||||
|  | ||||
|     p1++; | ||||
|     p2++; | ||||
|   } | ||||
|  | ||||
|   /* Terminate the string */ | ||||
|   newstr[newlen] = '\0'; | ||||
|  | ||||
|   return newstr; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_matchresp() | ||||
| @@ -508,7 +399,7 @@ static void state(struct connectdata *conn, imapstate newstate) | ||||
|  | ||||
|   if(imapc->state != newstate) | ||||
|     infof(conn->data, "IMAP %p state change from %s to %s\n", | ||||
|           imapc, names[imapc->state], names[newstate]); | ||||
|           (void *)imapc, names[imapc->state], names[newstate]); | ||||
| #endif | ||||
|  | ||||
|   imapc->state = newstate; | ||||
| @@ -635,6 +526,7 @@ static CURLcode imap_perform_login(struct connectdata *conn) | ||||
| static CURLcode imap_perform_authenticate(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct imap_conn *imapc = &conn->proto.imapc; | ||||
|   const char *mech = NULL; | ||||
|   char *initresp = NULL; | ||||
| @@ -653,12 +545,14 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn) | ||||
|   /* Calculate the supported authentication mechanism by decreasing order of | ||||
|      security */ | ||||
| #ifndef CURL_DISABLE_CRYPTO_AUTH | ||||
|   if(imapc->authmechs & SASL_MECH_DIGEST_MD5) { | ||||
|   if((imapc->authmechs & SASL_MECH_DIGEST_MD5) && | ||||
|      (imapc->prefmech & SASL_MECH_DIGEST_MD5)) { | ||||
|     mech = "DIGEST-MD5"; | ||||
|     state1 = IMAP_AUTHENTICATE_DIGESTMD5; | ||||
|     imapc->authused = SASL_MECH_DIGEST_MD5; | ||||
|   } | ||||
|   else if(imapc->authmechs & SASL_MECH_CRAM_MD5) { | ||||
|   else if((imapc->authmechs & SASL_MECH_CRAM_MD5) && | ||||
|           (imapc->prefmech & SASL_MECH_CRAM_MD5)) { | ||||
|     mech = "CRAM-MD5"; | ||||
|     state1 = IMAP_AUTHENTICATE_CRAMMD5; | ||||
|     imapc->authused = SASL_MECH_CRAM_MD5; | ||||
| @@ -666,67 +560,69 @@ static CURLcode imap_perform_authenticate(struct connectdata *conn) | ||||
|   else | ||||
| #endif | ||||
| #ifdef USE_NTLM | ||||
|   if(imapc->authmechs & SASL_MECH_NTLM) { | ||||
|     if((imapc->authmechs & SASL_MECH_NTLM) && | ||||
|        (imapc->prefmech & SASL_MECH_NTLM)) { | ||||
|     mech = "NTLM"; | ||||
|     state1 = IMAP_AUTHENTICATE_NTLM; | ||||
|     state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG; | ||||
|     imapc->authused = SASL_MECH_NTLM; | ||||
|  | ||||
|     if(imapc->ir_supported) | ||||
|     if(imapc->ir_supported || data->set.sasl_ir) | ||||
|       result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, | ||||
|                                                    &conn->ntlm, | ||||
|                                                    &initresp, &len); | ||||
|   } | ||||
|   else | ||||
| #endif | ||||
|   if(imapc->authmechs & SASL_MECH_LOGIN) { | ||||
|   if((imapc->authmechs & SASL_MECH_LOGIN) && | ||||
|      (imapc->prefmech & SASL_MECH_LOGIN)) { | ||||
|     mech = "LOGIN"; | ||||
|     state1 = IMAP_AUTHENTICATE_LOGIN; | ||||
|     state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD; | ||||
|     imapc->authused = SASL_MECH_LOGIN; | ||||
|  | ||||
|     if(imapc->ir_supported) | ||||
|     if(imapc->ir_supported || data->set.sasl_ir) | ||||
|       result = Curl_sasl_create_login_message(conn->data, conn->user, | ||||
|                                               &initresp, &len); | ||||
|   } | ||||
|   else if(imapc->authmechs & SASL_MECH_PLAIN) { | ||||
|   else if((imapc->authmechs & SASL_MECH_PLAIN) && | ||||
|           (imapc->prefmech & SASL_MECH_PLAIN)) { | ||||
|     mech = "PLAIN"; | ||||
|     state1 = IMAP_AUTHENTICATE_PLAIN; | ||||
|     state2 = IMAP_AUTHENTICATE_FINAL; | ||||
|     imapc->authused = SASL_MECH_PLAIN; | ||||
|  | ||||
|     if(imapc->ir_supported) | ||||
|     if(imapc->ir_supported || data->set.sasl_ir) | ||||
|       result = Curl_sasl_create_plain_message(conn->data, conn->user, | ||||
|                                               conn->passwd, &initresp, &len); | ||||
|   } | ||||
|  | ||||
|   if(result) | ||||
|     return result; | ||||
|   if(!result) { | ||||
|     if(mech) { | ||||
|       /* Perform SASL based authentication */ | ||||
|       if(initresp) { | ||||
|         result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); | ||||
|  | ||||
|   if(mech) { | ||||
|     /* Perform SASL based authentication */ | ||||
|     if(initresp) { | ||||
|       result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp); | ||||
|         if(!result) | ||||
|           state(conn, state2); | ||||
|       } | ||||
|       else { | ||||
|         result = imap_sendf(conn, "AUTHENTICATE %s", mech); | ||||
|  | ||||
|       if(!result) | ||||
|         state(conn, state2); | ||||
|         if(!result) | ||||
|           state(conn, state1); | ||||
|       } | ||||
|  | ||||
|       Curl_safefree(initresp); | ||||
|     } | ||||
|     else if(!imapc->login_disabled) | ||||
|       /* Perform clear text authentication */ | ||||
|       result = imap_perform_login(conn); | ||||
|     else { | ||||
|       result = imap_sendf(conn, "AUTHENTICATE %s", mech); | ||||
|  | ||||
|       if(!result) | ||||
|         state(conn, state1); | ||||
|       /* Other mechanisms not supported */ | ||||
|       infof(conn->data, "No known authentication mechanisms supported!\n"); | ||||
|       result = CURLE_LOGIN_DENIED; | ||||
|     } | ||||
|  | ||||
|     Curl_safefree(initresp); | ||||
|   } | ||||
|   else if(!imapc->login_disabled) | ||||
|     /* Perform clear text authentication */ | ||||
|     result = imap_perform_login(conn); | ||||
|   else { | ||||
|     /* Other mechanisms not supported */ | ||||
|     infof(conn->data, "No known authentication mechanisms supported!\n"); | ||||
|     result = CURLE_LOGIN_DENIED; | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| @@ -1257,7 +1153,7 @@ static CURLcode imap_state_auth_digest_resp_resp(struct connectdata *conn, | ||||
|   } | ||||
|   else { | ||||
|     /* Send an empty response */ | ||||
|     result = Curl_pp_sendf(&conn->proto.imapc.pp, ""); | ||||
|     result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); | ||||
|  | ||||
|     if(!result) | ||||
|       state(conn, IMAP_AUTHENTICATE_FINAL); | ||||
| @@ -1793,12 +1689,13 @@ static int imap_getsock(struct connectdata *conn, curl_socket_t *socks, | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_connect() should do everything that is to be considered a part of | ||||
|  * the connection phase. | ||||
|  * imap_connect() | ||||
|  * | ||||
|  * This function should do everything that is to be considered a part of the | ||||
|  * connection phase. | ||||
|  * | ||||
|  * The variable 'done' points to will be TRUE if the protocol-layer connect | ||||
|  * phase is done when this function returns, or FALSE is not. When called as | ||||
|  * a part of the easy interface, it will always be TRUE. | ||||
|  * phase is done when this function returns, or FALSE if not. | ||||
|  */ | ||||
| static CURLcode imap_connect(struct connectdata *conn, bool *done) | ||||
| { | ||||
| @@ -1826,9 +1723,17 @@ static CURLcode imap_connect(struct connectdata *conn, bool *done) | ||||
|   pp->endofresp = imap_endofresp; | ||||
|   pp->conn = conn; | ||||
|  | ||||
|   /* Set the default preferred authentication mechanism */ | ||||
|   imapc->prefmech = SASL_AUTH_ANY; | ||||
|  | ||||
|   /* Initialise the pingpong layer */ | ||||
|   Curl_pp_init(pp); | ||||
|  | ||||
|   /* Parse the URL options */ | ||||
|   result = imap_parse_url_options(conn); | ||||
|   if(result) | ||||
|     return result; | ||||
|  | ||||
|   /* Start off waiting for the server greeting response */ | ||||
|   state(conn, IMAP_SERVERGREET); | ||||
|  | ||||
| @@ -1876,7 +1781,7 @@ static CURLcode imap_done(struct connectdata *conn, CURLcode status, | ||||
|       state(conn, IMAP_FETCH_FINAL); | ||||
|     else { | ||||
|       /* End the APPEND command first by sending an empty line */ | ||||
|       result = Curl_pp_sendf(&conn->proto.imapc.pp, ""); | ||||
|       result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", ""); | ||||
|       if(!result) | ||||
|         state(conn, IMAP_APPEND_FINAL); | ||||
|     } | ||||
| @@ -2044,6 +1949,220 @@ static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection) | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* Call this when the DO phase has completed */ | ||||
| static CURLcode imap_dophase_done(struct connectdata *conn, bool connected) | ||||
| { | ||||
|   struct IMAP *imap = conn->data->state.proto.imap; | ||||
|  | ||||
|   (void)connected; | ||||
|  | ||||
|   if(imap->transfer != FTPTRANSFER_BODY) | ||||
|     /* no data to transfer */ | ||||
|     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* Called from multi.c while DOing */ | ||||
| static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done) | ||||
| { | ||||
|   CURLcode result = imap_multi_statemach(conn, dophase_done); | ||||
|  | ||||
|   if(result) | ||||
|     DEBUGF(infof(conn->data, "DO phase failed\n")); | ||||
|   else if(*dophase_done) { | ||||
|     result = imap_dophase_done(conn, FALSE /* not connected */); | ||||
|  | ||||
|     DEBUGF(infof(conn->data, "DO phase is complete\n")); | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_regular_transfer() | ||||
|  * | ||||
|  * The input argument is already checked for validity. | ||||
|  * | ||||
|  * Performs all commands done before a regular transfer between a local and a | ||||
|  * remote host. | ||||
|  */ | ||||
| static CURLcode imap_regular_transfer(struct connectdata *conn, | ||||
|                                       bool *dophase_done) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   bool connected = FALSE; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|  | ||||
|   /* Make sure size is unknown at this point */ | ||||
|   data->req.size = -1; | ||||
|  | ||||
|   /* Set the progress data */ | ||||
|   Curl_pgrsSetUploadCounter(data, 0); | ||||
|   Curl_pgrsSetDownloadCounter(data, 0); | ||||
|   Curl_pgrsSetUploadSize(data, 0); | ||||
|   Curl_pgrsSetDownloadSize(data, 0); | ||||
|  | ||||
|   /* Carry out the perform */ | ||||
|   result = imap_perform(conn, &connected, dophase_done); | ||||
|  | ||||
|   /* Perform post DO phase operations if necessary */ | ||||
|   if(!result && *dophase_done) | ||||
|     result = imap_dophase_done(conn, connected); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode imap_setup_connection(struct connectdata *conn) | ||||
| { | ||||
|   struct SessionHandle *data = conn->data; | ||||
|  | ||||
|   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { | ||||
|     /* Unless we have asked to tunnel IMAP operations through the proxy, we | ||||
|        switch and use HTTP operations only */ | ||||
| #ifndef CURL_DISABLE_HTTP | ||||
|     if(conn->handler == &Curl_handler_imap) | ||||
|       conn->handler = &Curl_handler_imap_proxy; | ||||
|     else { | ||||
| #ifdef USE_SSL | ||||
|       conn->handler = &Curl_handler_imaps_proxy; | ||||
| #else | ||||
|       failf(data, "IMAPS not supported!"); | ||||
|       return CURLE_UNSUPPORTED_PROTOCOL; | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     /* We explicitly mark this connection as persistent here as we're doing | ||||
|        IMAP over HTTP and thus we accidentally avoid setting this value | ||||
|        otherwise */ | ||||
|     conn->bits.close = FALSE; | ||||
| #else | ||||
|     failf(data, "IMAP over http proxy requires HTTP support built-in!"); | ||||
|     return CURLE_UNSUPPORTED_PROTOCOL; | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   data->state.path++;   /* don't include the initial slash */ | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_sendf() | ||||
|  * | ||||
|  * Sends the formated string as an IMAP command to the server. | ||||
|  * | ||||
|  * Designed to never block. | ||||
|  */ | ||||
| static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct imap_conn *imapc = &conn->proto.imapc; | ||||
|   char *taggedfmt; | ||||
|   va_list ap; | ||||
|  | ||||
|   DEBUGASSERT(fmt); | ||||
|  | ||||
|   /* Calculate the next command ID wrapping at 3 digits */ | ||||
|   imapc->cmdid = (imapc->cmdid + 1) % 1000; | ||||
|  | ||||
|   /* Calculate the tag based on the connection ID and command ID */ | ||||
|   snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d", | ||||
|            'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid); | ||||
|  | ||||
|   /* Prefix the format with the tag */ | ||||
|   taggedfmt = aprintf("%s %s", imapc->resptag, fmt); | ||||
|   if(!taggedfmt) | ||||
|     return CURLE_OUT_OF_MEMORY; | ||||
|  | ||||
|   /* Send the data with the tag */ | ||||
|   va_start(ap, fmt); | ||||
|   result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap); | ||||
|   va_end(ap); | ||||
|  | ||||
|   Curl_safefree(taggedfmt); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_atom() | ||||
|  * | ||||
|  * Checks the input string for characters that need escaping and returns an | ||||
|  * atom ready for sending to the server. | ||||
|  * | ||||
|  * The returned string needs to be freed. | ||||
|  * | ||||
|  */ | ||||
| static char *imap_atom(const char *str) | ||||
| { | ||||
|   const char *p1; | ||||
|   char *p2; | ||||
|   size_t backsp_count = 0; | ||||
|   size_t quote_count = 0; | ||||
|   bool space_exists = FALSE; | ||||
|   size_t newlen = 0; | ||||
|   char *newstr = NULL; | ||||
|  | ||||
|   if(!str) | ||||
|     return NULL; | ||||
|  | ||||
|   /* Count any unescapped characters */ | ||||
|   p1 = str; | ||||
|   while(*p1) { | ||||
|     if(*p1 == '\\') | ||||
|       backsp_count++; | ||||
|     else if(*p1 == '"') | ||||
|       quote_count++; | ||||
|     else if(*p1 == ' ') | ||||
|       space_exists = TRUE; | ||||
|  | ||||
|     p1++; | ||||
|   } | ||||
|  | ||||
|   /* Does the input contain any unescapped characters? */ | ||||
|   if(!backsp_count && !quote_count && !space_exists) | ||||
|     return strdup(str); | ||||
|  | ||||
|   /* Calculate the new string length */ | ||||
|   newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0); | ||||
|  | ||||
|   /* Allocate the new string */ | ||||
|   newstr = (char *) malloc((newlen + 1) * sizeof(char)); | ||||
|   if(!newstr) | ||||
|     return NULL; | ||||
|  | ||||
|   /* Surround the string in quotes if necessary */ | ||||
|   p2 = newstr; | ||||
|   if(space_exists) { | ||||
|     newstr[0] = '"'; | ||||
|     newstr[newlen - 1] = '"'; | ||||
|     p2++; | ||||
|   } | ||||
|  | ||||
|   /* Copy the string, escaping backslash and quote characters along the way */ | ||||
|   p1 = str; | ||||
|   while(*p1) { | ||||
|     if(*p1 == '\\' || *p1 == '"') { | ||||
|       *p2 = '\\'; | ||||
|       p2++; | ||||
|     } | ||||
|  | ||||
|    *p2 = *p1; | ||||
|  | ||||
|     p1++; | ||||
|     p2++; | ||||
|   } | ||||
|  | ||||
|   /* Terminate the string */ | ||||
|   newstr[newlen] = '\0'; | ||||
|  | ||||
|   return newstr; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_is_bchar() | ||||
| @@ -2082,6 +2201,52 @@ static bool imap_is_bchar(char ch) | ||||
|   } | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_parse_url_options() | ||||
|  * | ||||
|  * Parse the URL login options. | ||||
|  */ | ||||
| static CURLcode imap_parse_url_options(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct imap_conn *imapc = &conn->proto.imapc; | ||||
|   const char *options = conn->options; | ||||
|   const char *ptr = options; | ||||
|  | ||||
|   if(options) { | ||||
|     const char *key = ptr; | ||||
|  | ||||
|     while(*ptr && *ptr != '=') | ||||
|         ptr++; | ||||
|  | ||||
|     if(strnequal(key, "AUTH", 4)) { | ||||
|       const char *value = ptr + 1; | ||||
|  | ||||
|       if(strequal(value, "*")) | ||||
|         imapc->prefmech = SASL_AUTH_ANY; | ||||
|       else if(strequal(value, "LOGIN")) | ||||
|         imapc->prefmech = SASL_MECH_LOGIN; | ||||
|       else if(strequal(value, "PLAIN")) | ||||
|         imapc->prefmech = SASL_MECH_PLAIN; | ||||
|       else if(strequal(value, "CRAM-MD5")) | ||||
|         imapc->prefmech = SASL_MECH_CRAM_MD5; | ||||
|       else if(strequal(value, "DIGEST-MD5")) | ||||
|         imapc->prefmech = SASL_MECH_DIGEST_MD5; | ||||
|       else if(strequal(value, "GSSAPI")) | ||||
|         imapc->prefmech = SASL_MECH_GSSAPI; | ||||
|       else if(strequal(value, "NTLM")) | ||||
|         imapc->prefmech = SASL_MECH_NTLM; | ||||
|       else | ||||
|         imapc->prefmech = SASL_AUTH_NONE; | ||||
|     } | ||||
|     else | ||||
|       result = CURLE_URL_MALFORMAT; | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_parse_url_path() | ||||
| @@ -2192,6 +2357,12 @@ static CURLcode imap_parse_url_path(struct connectdata *conn) | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_parse_custom_request() | ||||
|  * | ||||
|  * Parse the custom request. | ||||
|  */ | ||||
| static CURLcode imap_parse_custom_request(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
| @@ -2223,103 +2394,4 @@ static CURLcode imap_parse_custom_request(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* Call this when the DO phase has completed */ | ||||
| static CURLcode imap_dophase_done(struct connectdata *conn, bool connected) | ||||
| { | ||||
|   struct IMAP *imap = conn->data->state.proto.imap; | ||||
|  | ||||
|   (void)connected; | ||||
|  | ||||
|   if(imap->transfer != FTPTRANSFER_BODY) | ||||
|     /* no data to transfer */ | ||||
|     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* Called from multi.c while DOing */ | ||||
| static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done) | ||||
| { | ||||
|   CURLcode result = imap_multi_statemach(conn, dophase_done); | ||||
|  | ||||
|   if(result) | ||||
|     DEBUGF(infof(conn->data, "DO phase failed\n")); | ||||
|   else if(*dophase_done) { | ||||
|     result = imap_dophase_done(conn, FALSE /* not connected */); | ||||
|  | ||||
|     DEBUGF(infof(conn->data, "DO phase is complete\n")); | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * imap_regular_transfer() | ||||
|  * | ||||
|  * The input argument is already checked for validity. | ||||
|  * | ||||
|  * Performs all commands done before a regular transfer between a local and a | ||||
|  * remote host. | ||||
|  */ | ||||
| static CURLcode imap_regular_transfer(struct connectdata *conn, | ||||
|                                       bool *dophase_done) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   bool connected = FALSE; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|  | ||||
|   /* Make sure size is unknown at this point */ | ||||
|   data->req.size = -1; | ||||
|  | ||||
|   /* Set the progress data */ | ||||
|   Curl_pgrsSetUploadCounter(data, 0); | ||||
|   Curl_pgrsSetDownloadCounter(data, 0); | ||||
|   Curl_pgrsSetUploadSize(data, 0); | ||||
|   Curl_pgrsSetDownloadSize(data, 0); | ||||
|  | ||||
|   /* Carry out the perform */ | ||||
|   result = imap_perform(conn, &connected, dophase_done); | ||||
|  | ||||
|   /* Perform post DO phase operations if necessary */ | ||||
|   if(!result && *dophase_done) | ||||
|     result = imap_dophase_done(conn, connected); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode imap_setup_connection(struct connectdata *conn) | ||||
| { | ||||
|   struct SessionHandle *data = conn->data; | ||||
|  | ||||
|   if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) { | ||||
|     /* Unless we have asked to tunnel IMAP operations through the proxy, we | ||||
|        switch and use HTTP operations only */ | ||||
| #ifndef CURL_DISABLE_HTTP | ||||
|     if(conn->handler == &Curl_handler_imap) | ||||
|       conn->handler = &Curl_handler_imap_proxy; | ||||
|     else { | ||||
| #ifdef USE_SSL | ||||
|       conn->handler = &Curl_handler_imaps_proxy; | ||||
| #else | ||||
|       failf(data, "IMAPS not supported!"); | ||||
|       return CURLE_UNSUPPORTED_PROTOCOL; | ||||
| #endif | ||||
|     } | ||||
|  | ||||
|     /* We explicitly mark this connection as persistent here as we're doing | ||||
|        IMAP over HTTP and thus we accidentally avoid setting this value | ||||
|        otherwise */ | ||||
|     conn->bits.close = FALSE; | ||||
| #else | ||||
|     failf(data, "IMAP over http proxy requires HTTP support built-in!"); | ||||
|     return CURLE_UNSUPPORTED_PROTOCOL; | ||||
| #endif | ||||
|   } | ||||
|  | ||||
|   data->state.path++;   /* don't include the initial slash */ | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| #endif /* CURL_DISABLE_IMAP */ | ||||
|   | ||||
| @@ -76,6 +76,7 @@ struct imap_conn { | ||||
|   imapstate state;            /* Always use imap.c:state() to change state! */ | ||||
|   bool ssldone;               /* Is connect() over SSL done? */ | ||||
|   unsigned int authmechs;     /* Accepted authentication mechanisms */ | ||||
|   unsigned int prefmech;      /* Preferred authentication mechanism */ | ||||
|   unsigned int authused;      /* Auth mechanism used for the connection */ | ||||
|   int cmdid;                  /* Last used command ID */ | ||||
|   char resptag[5];            /* Response tag to wait for */ | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                | (__| |_| |  _ <| |___ | ||||
|  *                 \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -260,7 +260,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) | ||||
|     } | ||||
|     server = ldapssl_init(conn->host.name, (int)conn->port, 1); | ||||
|     if(server == NULL) { | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%hu", | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%ld", | ||||
|               conn->host.name, conn->port); | ||||
|       status = CURLE_COULDNT_CONNECT; | ||||
|       goto quit; | ||||
| @@ -301,7 +301,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) | ||||
|     } | ||||
|     server = ldap_init(conn->host.name, (int)conn->port); | ||||
|     if(server == NULL) { | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%hu", | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%ld", | ||||
|               conn->host.name, conn->port); | ||||
|       status = CURLE_COULDNT_CONNECT; | ||||
|       goto quit; | ||||
| @@ -337,7 +337,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) | ||||
|   else { | ||||
|     server = ldap_init(conn->host.name, (int)conn->port); | ||||
|     if(server == NULL) { | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%hu", | ||||
|       failf(data, "LDAP local: Cannot connect to %s:%ld", | ||||
|               conn->host.name, conn->port); | ||||
|       status = CURLE_COULDNT_CONNECT; | ||||
|       goto quit; | ||||
|   | ||||
							
								
								
									
										32
									
								
								lib/md5.c
									
									
									
									
									
								
							
							
						
						
									
										32
									
								
								lib/md5.c
									
									
									
									
									
								
							| @@ -90,16 +90,36 @@ static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx) | ||||
| #    include <md5.h> | ||||
| #  endif | ||||
|  | ||||
| #elif defined(__MAC_10_4) || defined(__IPHONE_5_0) | ||||
| #elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \ | ||||
|               (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \ | ||||
|       (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \ | ||||
|               (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000)) | ||||
|  | ||||
| /* For Apple operating systems: CommonCrypto has the functions we need. | ||||
|    The library's headers are even backward-compatible with OpenSSL's | ||||
|    headers as long as we define COMMON_DIGEST_FOR_OPENSSL first. | ||||
|    These functions are available on Tiger and later, as well as iOS 2.0 | ||||
|    and later. If you're building for an older cat, well, sorry. | ||||
|  | ||||
|    These functions are available on Tiger and later, as well as iOS 5.0 | ||||
|    and later. If you're building for an older cat, well, sorry. */ | ||||
| #  define COMMON_DIGEST_FOR_OPENSSL | ||||
|    Declaring the functions as static like this seems to be a bit more | ||||
|    reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */ | ||||
| #  include <CommonCrypto/CommonDigest.h> | ||||
| #  define MD5_CTX CC_MD5_CTX | ||||
|  | ||||
| static void MD5_Init(MD5_CTX *ctx) | ||||
| { | ||||
|   CC_MD5_Init(ctx); | ||||
| } | ||||
|  | ||||
| static void MD5_Update(MD5_CTX *ctx, | ||||
|                        const unsigned char *input, | ||||
|                        unsigned int inputLen) | ||||
| { | ||||
|   CC_MD5_Update(ctx, input, inputLen); | ||||
| } | ||||
|  | ||||
| static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx) | ||||
| { | ||||
|   CC_MD5_Final(digest, ctx); | ||||
| } | ||||
|  | ||||
| #elif defined(_WIN32) | ||||
|  | ||||
|   | ||||
| @@ -185,8 +185,10 @@ void *curl_domalloc(size_t wantedsize, int line, const char *source) | ||||
|   } | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d malloc(%zd) = %p\n", | ||||
|                 source, line, wantedsize, mem ? mem->mem : 0); | ||||
|     curl_memlog("MEM %s:%d malloc(%zu) = %p\n", | ||||
|                 source, line, wantedsize, | ||||
|                 mem ? (void *)mem->mem : (void *)0); | ||||
|  | ||||
|   return (mem ? mem->mem : NULL); | ||||
| } | ||||
|  | ||||
| @@ -212,7 +214,9 @@ void *curl_docalloc(size_t wanted_elements, size_t wanted_size, | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n", | ||||
|                 source, line, wanted_elements, wanted_size, mem?mem->mem:0); | ||||
|                 source, line, wanted_elements, wanted_size, | ||||
|                 mem ? (void *)mem->mem : (void *)0); | ||||
|  | ||||
|   return (mem ? mem->mem : NULL); | ||||
| } | ||||
|  | ||||
| @@ -234,12 +238,12 @@ char *curl_dostrdup(const char *str, int line, const char *source) | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n", | ||||
|                 source, line, str, len, mem); | ||||
|                 source, line, (void *)str, len, (void *)mem); | ||||
|  | ||||
|   return mem; | ||||
| } | ||||
|  | ||||
| #ifdef WIN32 | ||||
| #if defined(WIN32) && defined(UNICODE) | ||||
| wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source) | ||||
| { | ||||
|   wchar_t *mem; | ||||
| @@ -259,7 +263,7 @@ wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source) | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n", | ||||
|                 source, line, str, bsiz, mem); | ||||
|                 source, line, (void *)str, bsiz, (void *)mem); | ||||
|  | ||||
|   return mem; | ||||
| } | ||||
| @@ -295,7 +299,8 @@ void *curl_dorealloc(void *ptr, size_t wantedsize, | ||||
|   mem = (Curl_crealloc)(mem, size); | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n", | ||||
|                 source, line, ptr, wantedsize, mem?mem->mem:NULL); | ||||
|                 source, line, (void *)ptr, wantedsize, | ||||
|                 mem ? (void *)mem->mem : (void *)0); | ||||
|  | ||||
|   if(mem) { | ||||
|     mem->size = wantedsize; | ||||
| @@ -330,7 +335,7 @@ void curl_dofree(void *ptr, int line, const char *source) | ||||
|   (Curl_cfree)(mem); | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("MEM %s:%d free(%p)\n", source, line, ptr); | ||||
|     curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr); | ||||
| } | ||||
|  | ||||
| curl_socket_t curl_socket(int domain, int type, int protocol, | ||||
| @@ -343,8 +348,10 @@ curl_socket_t curl_socket(int domain, int type, int protocol, | ||||
|                     "FD %s:%d socket() = %zd\n" ; | ||||
|  | ||||
|   curl_socket_t sockfd = socket(domain, type, protocol); | ||||
|  | ||||
|   if(source && (sockfd != CURL_SOCKET_BAD)) | ||||
|     curl_memlog(fmt, source, line, sockfd); | ||||
|  | ||||
|   return sockfd; | ||||
| } | ||||
|  | ||||
| @@ -360,8 +367,10 @@ int curl_socketpair(int domain, int type, int protocol, | ||||
|                     "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 | ||||
| @@ -377,9 +386,12 @@ curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen, | ||||
|  | ||||
|   struct sockaddr *addr = (struct sockaddr *)saddr; | ||||
|   curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen; | ||||
|  | ||||
|   curl_socket_t sockfd = accept(s, addr, addrlen); | ||||
|  | ||||
|   if(source && (sockfd != CURL_SOCKET_BAD)) | ||||
|     curl_memlog(fmt, source, line, sockfd); | ||||
|  | ||||
|   return sockfd; | ||||
| } | ||||
|  | ||||
| @@ -408,9 +420,11 @@ FILE *curl_fopen(const char *file, const char *mode, | ||||
|                  int line, const char *source) | ||||
| { | ||||
|   FILE *res=fopen(file, mode); | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n", | ||||
|                 source, line, file, mode, res); | ||||
|                 source, line, file, mode, (void *)res); | ||||
|  | ||||
|   return res; | ||||
| } | ||||
|  | ||||
| @@ -419,9 +433,11 @@ FILE *curl_fdopen(int filedes, const char *mode, | ||||
|                   int line, const char *source) | ||||
| { | ||||
|   FILE *res=fdopen(filedes, mode); | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n", | ||||
|                 source, line, filedes, mode, res); | ||||
|                 source, line, filedes, mode, (void *)res); | ||||
|  | ||||
|   return res; | ||||
| } | ||||
| #endif | ||||
| @@ -433,9 +449,11 @@ int curl_fclose(FILE *file, int line, const char *source) | ||||
|   assert(file != NULL); | ||||
|  | ||||
|   res=fclose(file); | ||||
|  | ||||
|   if(source) | ||||
|     curl_memlog("FILE %s:%d fclose(%p)\n", | ||||
|                 source, line, file); | ||||
|                 source, line, (void *)file); | ||||
|  | ||||
|   return res; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -46,7 +46,7 @@ CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line, | ||||
|                                  const char *source); | ||||
| CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source); | ||||
| CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source); | ||||
| #ifdef WIN32 | ||||
| #if defined(WIN32) && defined(UNICODE) | ||||
| CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line, | ||||
|                                    const char *source); | ||||
| #endif | ||||
| @@ -90,14 +90,15 @@ CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source); | ||||
| #define free(ptr) curl_dofree(ptr, __LINE__, __FILE__) | ||||
|  | ||||
| #ifdef WIN32 | ||||
| #  undef wcsdup | ||||
| #  define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) | ||||
| #  undef _wcsdup | ||||
| #  define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) | ||||
| #  undef _tcsdup | ||||
| #  ifdef UNICODE | ||||
| #    undef wcsdup | ||||
| #    define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) | ||||
| #    undef _wcsdup | ||||
| #    define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) | ||||
| #    undef _tcsdup | ||||
| #    define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__) | ||||
| #  else | ||||
| #    undef _tcsdup | ||||
| #    define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__) | ||||
| #  endif | ||||
| #endif | ||||
|   | ||||
| @@ -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.18'; | ||||
| my $version = '1.19'; | ||||
|  | ||||
| $opt_w = 76; # default base64 encoded lines length | ||||
|  | ||||
| @@ -164,7 +164,7 @@ while (<TXT>) { | ||||
|   if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) { | ||||
|     $caname = $1; | ||||
|   } | ||||
|   my $untrusted = 0; | ||||
|   my $untrusted = 1; | ||||
|   if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) { | ||||
|     my $data; | ||||
|     while (<TXT>) { | ||||
| @@ -184,9 +184,8 @@ while (<TXT>) { | ||||
|     # now scan the trust part for untrusted certs | ||||
|     while (<TXT>) { | ||||
|       last if (/^#/); | ||||
|       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$/) { | ||||
|           $untrusted = 1; | ||||
|       if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUSTED_DELEGATOR$/) { | ||||
|           $untrusted = 0; | ||||
|       } | ||||
|     } | ||||
|     if ($untrusted) { | ||||
|   | ||||
| @@ -26,7 +26,7 @@ | ||||
| '* Hacked by Guenter Knauf | ||||
| '*************************************************************************** | ||||
| Option Explicit | ||||
| Const myVersion = "0.3.7" | ||||
| Const myVersion = "0.3.8" | ||||
|  | ||||
| Const myUrl = "http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1" | ||||
|  | ||||
| @@ -130,9 +130,8 @@ For i = 0 To UBound(myLines) | ||||
|       myInsideCert = FALSE | ||||
|       While (i < UBound(myLines)) And Not (myLines(i) = "#") | ||||
|         i = i + 1 | ||||
|         If (InstrRev(myLines(i), "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_NOT_TRUSTED") Or _ | ||||
|            InstrRev(myLines(i), "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUST_UNKNOWN")) Then | ||||
|           myUntrusted = TRUE | ||||
|         If InstrRev(myLines(i), "CKA_TRUST_SERVER_AUTH CK_TRUST CKT_NSS_TRUSTED_DELEGATOR") Then | ||||
|           myUntrusted = FALSE | ||||
|         End If | ||||
|       Wend | ||||
|       If (myUntrusted = TRUE) Then | ||||
| @@ -182,7 +181,7 @@ For i = 0 To UBound(myLines) | ||||
|   End If | ||||
|   If InstrRev(myLines(i), "CKA_VALUE MULTILINE_OCTAL") Then | ||||
|     myInsideCert = TRUE | ||||
|     myUntrusted = FALSE | ||||
|     myUntrusted = TRUE | ||||
|     myData = "" | ||||
|   End If | ||||
|   If InstrRev(myLines(i), "***** BEGIN LICENSE BLOCK *****") Then | ||||
|   | ||||
| @@ -380,11 +380,11 @@ static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos, | ||||
|         break; | ||||
|       case 'x': | ||||
|         vto[i].type = FORMAT_INT; | ||||
|         flags |= FLAGS_HEX; | ||||
|         flags |= FLAGS_HEX|FLAGS_UNSIGNED; | ||||
|         break; | ||||
|       case 'X': | ||||
|         vto[i].type = FORMAT_INT; | ||||
|         flags |= FLAGS_HEX|FLAGS_UPPER; | ||||
|         flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED; | ||||
|         break; | ||||
|       case 'c': | ||||
|         vto[i].type = FORMAT_INT; | ||||
| @@ -633,23 +633,23 @@ static int dprintf_formatf( | ||||
|             OUTCHAR(' '); | ||||
|         break; | ||||
|       } | ||||
|       if(p->flags & FLAGS_UNSIGNED) { | ||||
|         /* Decimal unsigned integer.  */ | ||||
|         base = 10; | ||||
|         goto unsigned_number; | ||||
|       } | ||||
|       if(p->flags & FLAGS_OCTAL) { | ||||
|         /* Octal unsigned integer.  */ | ||||
|         base = 8; | ||||
|         goto unsigned_number; | ||||
|       } | ||||
|       if(p->flags & FLAGS_HEX) { | ||||
|       else if(p->flags & FLAGS_HEX) { | ||||
|         /* Hexadecimal unsigned integer.  */ | ||||
|  | ||||
|         digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits; | ||||
|         base = 16; | ||||
|         goto unsigned_number; | ||||
|       } | ||||
|       else if(p->flags & FLAGS_UNSIGNED) { | ||||
|         /* Decimal unsigned integer.  */ | ||||
|         base = 10; | ||||
|         goto unsigned_number; | ||||
|       } | ||||
|  | ||||
|       /* Decimal integer.  */ | ||||
|       base = 10; | ||||
|   | ||||
							
								
								
									
										500
									
								
								lib/multi.c
									
									
									
									
									
								
							
							
						
						
									
										500
									
								
								lib/multi.c
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -59,27 +59,6 @@ typedef enum { | ||||
| #define GETSOCK_READABLE (0x00ff) | ||||
| #define GETSOCK_WRITABLE (0xff00) | ||||
|  | ||||
| struct Curl_one_easy { | ||||
|   /* first, two fields for the linked list of these */ | ||||
|   struct Curl_one_easy *next; | ||||
|   struct Curl_one_easy *prev; | ||||
|  | ||||
|   struct SessionHandle *easy_handle; /* the easy handle for this unit */ | ||||
|   struct connectdata *easy_conn;     /* the "unit's" connection */ | ||||
|  | ||||
|   CURLMstate state;  /* the handle's state */ | ||||
|   CURLcode result;   /* previous result */ | ||||
|  | ||||
|   struct Curl_message msg; /* A single posted message. */ | ||||
|  | ||||
|   /* Array with the plain socket numbers this handle takes care of, in no | ||||
|      particular order. Note that all sockets are added to the sockhash, where | ||||
|      the state etc are also kept. This array is mostly used to detect when a | ||||
|      socket is to be removed from the hash. See singlesocket(). */ | ||||
|   curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE]; | ||||
|   int numsocks; | ||||
| }; | ||||
|  | ||||
| /* This is the struct known as CURLM on the outside */ | ||||
| struct Curl_multi { | ||||
|   /* First a simple identifier to easier detect if a user mix up | ||||
| @@ -87,7 +66,8 @@ struct Curl_multi { | ||||
|   long type; | ||||
|  | ||||
|   /* We have a doubly-linked circular list with easy handles */ | ||||
|   struct Curl_one_easy easy; | ||||
|   struct SessionHandle *easyp; | ||||
|   struct SessionHandle *easylp; /* last node */ | ||||
|  | ||||
|   int num_easy; /* amount of entries in the linked list above. */ | ||||
|   int num_alive; /* amount of easy handles that are added but have not yet | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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,6 +22,8 @@ | ||||
|  * | ||||
|  ***************************************************************************/ | ||||
|  | ||||
|  | ||||
|  | ||||
| /* | ||||
|  * Prototypes for library-wide functions provided by multi.c | ||||
|  */ | ||||
| @@ -30,6 +32,10 @@ void Curl_expire(struct SessionHandle *data, long milli); | ||||
| bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi); | ||||
| void Curl_multi_handlePipeBreak(struct SessionHandle *data); | ||||
|  | ||||
| /* Internal version of curl_multi_init() accepts size parameters for the | ||||
|    socket and connection hashes */ | ||||
| struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize); | ||||
|  | ||||
| /* the write bits start at bit 16 for the *getsock() bitmap */ | ||||
| #define GETSOCK_WRITEBITSTART 16 | ||||
|  | ||||
| @@ -77,4 +83,16 @@ struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi); | ||||
| /* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */ | ||||
| size_t Curl_multi_max_total_connections(struct Curl_multi *multi); | ||||
|  | ||||
| /* | ||||
|  * Curl_multi_closed() | ||||
|  * | ||||
|  * Used by the connect code to tell the multi_socket code that one of the | ||||
|  * sockets we were using have just been closed.  This function will then | ||||
|  * remove it from the sockethash for this handle to make the multi_socket API | ||||
|  * behave properly, especially for the case when libcurl will create another | ||||
|  * socket again and it gets the same file descriptor number. | ||||
|  */ | ||||
|  | ||||
| void Curl_multi_closed(struct connectdata *conn, curl_socket_t s); | ||||
|  | ||||
| #endif /* HEADER_CURL_MULTIIF_H */ | ||||
|   | ||||
							
								
								
									
										11
									
								
								lib/nss.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								lib/nss.c
									
									
									
									
									
								
							| @@ -1482,10 +1482,8 @@ static ssize_t nss_send(struct connectdata *conn,  /* connection data */ | ||||
|                         size_t len,                /* amount to write */ | ||||
|                         CURLcode *curlcode) | ||||
| { | ||||
|   int rc; | ||||
|  | ||||
|   rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, -1); | ||||
|  | ||||
|   ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0, | ||||
|                        PR_INTERVAL_NO_WAIT); | ||||
|   if(rc < 0) { | ||||
|     PRInt32 err = PR_GetError(); | ||||
|     if(err == PR_WOULD_BLOCK_ERROR) | ||||
| @@ -1513,9 +1511,8 @@ static ssize_t nss_recv(struct connectdata * conn, /* connection data */ | ||||
|                         size_t buffersize,         /* max amount to read */ | ||||
|                         CURLcode *curlcode) | ||||
| { | ||||
|   ssize_t nread; | ||||
|  | ||||
|   nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, -1); | ||||
|   ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0, | ||||
|                           PR_INTERVAL_NO_WAIT); | ||||
|   if(nread < 0) { | ||||
|     /* failed SSL read */ | ||||
|     PRInt32 err = PR_GetError(); | ||||
|   | ||||
| @@ -7,7 +7,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -60,6 +60,10 @@ void Curl_nss_md5sum(unsigned char *tmp, /* input */ | ||||
|                      unsigned char *md5sum, /* output */ | ||||
|                      size_t md5len); | ||||
|  | ||||
| /* this backend provides these functions: */ | ||||
| #define have_curlssl_random 1 | ||||
| #define have_curlssl_md5sum 1 | ||||
|  | ||||
| /* API setup for NSS */ | ||||
| #define curlssl_init Curl_nss_init | ||||
| #define curlssl_cleanup Curl_nss_cleanup | ||||
|   | ||||
| @@ -6,6 +6,7 @@ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se> | ||||
|  * Copyright (C) 2013, 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 | ||||
| @@ -84,9 +85,10 @@ bool Curl_pipeline_penalized(struct SessionHandle *data, | ||||
|        (curl_off_t)conn->chunk.datasize > chunk_penalty_size) | ||||
|       penalized = TRUE; | ||||
|  | ||||
|     infof(data, "Conn: %d (%p) Receive pipe weight: (%d/%d), penalized: %d\n", | ||||
|           conn->connection_id, conn, recv_size, | ||||
|           conn->chunk.datasize, penalized); | ||||
|     infof(data, "Conn: %ld (%p) Receive pipe weight: (%" FORMAT_OFF_T | ||||
|           "/%zu), penalized: %s\n", | ||||
|           conn->connection_id, (void *)conn, recv_size, | ||||
|           conn->chunk.datasize, penalized?"TRUE":"FALSE"); | ||||
|     return penalized; | ||||
|   } | ||||
|   return FALSE; | ||||
| @@ -101,7 +103,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, | ||||
|  | ||||
|   pipeline = conn->send_pipe; | ||||
|  | ||||
|   infof(conn->data, "Adding handle: conn: %p\n", conn); | ||||
|   infof(conn->data, "Adding handle: conn: %p\n", (void *)conn); | ||||
|   infof(conn->data, "Adding handle: send: %d\n", conn->send_pipe->size); | ||||
|   infof(conn->data, "Adding handle: recv: %d\n", conn->recv_pipe->size); | ||||
|   rc = Curl_addHandleToPipeline(handle, pipeline); | ||||
| @@ -111,7 +113,7 @@ CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle, | ||||
|     conn->writechannel_inuse = FALSE; /* not in use yet */ | ||||
| #ifdef DEBUGBUILD | ||||
|     infof(conn->data, "%p is at send pipe head!\n", | ||||
|           conn->send_pipe->head->ptr); | ||||
|           (void *)conn->send_pipe->head->ptr); | ||||
| #endif | ||||
|     Curl_expire(conn->send_pipe->head->ptr, 1); | ||||
|   } | ||||
| @@ -144,7 +146,7 @@ void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle, | ||||
|         conn->writechannel_inuse = FALSE; /* not used now */ | ||||
| #ifdef DEBUGBUILD | ||||
|         infof(conn->data, "%p is at send pipe head B!\n", | ||||
|               conn->send_pipe->head->ptr); | ||||
|               (void *)conn->send_pipe->head->ptr); | ||||
| #endif | ||||
|         Curl_expire(conn->send_pipe->head->ptr, 1); | ||||
|       } | ||||
| @@ -320,9 +322,9 @@ void print_pipeline(struct connectdata *conn) | ||||
|     curr = cb_ptr->conn_list->head; | ||||
|     while(curr) { | ||||
|       conn = curr->ptr; | ||||
|       infof(data, "- Conn %d (%p) send_pipe: %d, recv_pipe: %d\n", | ||||
|       infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n", | ||||
|             conn->connection_id, | ||||
|             conn, | ||||
|             (void *)conn, | ||||
|             conn->send_pipe->size, | ||||
|             conn->recv_pipe->size); | ||||
|       curr = curr->next; | ||||
|   | ||||
							
								
								
									
										482
									
								
								lib/pop3.c
									
									
									
									
									
								
							
							
						
						
									
										482
									
								
								lib/pop3.c
									
									
									
									
									
								
							| @@ -90,8 +90,6 @@ | ||||
| #include "memdebug.h" | ||||
|  | ||||
| /* Local API functions */ | ||||
| static CURLcode pop3_parse_url_path(struct connectdata *conn); | ||||
| static CURLcode pop3_parse_custom_request(struct connectdata *conn); | ||||
| static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done); | ||||
| static CURLcode pop3_do(struct connectdata *conn, bool *done); | ||||
| static CURLcode pop3_done(struct connectdata *conn, CURLcode status, | ||||
| @@ -103,6 +101,9 @@ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, | ||||
|                         int numsocks); | ||||
| static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done); | ||||
| static CURLcode pop3_setup_connection(struct connectdata *conn); | ||||
| static CURLcode pop3_parse_url_options(struct connectdata *conn); | ||||
| static CURLcode pop3_parse_url_path(struct connectdata *conn); | ||||
| static CURLcode pop3_parse_custom_request(struct connectdata *conn); | ||||
|  | ||||
| /* | ||||
|  * POP3 protocol handler. | ||||
| @@ -216,10 +217,15 @@ static void pop3_to_pop3s(struct connectdata *conn) | ||||
| #define pop3_to_pop3s(x) Curl_nop_stmt | ||||
| #endif | ||||
|  | ||||
| /* Function that checks for an ending POP3 status code at the start of the | ||||
|    given string, but also detects the APOP timestamp from the server greeting | ||||
|    and various capabilities from the CAPA response including the supported | ||||
|    authentication types and allowed SASL mechanisms. */ | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_endofresp() | ||||
|  * | ||||
|  * Checks for an ending POP3 status code at the start of the given string, but | ||||
|  * also detects the APOP timestamp from the server greeting and various | ||||
|  * capabilities from the CAPA response including the supported authentication | ||||
|  * types and allowed SASL mechanisms. | ||||
|  */ | ||||
| static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, | ||||
|                            int *resp) | ||||
| { | ||||
| @@ -340,7 +346,12 @@ static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len, | ||||
|   return FALSE; /* Nothing for us */ | ||||
| } | ||||
|  | ||||
| /* This is the ONLY way to change POP3 state! */ | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * state() | ||||
|  * | ||||
|  * This is the ONLY way to change POP3 state! | ||||
|  */ | ||||
| static void state(struct connectdata *conn, pop3state newstate) | ||||
| { | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
| @@ -371,13 +382,20 @@ static void state(struct connectdata *conn, pop3state newstate) | ||||
|  | ||||
|   if(pop3c->state != newstate) | ||||
|     infof(conn->data, "POP3 %p state change from %s to %s\n", | ||||
|           pop3c, names[pop3c->state], names[newstate]); | ||||
|           (void *)pop3c, names[pop3c->state], names[newstate]); | ||||
| #endif | ||||
|  | ||||
|   pop3c->state = newstate; | ||||
| } | ||||
|  | ||||
| static CURLcode pop3_state_capa(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_capa() | ||||
|  * | ||||
|  * Sends the CAPA command in order to obtain a list of server side supported | ||||
|  * capabilities. | ||||
|  */ | ||||
| static CURLcode pop3_perform_capa(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
| @@ -387,7 +405,7 @@ static CURLcode pop3_state_capa(struct connectdata *conn) | ||||
|   pop3c->tls_supported = FALSE; /* Clear the TLS capability */ | ||||
|  | ||||
|   /* Send the CAPA command */ | ||||
|   result = Curl_pp_sendf(&pop3c->pp, "CAPA"); | ||||
|   result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA"); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_CAPA); | ||||
| @@ -395,12 +413,18 @@ static CURLcode pop3_state_capa(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode pop3_state_starttls(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_starttls() | ||||
|  * | ||||
|  * Sends the STLS command to start the upgrade to TLS. | ||||
|  */ | ||||
| static CURLcode pop3_perform_starttls(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
|   /* Send the STLS command */ | ||||
|   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "STLS"); | ||||
|   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS"); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_STARTTLS); | ||||
| @@ -408,7 +432,13 @@ static CURLcode pop3_state_starttls(struct connectdata *conn) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode pop3_state_upgrade_tls(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_upgrade_tls() | ||||
|  * | ||||
|  * Performs the upgrade to TLS. | ||||
|  */ | ||||
| static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
| @@ -422,14 +452,20 @@ static CURLcode pop3_state_upgrade_tls(struct connectdata *conn) | ||||
|  | ||||
|     if(pop3c->ssldone) { | ||||
|       pop3_to_pop3s(conn); | ||||
|       result = pop3_state_capa(conn); | ||||
|       result = pop3_perform_capa(conn); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| static CURLcode pop3_state_user(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_user() | ||||
|  * | ||||
|  * Sends a clear text USER command to authenticate with. | ||||
|  */ | ||||
| static CURLcode pop3_perform_user(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
| @@ -451,7 +487,13 @@ static CURLcode pop3_state_user(struct connectdata *conn) | ||||
| } | ||||
|  | ||||
| #ifndef CURL_DISABLE_CRYPTO_AUTH | ||||
| static CURLcode pop3_state_apop(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_apop() | ||||
|  * | ||||
|  * Sends an APOP command to authenticate with. | ||||
|  */ | ||||
| static CURLcode pop3_perform_apop(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
| @@ -495,12 +537,26 @@ static CURLcode pop3_state_apop(struct connectdata *conn) | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static CURLcode pop3_authenticate(struct connectdata *conn) | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_authenticate() | ||||
|  * | ||||
|  * Sends an AUTH command allowing the client to login with the appropriate | ||||
|  * SASL authentication mechanism. | ||||
|  * | ||||
|  * Additionally, the function will perform fallback to APOP and USER commands | ||||
|  * should a common mechanism not be available between the client and server. | ||||
|  */ | ||||
| static CURLcode pop3_perform_authenticate(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
|   const char *mech = NULL; | ||||
|   pop3state authstate = POP3_STOP; | ||||
|   char *initresp = NULL; | ||||
|   size_t len = 0; | ||||
|   pop3state state1 = POP3_STOP; | ||||
|   pop3state state2 = POP3_STOP; | ||||
|  | ||||
|   /* Check we have a username and password to authenticate with and end the | ||||
|      connect phase if we don't */ | ||||
| @@ -514,62 +570,158 @@ static CURLcode pop3_authenticate(struct connectdata *conn) | ||||
|      security */ | ||||
|   if(pop3c->authtypes & POP3_TYPE_SASL) { | ||||
| #ifndef CURL_DISABLE_CRYPTO_AUTH | ||||
|     if(pop3c->authmechs & SASL_MECH_DIGEST_MD5) { | ||||
|     if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) && | ||||
|        (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) { | ||||
|       mech = "DIGEST-MD5"; | ||||
|       authstate = POP3_AUTH_DIGESTMD5; | ||||
|       state1 = POP3_AUTH_DIGESTMD5; | ||||
|       pop3c->authused = SASL_MECH_DIGEST_MD5; | ||||
|     } | ||||
|     else if(pop3c->authmechs & SASL_MECH_CRAM_MD5) { | ||||
|     else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) && | ||||
|             (pop3c->prefmech & SASL_MECH_CRAM_MD5)) { | ||||
|       mech = "CRAM-MD5"; | ||||
|       authstate = POP3_AUTH_CRAMMD5; | ||||
|       state1 = POP3_AUTH_CRAMMD5; | ||||
|       pop3c->authused = SASL_MECH_CRAM_MD5; | ||||
|     } | ||||
|     else | ||||
| #endif | ||||
| #ifdef USE_NTLM | ||||
|     if(pop3c->authmechs & SASL_MECH_NTLM) { | ||||
|     if((pop3c->authmechs & SASL_MECH_NTLM) && | ||||
|        (pop3c->prefmech & SASL_MECH_NTLM)) { | ||||
|       mech = "NTLM"; | ||||
|       authstate = POP3_AUTH_NTLM; | ||||
|       state1 = POP3_AUTH_NTLM; | ||||
|       state2 = POP3_AUTH_NTLM_TYPE2MSG; | ||||
|       pop3c->authused = SASL_MECH_NTLM; | ||||
|  | ||||
|       if(data->set.sasl_ir) | ||||
|         result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd, | ||||
|                                                      &conn->ntlm, | ||||
|                                                      &initresp, &len); | ||||
|     } | ||||
|     else | ||||
| #endif | ||||
|     if(pop3c->authmechs & SASL_MECH_LOGIN) { | ||||
|     if((pop3c->authmechs & SASL_MECH_LOGIN) && | ||||
|        (pop3c->prefmech & SASL_MECH_LOGIN)) { | ||||
|       mech = "LOGIN"; | ||||
|       authstate = POP3_AUTH_LOGIN; | ||||
|       state1 = POP3_AUTH_LOGIN; | ||||
|       state2 = POP3_AUTH_LOGIN_PASSWD; | ||||
|       pop3c->authused = SASL_MECH_LOGIN; | ||||
|  | ||||
|       if(data->set.sasl_ir) | ||||
|         result = Curl_sasl_create_login_message(conn->data, conn->user, | ||||
|                                                 &initresp, &len); | ||||
|     } | ||||
|     else if(pop3c->authmechs & SASL_MECH_PLAIN) { | ||||
|     else if((pop3c->authmechs & SASL_MECH_PLAIN) && | ||||
|             (pop3c->prefmech & SASL_MECH_PLAIN)) { | ||||
|       mech = "PLAIN"; | ||||
|       authstate = POP3_AUTH_PLAIN; | ||||
|       state1 = POP3_AUTH_PLAIN; | ||||
|       state2 = POP3_AUTH_FINAL; | ||||
|       pop3c->authused = SASL_MECH_PLAIN; | ||||
|  | ||||
|       if(data->set.sasl_ir) | ||||
|         result = Curl_sasl_create_plain_message(conn->data, conn->user, | ||||
|                                                 conn->passwd, &initresp, | ||||
|                                                 &len); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if(mech) { | ||||
|     /* Perform SASL based authentication */ | ||||
|     result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); | ||||
|   if(!result) { | ||||
|     if(mech && (pop3c->preftype & POP3_TYPE_SASL)) { | ||||
|       /* Perform SASL based authentication */ | ||||
|       if(initresp && | ||||
|          8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */ | ||||
|         result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp); | ||||
|  | ||||
|     if(!result) | ||||
|       state(conn, authstate); | ||||
|   } | ||||
|         if(!result) | ||||
|           state(conn, state2); | ||||
|       } | ||||
|       else { | ||||
|         result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech); | ||||
|  | ||||
|         if(!result) | ||||
|           state(conn, state1); | ||||
|       } | ||||
|  | ||||
|       Curl_safefree(initresp); | ||||
|     } | ||||
| #ifndef CURL_DISABLE_CRYPTO_AUTH | ||||
|   else if(pop3c->authtypes & POP3_TYPE_APOP) | ||||
|     /* Perform APOP authentication */ | ||||
|     result = pop3_state_apop(conn); | ||||
|     else if((pop3c->authtypes & POP3_TYPE_APOP) && | ||||
|             (pop3c->preftype & POP3_TYPE_APOP)) | ||||
|       /* Perform APOP authentication */ | ||||
|       result = pop3_perform_apop(conn); | ||||
| #endif | ||||
|   else if(pop3c->authtypes & POP3_TYPE_CLEARTEXT) | ||||
|     /* Perform clear text authentication */ | ||||
|     result = pop3_state_user(conn); | ||||
|   else { | ||||
|     /* Other mechanisms not supported */ | ||||
|     infof(conn->data, "No known authentication mechanisms supported!\n"); | ||||
|     result = CURLE_LOGIN_DENIED; | ||||
|     else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) && | ||||
|             (pop3c->preftype & POP3_TYPE_CLEARTEXT)) | ||||
|       /* Perform clear text authentication */ | ||||
|       result = pop3_perform_user(conn); | ||||
|     else { | ||||
|       /* Other mechanisms not supported */ | ||||
|       infof(conn->data, "No known authentication mechanisms supported!\n"); | ||||
|       result = CURLE_LOGIN_DENIED; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_command() | ||||
|  * | ||||
|  * Sends a POP3 based command. | ||||
|  */ | ||||
| static CURLcode pop3_perform_command(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *command = NULL; | ||||
|  | ||||
|   /* Calculate the default command */ | ||||
|   if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { | ||||
|     command = "LIST"; | ||||
|  | ||||
|     if(pop3->id[0] != '\0') | ||||
|       /* Message specific LIST so skip the BODY transfer */ | ||||
|       pop3->transfer = FTPTRANSFER_INFO; | ||||
|   } | ||||
|   else | ||||
|     command = "RETR"; | ||||
|  | ||||
|   /* Send the command */ | ||||
|   if(pop3->id[0] != '\0') | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", | ||||
|                            (pop3->custom && pop3->custom[0] != '\0' ? | ||||
|                             pop3->custom : command), pop3->id); | ||||
|   else | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", | ||||
|                            (pop3->custom && pop3->custom[0] != '\0' ? | ||||
|                             pop3->custom : command)); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_COMMAND); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_perform_quit() | ||||
|  * | ||||
|  * Performs the quit action prior to sclose() be called. | ||||
|  */ | ||||
| static CURLcode pop3_perform_quit(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
|   /* Send the QUIT command */ | ||||
|   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT"); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_QUIT); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* For the initial server greeting */ | ||||
| static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, | ||||
|                                             int pop3code, | ||||
| @@ -582,10 +734,10 @@ static CURLcode pop3_state_servergreet_resp(struct connectdata *conn, | ||||
|  | ||||
|   if(pop3code != '+') { | ||||
|     failf(data, "Got unexpected pop3-server response"); | ||||
|     return CURLE_FTP_WEIRD_SERVER_REPLY; | ||||
|     result = CURLE_FTP_WEIRD_SERVER_REPLY; | ||||
|   } | ||||
|  | ||||
|   result = pop3_state_capa(conn); | ||||
|   else | ||||
|     result = pop3_perform_capa(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
| @@ -601,22 +753,22 @@ static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code, | ||||
|   (void)instate; /* no use for this yet */ | ||||
|  | ||||
|   if(pop3code != '+') | ||||
|     result = pop3_state_user(conn); | ||||
|     result = pop3_perform_user(conn); | ||||
|   else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) { | ||||
|     /* We don't have a SSL/TLS connection yet, but SSL is requested */ | ||||
|     if(pop3c->tls_supported) | ||||
|       /* Switch to TLS connection now */ | ||||
|       result = pop3_state_starttls(conn); | ||||
|       result = pop3_perform_starttls(conn); | ||||
|     else if(data->set.use_ssl == CURLUSESSL_TRY) | ||||
|       /* Fallback and carry on with authentication */ | ||||
|       result = pop3_authenticate(conn); | ||||
|       result = pop3_perform_authenticate(conn); | ||||
|     else { | ||||
|       failf(data, "STLS not supported."); | ||||
|       result = CURLE_USE_SSL_FAILED; | ||||
|     } | ||||
|   } | ||||
|   else | ||||
|     result = pop3_authenticate(conn); | ||||
|     result = pop3_perform_authenticate(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
| @@ -637,15 +789,15 @@ static CURLcode pop3_state_starttls_resp(struct connectdata *conn, | ||||
|       result = CURLE_USE_SSL_FAILED; | ||||
|     } | ||||
|     else | ||||
|       result = pop3_authenticate(conn); | ||||
|       result = pop3_perform_authenticate(conn); | ||||
|   } | ||||
|   else | ||||
|     result = pop3_state_upgrade_tls(conn); | ||||
|     result = pop3_perform_upgrade_tls(conn); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* For AUTH PLAIN responses */ | ||||
| /* For AUTH PLAIN (without initial response) responses */ | ||||
| static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, | ||||
|                                            int pop3code, | ||||
|                                            pop3state instate) | ||||
| @@ -682,7 +834,7 @@ static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn, | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* For AUTH LOGIN responses */ | ||||
| /* For AUTH LOGIN (without initial response) responses */ | ||||
| static CURLcode pop3_state_auth_login_resp(struct connectdata *conn, | ||||
|                                            int pop3code, | ||||
|                                            pop3state instate) | ||||
| @@ -868,7 +1020,7 @@ static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, | ||||
|   } | ||||
|   else { | ||||
|     /* Send an empty response */ | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, ""); | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", ""); | ||||
|  | ||||
|     if(!result) | ||||
|       state(conn, POP3_AUTH_FINAL); | ||||
| @@ -879,7 +1031,7 @@ static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn, | ||||
| #endif | ||||
|  | ||||
| #ifdef USE_NTLM | ||||
| /* For AUTH NTLM responses */ | ||||
| /* For AUTH NTLM (without initial response) responses */ | ||||
| static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn, | ||||
|                                           int pop3code, | ||||
|                                           pop3state instate) | ||||
| @@ -980,6 +1132,7 @@ static CURLcode pop3_state_auth_final_resp(struct connectdata *conn, | ||||
| } | ||||
|  | ||||
| #ifndef CURL_DISABLE_CRYPTO_AUTH | ||||
| /* For APOP responses */ | ||||
| static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code, | ||||
|                                      pop3state instate) | ||||
| { | ||||
| @@ -1043,41 +1196,6 @@ static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code, | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* Start the DO phase for the command */ | ||||
| static CURLcode pop3_command(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *command = NULL; | ||||
|  | ||||
|   /* Calculate the default command */ | ||||
|   if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) { | ||||
|     command = "LIST"; | ||||
|  | ||||
|     if(pop3->id[0] != '\0') | ||||
|       /* Message specific LIST so skip the BODY transfer */ | ||||
|       pop3->transfer = FTPTRANSFER_INFO; | ||||
|   } | ||||
|   else | ||||
|     command = "RETR"; | ||||
|  | ||||
|   /* Send the command */ | ||||
|   if(pop3->id[0] != '\0') | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s", | ||||
|                            (pop3->custom && pop3->custom[0] != '\0' ? | ||||
|                             pop3->custom : command), pop3->id); | ||||
|   else | ||||
|     result = Curl_pp_sendf(&conn->proto.pop3c.pp, | ||||
|                            (pop3->custom && pop3->custom[0] != '\0' ? | ||||
|                             pop3->custom : command)); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_COMMAND); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* For command responses */ | ||||
| static CURLcode pop3_state_command_resp(struct connectdata *conn, | ||||
|                                         int pop3code, | ||||
| @@ -1146,7 +1264,7 @@ static CURLcode pop3_statemach_act(struct connectdata *conn) | ||||
|  | ||||
|   /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */ | ||||
|   if(pop3c->state == POP3_UPGRADETLS) | ||||
|     return pop3_state_upgrade_tls(conn); | ||||
|     return pop3_perform_upgrade_tls(conn); | ||||
|  | ||||
|   /* Flush any data that needs to be sent */ | ||||
|   if(pp->sendleft) | ||||
| @@ -1303,8 +1421,7 @@ static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks, | ||||
|  * 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. | ||||
|  * phase is done when this function returns, or FALSE if not. | ||||
|  */ | ||||
| static CURLcode pop3_connect(struct connectdata *conn, bool *done) | ||||
| { | ||||
| @@ -1332,9 +1449,18 @@ static CURLcode pop3_connect(struct connectdata *conn, bool *done) | ||||
|   pp->endofresp = pop3_endofresp; | ||||
|   pp->conn = conn; | ||||
|  | ||||
|   /* Set the default preferred authentication type and mechanism */ | ||||
|   pop3c->preftype = POP3_TYPE_ANY; | ||||
|   pop3c->prefmech = SASL_AUTH_ANY; | ||||
|  | ||||
|   /* Initialise the pingpong layer */ | ||||
|   Curl_pp_init(pp); | ||||
|  | ||||
|   /* Parse the URL options */ | ||||
|   result = pop3_parse_url_options(conn); | ||||
|   if(result) | ||||
|     return result; | ||||
|  | ||||
|   /* Start off waiting for the server greeting response */ | ||||
|   state(conn, POP3_SERVERGREET); | ||||
|  | ||||
| @@ -1407,7 +1533,7 @@ static CURLcode pop3_perform(struct connectdata *conn, bool *connected, | ||||
|   *dophase_done = FALSE; /* not done yet */ | ||||
|  | ||||
|   /* Start the first command in the DO phase */ | ||||
|   result = pop3_command(conn); | ||||
|   result = pop3_perform_command(conn); | ||||
|   if(result) | ||||
|     return result; | ||||
|  | ||||
| @@ -1461,25 +1587,6 @@ static CURLcode pop3_do(struct connectdata *conn, bool *done) | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_quit() | ||||
|  * | ||||
|  * Performs the quit action prior to sclose() be called. | ||||
|  */ | ||||
| static CURLcode pop3_quit(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|  | ||||
|   /* Send the QUIT command */ | ||||
|   result = Curl_pp_sendf(&conn->proto.pop3c.pp, "QUIT"); | ||||
|  | ||||
|   if(!result) | ||||
|     state(conn, POP3_QUIT); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_disconnect() | ||||
| @@ -1499,7 +1606,7 @@ static CURLcode pop3_disconnect(struct connectdata *conn, | ||||
|   /* The POP3 session may or may not have been allocated/setup at this | ||||
|      point! */ | ||||
|   if(!dead_connection && pop3c->pp.conn) | ||||
|     if(!pop3_quit(conn)) | ||||
|     if(!pop3_perform_quit(conn)) | ||||
|       (void)pop3_block_statemach(conn); /* ignore errors on QUIT */ | ||||
|  | ||||
|   /* Disconnect from the server */ | ||||
| @@ -1514,37 +1621,6 @@ static CURLcode pop3_disconnect(struct connectdata *conn, | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_parse_url_path() | ||||
|  * | ||||
|  * Parse the URL path into separate path components. | ||||
|  */ | ||||
| static CURLcode pop3_parse_url_path(struct connectdata *conn) | ||||
| { | ||||
|   /* The POP3 struct is already initialised in pop3_connect() */ | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *path = data->state.path; | ||||
|  | ||||
|   /* URL decode the path for the message ID */ | ||||
|   return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); | ||||
| } | ||||
|  | ||||
| static CURLcode pop3_parse_custom_request(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *custom = data->set.str[STRING_CUSTOMREQUEST]; | ||||
|  | ||||
|   /* URL decode the custom request */ | ||||
|   if(custom) | ||||
|     result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /* Call this when the DO phase has completed */ | ||||
| static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected) | ||||
| { | ||||
| @@ -1639,8 +1715,116 @@ static CURLcode pop3_setup_connection(struct connectdata *conn) | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| /* This function scans the body after the end-of-body and writes everything | ||||
|    until the end is found */ | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_parse_url_options() | ||||
|  * | ||||
|  * Parse the URL login options. | ||||
|  */ | ||||
| static CURLcode pop3_parse_url_options(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct pop3_conn *pop3c = &conn->proto.pop3c; | ||||
|   const char *options = conn->options; | ||||
|   const char *ptr = options; | ||||
|  | ||||
|   if(options) { | ||||
|     const char *key = ptr; | ||||
|  | ||||
|     while(*ptr && *ptr != '=') | ||||
|         ptr++; | ||||
|  | ||||
|     if(strnequal(key, "AUTH", 4)) { | ||||
|       const char *value = ptr + 1; | ||||
|  | ||||
|       if(strequal(value, "*")) { | ||||
|         pop3c->preftype = POP3_TYPE_ANY; | ||||
|         pop3c->prefmech = SASL_AUTH_ANY; | ||||
|       } | ||||
|       else if(strequal(value, "+APOP")) { | ||||
|         pop3c->preftype = POP3_TYPE_APOP; | ||||
|         pop3c->prefmech = SASL_AUTH_NONE; | ||||
|       } | ||||
|       else if(strequal(value, "LOGIN")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_LOGIN; | ||||
|       } | ||||
|       else if(strequal(value, "PLAIN")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_PLAIN; | ||||
|       } | ||||
|       else if(strequal(value, "CRAM-MD5")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_CRAM_MD5; | ||||
|       } | ||||
|       else if(strequal(value, "DIGEST-MD5")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_DIGEST_MD5; | ||||
|       } | ||||
|       else if(strequal(value, "GSSAPI")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_GSSAPI; | ||||
|       } | ||||
|       else if(strequal(value, "NTLM")) { | ||||
|         pop3c->preftype = POP3_TYPE_SASL; | ||||
|         pop3c->prefmech = SASL_MECH_NTLM; | ||||
|       } | ||||
|       else { | ||||
|         pop3c->preftype = POP3_TYPE_NONE; | ||||
|         pop3c->prefmech = SASL_AUTH_NONE; | ||||
|       } | ||||
|     } | ||||
|     else | ||||
|       result = CURLE_URL_MALFORMAT; | ||||
|   } | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_parse_url_path() | ||||
|  * | ||||
|  * Parse the URL path into separate path components. | ||||
|  */ | ||||
| static CURLcode pop3_parse_url_path(struct connectdata *conn) | ||||
| { | ||||
|   /* The POP3 struct is already initialised in pop3_connect() */ | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *path = data->state.path; | ||||
|  | ||||
|   /* URL decode the path for the message ID */ | ||||
|   return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE); | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * pop3_parse_custom_request() | ||||
|  * | ||||
|  * Parse the custom request. | ||||
|  */ | ||||
| static CURLcode pop3_parse_custom_request(struct connectdata *conn) | ||||
| { | ||||
|   CURLcode result = CURLE_OK; | ||||
|   struct SessionHandle *data = conn->data; | ||||
|   struct POP3 *pop3 = data->state.proto.pop3; | ||||
|   const char *custom = data->set.str[STRING_CUSTOMREQUEST]; | ||||
|  | ||||
|   /* URL decode the custom request */ | ||||
|   if(custom) | ||||
|     result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE); | ||||
|  | ||||
|   return result; | ||||
| } | ||||
|  | ||||
| /*********************************************************************** | ||||
|  * | ||||
|  * Curl_pop3_write() | ||||
|  * | ||||
|  * This function scans the body after the end-of-body and writes everything | ||||
|  * until the end is found. | ||||
|  */ | ||||
| CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread) | ||||
| { | ||||
|   /* This code could be made into a special function in the handler struct */ | ||||
|   | ||||
							
								
								
									
										14
									
								
								lib/pop3.h
									
									
									
									
									
								
							
							
						
						
									
										14
									
								
								lib/pop3.h
									
									
									
									
									
								
							| @@ -72,8 +72,10 @@ struct pop3_conn { | ||||
|                              have been received so far */ | ||||
|   size_t strip;           /* Number of bytes from the start to ignore as | ||||
|                              non-body */ | ||||
|   unsigned int authtypes; /* Supported authentication types */ | ||||
|   unsigned int authtypes; /* Accepted authentication types */ | ||||
|   unsigned int authmechs; /* Accepted SASL authentication mechanisms */ | ||||
|   unsigned int preftype;  /* Preferred authentication type */ | ||||
|   unsigned int prefmech;  /* Preferred SASL authentication mechanism */ | ||||
|   unsigned int authused;  /* SASL auth mechanism used for the connection */ | ||||
|   char *apoptimestamp;    /* APOP timestamp from the server greeting */ | ||||
|   bool tls_supported;     /* StartTLS capability supported by server */ | ||||
| @@ -83,9 +85,13 @@ extern const struct Curl_handler Curl_handler_pop3; | ||||
| extern const struct Curl_handler Curl_handler_pop3s; | ||||
|  | ||||
| /* Authentication type flags */ | ||||
| #define POP3_TYPE_CLEARTEXT 0x0001 | ||||
| #define POP3_TYPE_APOP      0x0002 | ||||
| #define POP3_TYPE_SASL      0x0004 | ||||
| #define POP3_TYPE_CLEARTEXT (1 << 0) | ||||
| #define POP3_TYPE_APOP      (1 << 1) | ||||
| #define POP3_TYPE_SASL      (1 << 2) | ||||
|  | ||||
| /* Authentication type values */ | ||||
| #define POP3_TYPE_NONE      0 | ||||
| #define POP3_TYPE_ANY       ~0 | ||||
|  | ||||
| /* This is the 5-bytes End-Of-Body marker for POP3 */ | ||||
| #define POP3_EOB "\x0d\x0a\x2e\x0d\x0a" | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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 | ||||
| @@ -357,12 +357,21 @@ int Curl_pgrsUpdate(struct connectdata *conn) | ||||
|   } /* Calculations end */ | ||||
|  | ||||
|   if(!(data->progress.flags & PGRS_HIDE)) { | ||||
|  | ||||
|     /* progress meter has not been shut off */ | ||||
|  | ||||
|     if(data->set.fprogress) { | ||||
|       /* There's a callback set, so we call that instead of writing | ||||
|          anything ourselves. This really is the way to go. */ | ||||
|     if(data->set.fxferinfo) { | ||||
|       /* There's a callback set, call that */ | ||||
|       result= data->set.fxferinfo(data->set.progress_client, | ||||
|                                   data->progress.size_dl, | ||||
|                                   data->progress.downloaded, | ||||
|                                   data->progress.size_ul, | ||||
|                                   data->progress.uploaded); | ||||
|       if(result) | ||||
|         failf(data, "Callback aborted"); | ||||
|       return result; | ||||
|     } | ||||
|     else if(data->set.fprogress) { | ||||
|       /* The older deprecated callback is set, call that */ | ||||
|       result= data->set.fprogress(data->set.progress_client, | ||||
|                                   (double)data->progress.size_dl, | ||||
|                                   (double)data->progress.downloaded, | ||||
|   | ||||
							
								
								
									
										44
									
								
								lib/qssl.c
									
									
									
									
									
								
							
							
						
						
									
										44
									
								
								lib/qssl.c
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ | ||||
|  *                            | (__| |_| |  _ <| |___ | ||||
|  *                             \___|\___/|_| \_\_____| | ||||
|  * | ||||
|  * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||
|  * Copyright (C) 1998 - 2013, 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,6 +37,7 @@ | ||||
| #include "sslgen.h" | ||||
| #include "connect.h" /* for the connect timeout */ | ||||
| #include "select.h" | ||||
| #include "x509asn1.h" | ||||
| #include "curl_memory.h" | ||||
| /* The last #include file should be: */ | ||||
| #include "memdebug.h" | ||||
| @@ -169,10 +170,7 @@ static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) | ||||
|   SSLHandle * h = connssl->handle; | ||||
|   long timeout_ms; | ||||
|  | ||||
|   h->exitPgm = NULL; | ||||
|  | ||||
|   if(!data->set.ssl.verifyhost) | ||||
|     h->exitPgm = Curl_qsossl_trap_cert; | ||||
|   h->exitPgm = data->set.ssl.verifypeer? NULL: Curl_qsossl_trap_cert; | ||||
|  | ||||
|   /* figure out how long time we should wait at maximum */ | ||||
|   timeout_ms = Curl_timeleft(data, NULL, TRUE); | ||||
| @@ -208,6 +206,8 @@ static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) | ||||
|     break; | ||||
|   } | ||||
|  | ||||
|   h->peerCert = NULL; | ||||
|   h->peerCertLen = 0; | ||||
|   rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT); | ||||
|  | ||||
|   switch (rc) { | ||||
| @@ -238,6 +238,23 @@ static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex) | ||||
|     return CURLE_SSL_CONNECT_ERROR; | ||||
|   } | ||||
|  | ||||
|   /* Verify host. */ | ||||
|   rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen); | ||||
|   if(rc != CURLE_OK) | ||||
|     return rc; | ||||
|  | ||||
|   /* Gather certificate info. */ | ||||
|   if(data->set.ssl.certinfo) { | ||||
|     if(Curl_ssl_init_certinfo(data, 1)) | ||||
|       return CURLE_OUT_OF_MEMORY; | ||||
|     if(h->peerCert) { | ||||
|       rc = Curl_extract_certinfo(conn, 0, h->peerCert, | ||||
|                                  h->peerCert + h->peerCertLen); | ||||
|       if(rc != CURLE_OK) | ||||
|         return rc; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   return CURLE_OK; | ||||
| } | ||||
|  | ||||
| @@ -257,19 +274,22 @@ CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex) | ||||
|   if(rc == CURLE_OK) { | ||||
|     rc = Curl_qsossl_create(conn, sockindex); | ||||
|  | ||||
|     if(rc == CURLE_OK) | ||||
|     if(rc == CURLE_OK) { | ||||
|       rc = Curl_qsossl_handshake(conn, sockindex); | ||||
|     else { | ||||
|       SSL_Destroy(connssl->handle); | ||||
|       connssl->handle = NULL; | ||||
|       connssl->use = FALSE; | ||||
|       connssl->state = ssl_connection_none; | ||||
|       if(rc != CURLE_OK) | ||||
|         SSL_Destroy(connssl->handle); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if(rc == CURLE_OK) { | ||||
|     connssl->state = ssl_connection_complete; | ||||
|     conn->recv[sockindex] = qsossl_recv; | ||||
|     conn->send[sockindex] = qsossl_send; | ||||
|     connssl->state = ssl_connection_complete; | ||||
|   } | ||||
|   else { | ||||
|     connssl->handle = NULL; | ||||
|     connssl->use = FALSE; | ||||
|     connssl->state = ssl_connection_none; | ||||
|   } | ||||
|  | ||||
|   return rc; | ||||
|   | ||||
| @@ -668,7 +668,7 @@ static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data, | ||||
|   } | ||||
|  | ||||
|   if(rtp_dataleft != 0 && rtp[0] == '$') { | ||||
|     DEBUGF(infof(data, "RTP Rewinding %zu %s\n", rtp_dataleft, | ||||
|     DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft, | ||||
|           *readmore ? "(READMORE)" : "")); | ||||
|  | ||||
|     /* Store the incomplete RTP packet for a "rewind" */ | ||||
|   | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user