Compare commits
	
		
			121 Commits
		
	
	
		
			curl-7_9_3
			...
			curl-7_9_5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | b40b9677b6 | ||
|   | c80ad865db | ||
|   | 758eae49ab | ||
|   | 721b05e343 | ||
|   | a333bddeeb | ||
|   | 4c6a52fe90 | ||
|   | 792d73a9cf | ||
|   | 9a95a3f8c3 | ||
|   | 485edb777f | ||
|   | a8c3431ae9 | ||
|   | 6fe4a6fa9a | ||
|   | 6d8c7356d6 | ||
|   | a782c96e81 | ||
|   | c795123cd5 | ||
|   | 0ec370e6fb | ||
|   | 3d5732d4e0 | ||
|   | b795929858 | ||
|   | 535258ffe4 | ||
|   | cc161b96ac | ||
|   | 5c4b422b18 | ||
|   | 89bad584c3 | ||
|   | e21926f7f0 | ||
|   | e452f467d4 | ||
|   | dfda7ba456 | ||
|   | feb6b6445e | ||
|   | 0b57fa9c51 | ||
|   | 55c6f60c90 | ||
|   | 9def011e8e | ||
|   | 7cf6e8c9cc | ||
|   | cdee43aa59 | ||
|   | 9c25b58b4c | ||
|   | 83f35463f5 | ||
|   | 818cdb879e | ||
|   | 3eead2d6c4 | ||
|   | 5cffe055ad | ||
|   | 3d4511daf3 | ||
|   | 4748b40ad9 | ||
|   | c40b4f6c39 | ||
|   | d3b96dd394 | ||
|   | f946df640b | ||
|   | fef78bd6f1 | ||
|   | 9e6cc86bf7 | ||
|   | b544c5fa5c | ||
|   | afa64ee31f | ||
|   | e9bfef0eb1 | ||
|   | ddbcccd43d | ||
|   | 5370d7a6eb | ||
|   | 685b180ab6 | ||
|   | 9dab850874 | ||
|   | 0d5bfe883e | ||
|   | cc2f1d4894 | ||
|   | a8dd13db4c | ||
|   | 325391aef9 | ||
|   | 3474ec4ecb | ||
|   | ec1736d488 | ||
|   | 4522579688 | ||
|   | 907a6e0eed | ||
|   | d20186a7b8 | ||
|   | b28051881e | ||
|   | bdea56cd3f | ||
|   | 8a3ec2c659 | ||
|   | 14e9420d2c | ||
|   | 5b58e61f28 | ||
|   | be2f3071b5 | ||
|   | 85dbf82d93 | ||
|   | a9c4963cc0 | ||
|   | a4934387d5 | ||
|   | e88a2ec6fc | ||
|   | 0666960173 | ||
|   | f114caca90 | ||
|   | 9468c9c796 | ||
|   | 76c53c690c | ||
|   | c341b11aaf | ||
|   | 6212e6990a | ||
|   | 28049a183c | ||
|   | 5d3dd7911e | ||
|   | ae8375516b | ||
|   | e3f10eb825 | ||
|   | 2b1f683239 | ||
|   | a2b19c9a63 | ||
|   | 4146ce8267 | ||
|   | 170bd6dafc | ||
|   | 7e16ec8724 | ||
|   | 8c459156f8 | ||
|   | 2db894807b | ||
|   | 95ceeb6e0b | ||
|   | c9c00d2a23 | ||
|   | 1afe49864d | ||
|   | 6924bee3a0 | ||
|   | 39d4552dab | ||
|   | a23c63738f | ||
|   | e911945c55 | ||
|   | 6d58d13710 | ||
|   | 0b177cb165 | ||
|   | 3e31b619de | ||
|   | f925979b2f | ||
|   | 49f7fa82b9 | ||
|   | e4cd4cf3f3 | ||
|   | e74b20926d | ||
|   | a312127c91 | ||
|   | 1dc5bf4f73 | ||
|   | 01cfe670c5 | ||
|   | fd307bfe29 | ||
|   | a00de093a7 | ||
|   | 7bfe853af3 | ||
|   | cbaecca8e9 | ||
|   | 8edfb370a8 | ||
|   | 4c08c8f7db | ||
|   | c174680a03 | ||
|   | cb5f6e18e6 | ||
|   | b798e7a5ae | ||
|   | 5deab7ad27 | ||
|   | 12cdfd282d | ||
|   | eba8035e12 | ||
|   | edcbf4350b | ||
|   | 9289ea471f | ||
|   | 7d06185aa6 | ||
|   | 01ecb1d7e7 | ||
|   | e177f14595 | ||
|   | 5c6eddcadd | ||
|   | b3b4786990 | 
							
								
								
									
										199
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										199
									
								
								CHANGES
									
									
									
									
									
								
							| @@ -7,6 +7,205 @@ | |||||||
|                                History of Changes |                                History of Changes | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Daniel (20 February 2002) | ||||||
|  | - Andr<64>s Garc<72>a provided a solution to bug report #515228. the total time | ||||||
|  |   counter was not set correctly when -I was used during some conditions (all | ||||||
|  |   headers were read in one single read). | ||||||
|  |  | ||||||
|  | - Nico Baggus provided a huge patch with minor tweaks all over to make curl | ||||||
|  |   compile nicely on VMS. | ||||||
|  |  | ||||||
|  | Daniel (19 February 2002) | ||||||
|  | - Rick Richardson found out that by replacing PF_UNSPEC with PF_INET in the | ||||||
|  |   getaddrinfo() calls, he could speed up some name resolving calls with an | ||||||
|  |   order of magnitudes on his Redhat Linux 7.2. | ||||||
|  |  | ||||||
|  | - Philip Gladstone found a second INADDR_NONE problem where we used long | ||||||
|  |   intead of in_addr_t which caused 64bit problemos. We really shouldn't define | ||||||
|  |   that on two different places. | ||||||
|  |  | ||||||
|  | Daniel (18 February 2002) | ||||||
|  | - Philip Gladstone found a problem in how HTTP requests were sent if the | ||||||
|  |   request couldn't be sent all at once. | ||||||
|  |  | ||||||
|  | - Emil found and corrected a bad connection timeout comparison that made curl | ||||||
|  |   use the longest of connect-timeout and timout as a timeout value, instead of | ||||||
|  |   the shortest as it was supposed to! | ||||||
|  |  | ||||||
|  | - Aron Roberts provided updated information about LDAP URL syntax to go into | ||||||
|  |   the manual as a replacement for the old references. | ||||||
|  |  | ||||||
|  | Daniel (17 February 2002) | ||||||
|  | - Philip Gladstone pointed out two missing include files that made curl core | ||||||
|  |   dump on 64bit architectures. We need to pay more attention on these details. | ||||||
|  |   It is *lethal* to for example forget the malloc() prototype, as 'int' is | ||||||
|  |   32bit and malloc() must return a 64bit pointer on these platforms. | ||||||
|  |  | ||||||
|  | - Giaslas Georgios fixed a problem with Host: headers on repeated requests on | ||||||
|  |   the same handle using a proxy. | ||||||
|  |  | ||||||
|  | Daniel (8 February 2002) | ||||||
|  | - Hanno L. Kranzhoff accurately found out that disabling the Expect: header | ||||||
|  |   when doing multipart formposts didn't work very well. It disabled other | ||||||
|  |   parts of the request header too, resulting in a broken header. When I fixed | ||||||
|  |   this, I also noticed that the Content-Type wasn't possible to disable. It is | ||||||
|  |   now, even though it probably is really stupid to try to do this (because of | ||||||
|  |   the boundary string that is included in the internally generated header, | ||||||
|  |   used as form part separator.) | ||||||
|  |  | ||||||
|  | Daniel (7 February 2002) | ||||||
|  | - I moved the config*.h files from the root directory to the lib/ directory. | ||||||
|  |  | ||||||
|  | - I've added the new test suite HTTP server to the CVS repository, It seems to | ||||||
|  |   work pretty good now, but we must make it get used by the test scripts | ||||||
|  |   properly and then we need to make sure that it compiles, builds and runs on | ||||||
|  |   most operating systems. | ||||||
|  |  | ||||||
|  | Version 7.9.5-pre1 | ||||||
|  |  | ||||||
|  | Daniel (6 February 2002) | ||||||
|  | - Miklos Nemeth provided updated windows makefiles and INSTALL docs. | ||||||
|  |  | ||||||
|  | - Mr Larry Fahnoe found a problem with formposts and I managed to track down | ||||||
|  |   and patch this bug. This was actually two bugs, as the posted size was also | ||||||
|  |   said to be two bytes too large. | ||||||
|  |  | ||||||
|  | - Brent Beardsley found out and brought a correction for the | ||||||
|  |   CURLINFO_CONTENT_TYPE parser that was off one byte. This was my fault, I | ||||||
|  |   accidentaly broke Giaslas Georgios' patch. | ||||||
|  |  | ||||||
|  | Daniel (5 February 2002) | ||||||
|  | - Kevin Roth found yet another SSL download problem. | ||||||
|  |  | ||||||
|  | Version 7.9.4 | ||||||
|  |  | ||||||
|  | - no changes since pre-release | ||||||
|  |  | ||||||
|  | Version 7.9.4-pre2 | ||||||
|  |  | ||||||
|  | Daniel (3 February 2002) | ||||||
|  | - Eric Melville provided a few spelling corrections in the curl man page. | ||||||
|  |  | ||||||
|  | Daniel (1 February 2002) | ||||||
|  | - Andreas Damm corrected the unconditional use of gmtime() in getdate, it now | ||||||
|  |   uses gmtime_r() on all hosts that have it. | ||||||
|  |  | ||||||
|  | Daniel (31 January 2002) | ||||||
|  | - An anonymous bug report identified a problem in the DNS caching which made it | ||||||
|  |   sometimes allocate one byte too little to store the cache entry in. This | ||||||
|  |   happened when the port number started with 1! | ||||||
|  |  | ||||||
|  | - Albert Chin provided a patch that improves the gethostbyname_r() configure | ||||||
|  |   check on HP-UX 11.00. | ||||||
|  |  | ||||||
|  | Version 7.9.4-pre1 | ||||||
|  |  | ||||||
|  | Daniel (30 January 2002) | ||||||
|  | - Georg Horn found another way the SSL reading failed due to the non-blocking | ||||||
|  |   state of the sockets! I fixed. | ||||||
|  |  | ||||||
|  | Daniel (29 January 2002) | ||||||
|  | - Multipart formposts now send the full request properly, including the CRLF. | ||||||
|  |   They were previously treated as part of the post data. | ||||||
|  |  | ||||||
|  | - The upload byte counter bugged. | ||||||
|  |  | ||||||
|  | - T. Bharath pointed out that we seed SSL on every connect, which is a time- | ||||||
|  |   consuming operation that should only be needed to do once. We patched | ||||||
|  |   libcurl to now only seed on the first connect when unseeded. The seeded | ||||||
|  |   status is global so it'll now only happen once during a program's life time. | ||||||
|  |  | ||||||
|  |   If the random_file or egdsocket is set, the seed will be re-made though. | ||||||
|  |  | ||||||
|  | - Giaslas Georgios introduced CURLINFO_CONTENT_TYPE that lets | ||||||
|  |   curl_easy_getinfo() read the content-type from the previous request. | ||||||
|  |  | ||||||
|  | Daniel (28 January 2002) | ||||||
|  | - Kjetil Jacobsen found a way to crash curl and after much debugging, it | ||||||
|  |   turned out it was a IPv4-linux only problem introduced in 7.9.3 related to | ||||||
|  |   name resolving. | ||||||
|  |  | ||||||
|  | - Andreas Damm posted a huge patch that made the curl_getdate() function fully | ||||||
|  |   reentrant! | ||||||
|  |  | ||||||
|  | - Steve Marx pointed out that you couldn't mix CURLOPT_CUSTOMREQUEST with | ||||||
|  |   CURLOPT_POSTFIELDS. You can now! | ||||||
|  |  | ||||||
|  | Daniel (25 January 2002) | ||||||
|  | - Krishnendu Majumdar pointed out that the header length counter was not reset | ||||||
|  |   between multiple requests on the same handle. | ||||||
|  |  | ||||||
|  | - Pedro Neves rightfully questioned why curl always append \r\n to the data | ||||||
|  |   that is sent in HTTP POST requests. Unfortunately, this broke the test suite | ||||||
|  |   as the test HTTP server is lame enough not to deal with this... :-O | ||||||
|  |  | ||||||
|  | - Following Location: headers when the connection didn't close didn't work as | ||||||
|  |   libcurl didn't properly stop reading. This problem was added in 7.9.3 due to | ||||||
|  |   the restructured internals. 'Frank' posted a bug report about this. | ||||||
|  |  | ||||||
|  | Daniel (24 January 2002) | ||||||
|  | - Kevin Roth very quickly spotted that we wrongly installed the example | ||||||
|  |   programs that were built in the multi directory, when 'make install' was | ||||||
|  |   used. :-/ | ||||||
|  |  | ||||||
|  | Version 7.9.3 | ||||||
|  |  | ||||||
|  | Daniel (23 January 2002) | ||||||
|  | - Andr<64>s Garc<72>a found a persistancy problem when doing HTTP HEAD, that made | ||||||
|  |   curl "hang" until the connection was closed by the server. This problem has | ||||||
|  |   been introduced in 7.9.3 due to internal rewrites, this was not present in | ||||||
|  |   7.9.2. | ||||||
|  |  | ||||||
|  | Version 7.9.3-pre4 | ||||||
|  |  | ||||||
|  | Daniel (19 January 2002) | ||||||
|  | - Antonio filed bug report #505514 and provided a fix! When doing multipart | ||||||
|  |   formposts, libcurl would include an error text in the actual post if a | ||||||
|  |   specified file wasn't found. This is not libcurl's job. Instead we add an | ||||||
|  |   empty part. | ||||||
|  |  | ||||||
|  | Daniel (18 January 2002) | ||||||
|  | - Played around with stricter compiler warnings for gcc (when ./configure | ||||||
|  |   --enable-debug is used) and changed some minor things to stop the warnings. | ||||||
|  |  | ||||||
|  | - Commented out the 'long long' and 'long double' checks in configure.in, as | ||||||
|  |   we don't currently use them anyway and the code in lib/mprintf.c that use | ||||||
|  |   them causes warnings. | ||||||
|  |  | ||||||
|  | - Saul Good and jonatan pointed out Mac OS X build problems with pre3 and how | ||||||
|  |   to correct them. Two compiler warnings were removed as well. | ||||||
|  |  | ||||||
|  | - Andr<64>s Garc<72>a fixed two minor mingw32 building problems. | ||||||
|  |  | ||||||
|  | Version 7.9.3-pre3 | ||||||
|  |  | ||||||
|  | Daniel (17 January 2002) | ||||||
|  | - docs/libcurl-the-guide is a new tutorial for our libcurl programming | ||||||
|  |   friends. | ||||||
|  |  | ||||||
|  | - Richard Archer brought back the ability to compile and build with OpenSSL | ||||||
|  |   versions before 0.9.5. | ||||||
|  |   [http://sourceforge.net/tracker/?func=detail&atid=100976&aid=504163&group_id=976] | ||||||
|  |  | ||||||
|  | - The DNS cache code didn't take the port number into account, which made it | ||||||
|  |   work rather bad on IPv6-enabled hosts (especially when doing passive | ||||||
|  |   FTP). Sterling fixed it. | ||||||
|  |  | ||||||
|  | Daniel (16 January 2002) | ||||||
|  | - Georg Horn could make a transfer time-out without error text. I found it and | ||||||
|  |   corrected it. | ||||||
|  |  | ||||||
|  | - SSL writes didn't work, they return an uninitialized value that caused | ||||||
|  |   havoc all over. Georg Horn experienced this. | ||||||
|  |  | ||||||
|  | - Kevin Roth patched the curl_version() function to use the proper OpenSSL | ||||||
|  |   function for version information. This way, curl will report the version of | ||||||
|  |   the SSL library actually running right now, not the one that had its headers | ||||||
|  |   installed when libcurl was built. Mainly intersting when running with shared | ||||||
|  |   OpenSSL libraries.   | ||||||
|  |  | ||||||
|  | Version 7.9.3-pre2 | ||||||
|  |  | ||||||
| Daniel (16 January 2002) | Daniel (16 January 2002) | ||||||
| - Mofied the main transfer loop and related stuff to deal with non-blocking | - Mofied the main transfer loop and related stuff to deal with non-blocking | ||||||
|   sockets in the upload section. While doing this, I've now separated the |   sockets in the upload section. While doing this, I've now separated the | ||||||
|   | |||||||
| @@ -6,8 +6,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies | |||||||
|  |  | ||||||
| EXTRA_DIST =						\ | EXTRA_DIST =						\ | ||||||
| 	CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt	\ | 	CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt	\ | ||||||
| 	reconf Makefile.dist curl-config.in build_vms.com curl-mode.el \ | 	reconf Makefile.dist curl-config.in build_vms.com curl-mode.el | ||||||
| 	config-vms.h config-win32.h config-riscos.h config-mac.h |  | ||||||
|  |  | ||||||
| bin_SCRIPTS = curl-config | bin_SCRIPTS = curl-config | ||||||
|  |  | ||||||
|   | |||||||
| @@ -51,6 +51,12 @@ vc-ssl: | |||||||
| 	cd lib | 	cd lib | ||||||
| 	nmake -f Makefile.vc6 cfg=release-ssl | 	nmake -f Makefile.vc6 cfg=release-ssl | ||||||
| 	cd ..\src | 	cd ..\src | ||||||
|  | 	nmake -f Makefile.vc6 cfg=release-ssl | ||||||
|  |  | ||||||
|  | vc-ssl-dll: | ||||||
|  | 	cd lib | ||||||
|  | 	nmake -f Makefile.vc6 cfg=release-ssl-dll | ||||||
|  | 	cd ..\src | ||||||
| 	nmake -f Makefile.vc6 | 	nmake -f Makefile.vc6 | ||||||
|  |  | ||||||
| cygwin: | cygwin: | ||||||
|   | |||||||
| @@ -377,6 +377,7 @@ AC_DEFUN(CURL_CHECK_GETHOSTBYNAME_R, | |||||||
|  |  | ||||||
| int | int | ||||||
| gethostbyname_r(const char *, struct hostent *, struct hostent_data *);],[ | gethostbyname_r(const char *, struct hostent *, struct hostent_data *);],[ | ||||||
|  | struct hostent_data data; | ||||||
| gethostbyname_r(NULL, NULL, NULL);],[ | gethostbyname_r(NULL, NULL, NULL);],[ | ||||||
|       AC_MSG_RESULT(yes) |       AC_MSG_RESULT(yes) | ||||||
|       AC_DEFINE(HAVE_GETHOSTBYNAME_R_3) |       AC_DEFINE(HAVE_GETHOSTBYNAME_R_3) | ||||||
| @@ -394,6 +395,7 @@ gethostbyname_r(NULL, NULL, NULL);],[ | |||||||
|  |  | ||||||
| int | int | ||||||
| gethostbyname_r(const char *,struct hostent *, struct hostent_data *);],[ | gethostbyname_r(const char *,struct hostent *, struct hostent_data *);],[ | ||||||
|  | struct hostent_data data; | ||||||
| gethostbyname_r(NULL, NULL, NULL);],[ | gethostbyname_r(NULL, NULL, NULL);],[ | ||||||
| 	AC_MSG_RESULT(yes) | 	AC_MSG_RESULT(yes) | ||||||
| 	AC_DEFINE(HAVE_GETHOSTBYNAME_R_3) | 	AC_DEFINE(HAVE_GETHOSTBYNAME_R_3) | ||||||
|   | |||||||
| @@ -6,14 +6,16 @@ $	loc  = f$environment("PROCEDURE") | |||||||
| $	def = f$parse("X.X;1",loc) - "X.X;1" | $	def = f$parse("X.X;1",loc) - "X.X;1" | ||||||
| $ | $ | ||||||
| $	set def 'def' | $	set def 'def' | ||||||
| $	cc_qual = "/define=HAVE_CONFIG_H=1/include=(""../include/"",""../"")" | $	cc_qual = "/define=HAVE_CONFIG_H=1/include=(""../include/"",""../"",""../../openssl-0_9_6c/include/"")" | ||||||
| $	if p1 .eqs. "LISTING" then cc_qual = cc_qual + "/LIST/MACHINE" | $	if p1 .eqs. "LISTING" then cc_qual = cc_qual + "/LIST/MACHINE" | ||||||
| $	if p1 .eqs. "DEBUG" then cc_qual = cc_qual + "/LIST/MACHINE/DEBUG" | $	if p1 .eqs. "DEBUG" then cc_qual = cc_qual + "/LIST/MACHINE/DEBUG" | ||||||
| $	msg_qual = "" | $	msg_qual = "" | ||||||
| $	call build "[.lib]" "*.c" | $	call build "[.lib]" "*.c" | ||||||
| $	call build "[.src]" "*.c" | $	call build "[.src]" "*.c" | ||||||
| $	call build "[.src]" "*.msg" | $	call build "[.src]" "*.msg" | ||||||
| $	link /exe=curl.exe [.src]curl/lib/include=main,[.lib]curl/lib | $	link /exe=curl.exe [.src]curl/lib/include=main,[.lib]curl/lib, - | ||||||
|  | 		[-.openssl-0_9_6c.axp.exe.ssl]libssl/lib, - | ||||||
|  | 		[-.openssl-0_9_6c.axp.exe.crypto]libcrypto/lib | ||||||
| $ | $ | ||||||
| $ | $ | ||||||
| $	goto Common_Exit | $	goto Common_Exit | ||||||
|   | |||||||
| @@ -8,7 +8,7 @@ AC_PREREQ(2.50) | |||||||
| dnl First some basic init macros | dnl First some basic init macros | ||||||
| AC_INIT | AC_INIT | ||||||
| AC_CONFIG_SRCDIR([lib/urldata.h]) | AC_CONFIG_SRCDIR([lib/urldata.h]) | ||||||
| AM_CONFIG_HEADER(config.h src/config.h) | AM_CONFIG_HEADER(lib/config.h src/config.h) | ||||||
|  |  | ||||||
| dnl figure out the libcurl version | dnl figure out the libcurl version | ||||||
| VERSION=`sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curl.h` | VERSION=`sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curl.h` | ||||||
| @@ -69,7 +69,7 @@ AC_ARG_ENABLE(debug, | |||||||
|   *)   AC_MSG_RESULT(yes) |   *)   AC_MSG_RESULT(yes) | ||||||
|  |  | ||||||
|     CPPFLAGS="$CPPFLAGS -DMALLOCDEBUG" |     CPPFLAGS="$CPPFLAGS -DMALLOCDEBUG" | ||||||
|     CFLAGS="-W -Wall -Wwrite-strings -pedantic -g"  |     CFLAGS="-W -Wall -Wwrite-strings -pedantic -Wundef -Wpointer-arith -Wcast-align -Wnested-externs -g"  | ||||||
|        ;; |        ;; | ||||||
|   esac ], |   esac ], | ||||||
|        AC_MSG_RESULT(no) |        AC_MSG_RESULT(no) | ||||||
| @@ -524,9 +524,9 @@ AC_HEADER_TIME | |||||||
| # mprintf() checks: | # mprintf() checks: | ||||||
|  |  | ||||||
| # check for 'long double' | # check for 'long double' | ||||||
| AC_CHECK_SIZEOF(long double, 8) | # AC_CHECK_SIZEOF(long double, 8) | ||||||
| # check for 'long long' | # check for 'long long' | ||||||
| AC_CHECK_SIZEOF(long long, 4) | # AC_CHECK_SIZEOF(long long, 4) | ||||||
|  |  | ||||||
| # check for ssize_t | # check for ssize_t | ||||||
| AC_CHECK_TYPE(ssize_t, int) | AC_CHECK_TYPE(ssize_t, int) | ||||||
|   | |||||||
							
								
								
									
										7
									
								
								docs/FAQ
									
									
									
									
									
								
							
							
						
						
									
										7
									
								
								docs/FAQ
									
									
									
									
									
								
							| @@ -1,4 +1,4 @@ | |||||||
| Updated: December 21, 2001 (http://curl.haxx.se/docs/faq.shtml) | Updated: January 22, 2002 (http://curl.haxx.se/docs/faq.shtml) | ||||||
|                                   _   _ ____  _      |                                   _   _ ____  _      | ||||||
|                               ___| | | |  _ \| |     |                               ___| | | |  _ \| |     | ||||||
|                              / __| | | | |_) | |     |                              / __| | | | |_) | |     | ||||||
| @@ -163,9 +163,8 @@ FAQ | |||||||
|  |  | ||||||
|   1.6 What do you get for making cURL? |   1.6 What do you get for making cURL? | ||||||
|  |  | ||||||
|   Project cURL is entirely free and open, without any commercial interests or |   Project cURL is entirely free and open. No person gets paid in any way for | ||||||
|   money involved. No person gets paid in any way for developing curl. We all |   developing curl. We all do this voluntarily on our spare time. | ||||||
|   do this voluntarily on our spare time. |  | ||||||
|  |  | ||||||
|   We get some help from companies. Contactor Data hosts the curl web site and |   We get some help from companies. Contactor Data hosts the curl web site and | ||||||
|   the main mailing list, Haxx owns the curl web site's domain and |   the main mailing list, Haxx owns the curl web site's domain and | ||||||
|   | |||||||
							
								
								
									
										29
									
								
								docs/INSTALL
									
									
									
									
									
								
							
							
						
						
									
										29
									
								
								docs/INSTALL
									
									
									
									
									
								
							| @@ -203,15 +203,32 @@ Win32 | |||||||
|       ---------------------------- |       ---------------------------- | ||||||
|         Please read the OpenSSL documentation on how to compile and install |         Please read the OpenSSL documentation on how to compile and install | ||||||
|         the OpenSSL library.  This generates the libeay32.dll and ssleay32.dll |         the OpenSSL library.  This generates the libeay32.dll and ssleay32.dll | ||||||
|         files. |         files in the out32dll subdirectory in the OpenSSL home directory.  If | ||||||
|  |         you compiled OpenSSL static libraries (libeay32.lib, ssleay32.lib, | ||||||
|  |         RSAglue.lib) they are created in the out32 subdirectory. | ||||||
|  |  | ||||||
|         Run the 'vcvars32.bat' file to get the proper environment variables |         Run the 'vcvars32.bat' file to get the proper environment variables | ||||||
|         set. Edit the makefile.vc6 in the lib directory and define |         set. The vcvars32.bat file is part of the Microsoft development | ||||||
|         OPENSSL_PATH.  Set the location of the OpenSSL library and run 'nmake |         environment and you may find it in 'C:\Program Files\Microsoft Visual | ||||||
|         vc-ssl' in the root directory. |         Studio\vc98\bin' if you installed Visual C/C++ 6 in the default | ||||||
|  |         directory. | ||||||
|  |  | ||||||
|         The vcvars32.bat file is part of the Microsoft development |         Before running nmake define the OPENSSL_PATH environment variable with | ||||||
|         environment. |         the root/base directory of OpenSSL, for example: | ||||||
|  |  | ||||||
|  |           set OPENSSL_PATH=c:\openssl-0.9.6b | ||||||
|  |  | ||||||
|  |         Then run 'nmake vc-ssl' or 'nmake vc-ssl-dll' in the curl's root | ||||||
|  |         directory.  'nmake vc-ssl' will create a libcurl static and dynamic | ||||||
|  |         libraries in the lib subdirectory, as well as a statically linked | ||||||
|  |         version of curl.exe in the scr subdirectory.  This statically linked | ||||||
|  |         version is a standalone executable not requiring any DLL at | ||||||
|  |         runtime. This making method requires that you have build the static | ||||||
|  |         libraries of OpenSSL available in OpenSSL's out32 subdirectory. | ||||||
|  | 	'nmake vc-ssl-dll' creates the libcurl dynamic library and | ||||||
|  | 	links curl.exe against libcurl and OpenSSL dynamically. | ||||||
|  | 	This executables requires libcurl.dll and the OpenSSL DLLs | ||||||
|  | 	at runtime. | ||||||
|  |  | ||||||
|       Microsoft / Borland style |       Microsoft / Borland style | ||||||
|       ------------------------- |       ------------------------- | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								docs/MANUAL
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								docs/MANUAL
									
									
									
									
									
								
							| @@ -668,8 +668,14 @@ LDAP | |||||||
|   and offer ldap:// support. |   and offer ldap:// support. | ||||||
|  |  | ||||||
|   LDAP is a complex thing and writing an LDAP query is not an easy task. I do |   LDAP is a complex thing and writing an LDAP query is not an easy task. I do | ||||||
|   advice you to dig up the syntax description for that elsewhere, RFC 1959 if |   advice you to dig up the syntax description for that elsewhere. Two places | ||||||
|   no other place is better. |   that might suit you are: | ||||||
|  |  | ||||||
|  |   Netscape's "Netscape Directory SDK 3.0 for C Programmer's Guide Chapter 10: | ||||||
|  |   Working with LDAP URLs": | ||||||
|  |   http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm | ||||||
|  |  | ||||||
|  |   RFC 2255, "The LDAP URL Format" http://www.rfc-editor.org/rfc/rfc2255.txt | ||||||
|  |  | ||||||
|   To show you an example, this is now I can get all people from my local LDAP |   To show you an example, this is now I can get all people from my local LDAP | ||||||
|   server that has a certain sub-domain in their email address: |   server that has a certain sub-domain in their email address: | ||||||
|   | |||||||
							
								
								
									
										119
									
								
								docs/TODO
									
									
									
									
									
								
							
							
						
						
									
										119
									
								
								docs/TODO
									
									
									
									
									
								
							| @@ -19,10 +19,7 @@ TODO | |||||||
|  |  | ||||||
|  * The new 'multi' interface is being designed. Work out the details, start |  * The new 'multi' interface is being designed. Work out the details, start | ||||||
|    implementing and write test applications! |    implementing and write test applications! | ||||||
|    [http://curl.haxx.se/dev/multi.h] |    [http://curl.haxx.se/lxr/source/lib/multi.h] | ||||||
|  |  | ||||||
|  * Add a name resolve cache to libcurl to make repeated fetches to the same |  | ||||||
|    host name (when persitancy isn't available) faster. |  | ||||||
|  |  | ||||||
|  * Introduce another callback interface for upload/download that makes one |  * Introduce another callback interface for upload/download that makes one | ||||||
|    less copy of data and thus a faster operation. |    less copy of data and thus a faster operation. | ||||||
| @@ -33,13 +30,36 @@ TODO | |||||||
|    telnet, ldap, dict or file. |    telnet, ldap, dict or file. | ||||||
|  |  | ||||||
|  * Add asynchronous name resolving. http://curl.haxx.se/dev/async-resolver.txt |  * Add asynchronous name resolving. http://curl.haxx.se/dev/async-resolver.txt | ||||||
|  |    This should be made to work on most of the supported platforms, or | ||||||
|  |    otherwise it isn't really interesting. | ||||||
|  |  | ||||||
|  * Strip any trailing CR from the error message when Curl_failf() is used. |  * Data sharing. Tell which easy handles within a multi handle that should | ||||||
|  |    share cookies, connection cache, dns cache, ssl session cache. | ||||||
|  |  | ||||||
|  |  * Mutexes. By adding mutex callback support, the 'data sharing' mentioned | ||||||
|  |    above can be made between several easy handles running in different threads | ||||||
|  |    too. The actual mutex implementations will be left for the application to | ||||||
|  |    implement, libcurl will merely call 'getmutex' and 'leavemutex' callbacks. | ||||||
|  |  | ||||||
|  |  * No-faster-then-this transfers. Many people have limited bandwidth and they | ||||||
|  |    want the ability to make sure their transfers never use more bandwith than | ||||||
|  |    they think is good. | ||||||
|  |  | ||||||
|  |  * Set the SO_KEEPALIVE socket option to make libcurl notice and disconnect | ||||||
|  |    very long time idle connections. | ||||||
|  |  | ||||||
|  |  * Make sure we don't ever loop because of non-blocking sockets return | ||||||
|  |    EWOULDBLOCK or similar. This concerns the HTTP request sending (and | ||||||
|  |    especially regular HTTP POST), the FTP command sending etc. | ||||||
|  |  | ||||||
|  |  * Go through the code and verify that libcurl deals with big files >2GB and | ||||||
|  |    >4GB all over. Bug reports indicate that it doesn't currently work | ||||||
|  |    properly. | ||||||
|  |  | ||||||
|  DOCUMENTATION |  DOCUMENTATION | ||||||
|  |  | ||||||
|  * Document all CURLcode error codes, why they happen and what most likely |  * Document all CURLcode error codes, why they happen and what most likely | ||||||
|    will make them not happen again. |    will make them not happen again. In a libcurl point of view. | ||||||
|  |  | ||||||
|  FTP |  FTP | ||||||
|  |  | ||||||
| @@ -54,11 +74,7 @@ TODO | |||||||
|    already working http dito works. It of course requires that 'MDTM' works, |    already working http dito works. It of course requires that 'MDTM' works, | ||||||
|    and it isn't a standard FTP command. |    and it isn't a standard FTP command. | ||||||
|  |  | ||||||
|  * Suggested on the mailing list: CURLOPT_FTP_MKDIR...! |  * Add FTPS support with SSL for the data connection too. | ||||||
|  |  | ||||||
|  * Always use the FTP SIZE command before downloading, as that makes it more |  | ||||||
|    likely that we know the size when downloading. Some sites support SIZE but |  | ||||||
|    don't show the size in the RETR response! |  | ||||||
|  |  | ||||||
|  HTTP |  HTTP | ||||||
|  |  | ||||||
| @@ -67,6 +83,12 @@ TODO | |||||||
|    encoding. [http://curl.haxx.se/dev/HTTP-PUT-stdin.txt] When the filter |    encoding. [http://curl.haxx.se/dev/HTTP-PUT-stdin.txt] When the filter | ||||||
|    system mentioned above gets real, it'll be a piece of cake to add. |    system mentioned above gets real, it'll be a piece of cake to add. | ||||||
|  |  | ||||||
|  |  * Pass a list of host name to libcurl to which we allow the user name and | ||||||
|  |    password to get sent to. Currently, it only get sent to the host name that | ||||||
|  |    the first URL uses (to prevent others from being able to read it), but this | ||||||
|  |    also prevents the authentication info from getting sent when following | ||||||
|  |    locations to legitimate other host names. | ||||||
|  |  | ||||||
|  * "Content-Encoding: compress/gzip/zlib" HTTP 1.1 clearly defines how to get |  * "Content-Encoding: compress/gzip/zlib" HTTP 1.1 clearly defines how to get | ||||||
|    and decode compressed documents. There is the zlib that is pretty good at |    and decode compressed documents. There is the zlib that is pretty good at | ||||||
|    decompressing stuff. This work was started in October 1999 but halted again |    decompressing stuff. This work was started in October 1999 but halted again | ||||||
| @@ -83,34 +105,66 @@ TODO | |||||||
|    http://www.innovation.ch/java/ntlm.html that contains detailed reverse- |    http://www.innovation.ch/java/ntlm.html that contains detailed reverse- | ||||||
|    engineered info. |    engineered info. | ||||||
|  |  | ||||||
|  * RFC2617 compliance, "Digest Access Authentication" |  * RFC2617 compliance, "Digest Access Authentication" A valid test page seem | ||||||
|    A valid test page seem to exist at: |    to exist at: http://hopf.math.nwu.edu/testpage/digest/ And some friendly | ||||||
|    http://hopf.math.nwu.edu/testpage/digest/ |    person's server source code is available at | ||||||
|    And some friendly person's server source code is available at |    http://hopf.math.nwu.edu/digestauth/index.html Then there's the Apache | ||||||
|    http://hopf.math.nwu.edu/digestauth/index.html |    mod_digest source code too of course.  It seems as if Netscape doesn't | ||||||
|    Then there's the Apache mod_digest source code too of course.  It seems as |    support this, and not many servers do. Although this is a lot better | ||||||
|    if Netscape doesn't support this, and not many servers do. Although this is |    authentication method than the more common "Basic". Basic sends the | ||||||
|    a lot better authentication method than the more common "Basic". Basic |    password in cleartext over the network, this "Digest" method uses a | ||||||
|    sends the password in cleartext over the network, this "Digest" method uses |    challange-response protocol which increases security quite a lot. | ||||||
|    a challange-response protocol which increases security quite a lot. |  | ||||||
|  |  * Pipelining. Sending multiple requests before the previous one(s) are done. | ||||||
|  |    This could possibly be implemented using the multi interface to queue | ||||||
|  |    requests and the response data. | ||||||
|  |  | ||||||
|  TELNET |  TELNET | ||||||
|  |  | ||||||
|  * Make TELNET work on windows98! |  * Make TELNET work on windows98! | ||||||
|  |  | ||||||
|  |  * Reading input (to send to the remote server) on stdin is a crappy solution | ||||||
|  |    for library purposes. We need to invent a good way for the application to | ||||||
|  |    be able to provide the data to send. | ||||||
|  |  | ||||||
|  |  * Move the telnet support's network select() loop go away and merge the code | ||||||
|  |    into the main transfer loop. Until this is done, the multi interface won't | ||||||
|  |    work for telnet. | ||||||
|  |  | ||||||
|  SSL |  SSL | ||||||
|  |  | ||||||
|  |  * If you really want to improve the SSL situation, you should probably have a | ||||||
|  |    look at SSL cafile loading as well - quick traces look to me like these are | ||||||
|  |    done on every request as well, when they should only be necessary once per | ||||||
|  |    ssl context (or once per handle). Even better would be to support the SSL | ||||||
|  |    CAdir option - instead of loading all of the root CA certs for every | ||||||
|  |    request, this option allows you to only read the CA chain that is actually | ||||||
|  |    required (into the cache)... | ||||||
|  |  | ||||||
|  * Add an interface to libcurl that enables "session IDs" to get |  * Add an interface to libcurl that enables "session IDs" to get | ||||||
|    exported/imported. Cris Bailiff said: "OpenSSL has functions which can |    exported/imported. Cris Bailiff said: "OpenSSL has functions which can | ||||||
|    serialise the current SSL state to a buffer of your choice, and |    serialise the current SSL state to a buffer of your choice, and | ||||||
|    recover/reset the state from such a buffer at a later date - this is used |    recover/reset the state from such a buffer at a later date - this is used | ||||||
|    by mod_ssl for apache to implement and SSL session ID cache" |    by mod_ssl for apache to implement and SSL session ID cache". This whole | ||||||
|  |    idea might become moot if we enable the 'data sharing' as mentioned in the | ||||||
|  |    LIBCURL label above. | ||||||
|  |  | ||||||
|  |  * OpenSSL supports a callback for customised verification of the peer | ||||||
|  |    certificate, but this doesn't seem to be exposed in the libcurl APIs. Could | ||||||
|  |    it be? There's so much that could be done if it were! (brought by Chris | ||||||
|  |    Clark) | ||||||
|  |  | ||||||
|  * Make curl's SSL layer option capable of using other free SSL libraries. |  * Make curl's SSL layer option capable of using other free SSL libraries. | ||||||
|    Such as the Mozilla Security Services |    Such as the Mozilla Security Services | ||||||
|    (http://www.mozilla.org/projects/security/pki/nss/) and GNUTLS |    (http://www.mozilla.org/projects/security/pki/nss/) and GNUTLS | ||||||
|    (http://gnutls.hellug.gr/) |    (http://gnutls.hellug.gr/) | ||||||
|  |  | ||||||
|  |  LDAP | ||||||
|  |  | ||||||
|  |  * Look over the implementation. The looping will have to "go away" from the | ||||||
|  |    lib/ldap.c source file and get moved to the main network code so that the | ||||||
|  |    multi interface and friends will work for LDAP as well. | ||||||
|  |  | ||||||
|  CLIENT |  CLIENT | ||||||
|  |  | ||||||
|  * "curl ftp://site.com/*.txt" |  * "curl ftp://site.com/*.txt" | ||||||
| @@ -119,11 +173,22 @@ TODO | |||||||
|    the same syntax to specify several files to get uploaded (using the same |    the same syntax to specify several files to get uploaded (using the same | ||||||
|    persistant connection), using -T. |    persistant connection), using -T. | ||||||
|  |  | ||||||
|  * Say you have a list of FTP addresses to download in a file named |  * When the multi interface has been implemented and proved to work, the | ||||||
|    ftp-list.txt: "cat ftp-list.txt | xargs curl -O -O -O [...]". curl _needs_ |    client could be told to use maximum N simultaneous transfers and then just | ||||||
|    an "-Oalways" flag -- all addresses on the command line use the base |    make sure that happens. It should of course not make more than one | ||||||
|    filename to store locally.  Else a script must precount the # of URLs, |    connection to the same remote host. | ||||||
|    construct the proper number of "-O"s... |  | ||||||
|  |  * Extending the capabilities of the multipart formposting. How about leaving | ||||||
|  |    the ';type=foo' syntax as it is and adding an extra tag (headers) which | ||||||
|  |    works like this: curl -F "coolfiles=@fil1.txt;headers=@fil1.hdr" where | ||||||
|  |    fil1.hdr contains extra headers like | ||||||
|  |  | ||||||
|  |      Content-Type: text/plain; charset=KOI8-R" | ||||||
|  |      Content-Transfer-Encoding: base64 | ||||||
|  |      X-User-Comment: Please don't use browser specific HTML code | ||||||
|  |  | ||||||
|  |    which should overwrite the program reasonable defaults (plain/text, | ||||||
|  |    8bit...) (Idea brough to us by kromJx) | ||||||
|  |  | ||||||
|  TEST SUITE |  TEST SUITE | ||||||
|  |  | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| .\" nroff -man curl-config.1 | .\" nroff -man curl-config.1 | ||||||
| .\" Written by Daniel Stenberg | .\" Written by Daniel Stenberg | ||||||
| .\" | .\" | ||||||
| .TH curl-config 1 "16 August 2001" "Curl 7.8.1" "curl-config manual" | .TH curl-config 1 "21 January 2002" "Curl 7.9.3" "curl-config manual" | ||||||
| .SH NAME | .SH NAME | ||||||
| curl-config \- Get information about a libcurl installation | curl-config \- Get information about a libcurl installation | ||||||
| .SH SYNOPSIS | .SH SYNOPSIS | ||||||
| @@ -11,6 +11,8 @@ curl-config \- Get information about a libcurl installation | |||||||
| .B curl-config | .B curl-config | ||||||
| displays information about a previous curl and libcurl installation. | displays information about a previous curl and libcurl installation. | ||||||
| .SH OPTIONS | .SH OPTIONS | ||||||
|  | .IP "--cc" | ||||||
|  | Displays the compiler used to build libcurl. | ||||||
| .IP "--cflags" | .IP "--cflags" | ||||||
| Set of compiler options (CFLAGS) to use when compiling files that use | Set of compiler options (CFLAGS) to use when compiling files that use | ||||||
| libcurl. Currently that is only thw include path to the curl include files. | libcurl. Currently that is only thw include path to the curl include files. | ||||||
| @@ -38,18 +40,23 @@ major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl | |||||||
| .SH "EXAMPLES" | .SH "EXAMPLES" | ||||||
| What linker options do I need when I link with libcurl? | What linker options do I need when I link with libcurl? | ||||||
|  |  | ||||||
|   curl-config --libs |   $ curl-config --libs | ||||||
|  |  | ||||||
| What compiler options do I need when I compile using libcurl functions? | What compiler options do I need when I compile using libcurl functions? | ||||||
|  |  | ||||||
|   curl-config --cflags |   $ curl-config --cflags | ||||||
|  |  | ||||||
| How do I know if libcurl was built with SSL support? | How do I know if libcurl was built with SSL support? | ||||||
|  |  | ||||||
|   curl-config --feature | grep SSL |   $ curl-config --feature | grep SSL | ||||||
|  |  | ||||||
| What's the installed libcurl version? | What's the installed libcurl version? | ||||||
|  |  | ||||||
|   curl-config --version |   $ curl-config --version | ||||||
|  |  | ||||||
|  | How do I build a single file with a one-line command? | ||||||
|  |  | ||||||
|  |   $ `curl-config --cc --cflags --libs` -o example example.c | ||||||
|  |  | ||||||
| .SH "SEE ALSO" | .SH "SEE ALSO" | ||||||
| .BR curl (1) | .BR curl (1) | ||||||
|   | |||||||
| @@ -510,7 +510,7 @@ password is specified, curl will ask for it interactively. | |||||||
|  |  | ||||||
| If this option is used several times, the last one will be used. | If this option is used several times, the last one will be used. | ||||||
| .IP "--url <URL>" | .IP "--url <URL>" | ||||||
| Specify a URL to fetch. This option is mostly handy when you wanna specify | Specify a URL to fetch. This option is mostly handy when you want to specify | ||||||
| URL(s) in a config file. | URL(s) in a config file. | ||||||
|  |  | ||||||
| This option may be used any number of times. To control where this URL is written, use the | This option may be used any number of times. To control where this URL is written, use the | ||||||
| @@ -538,7 +538,7 @@ write "@-". | |||||||
| The variables present in the output format will be substituted by the value or | The variables present in the output format will be substituted by the value or | ||||||
| text that curl thinks fit, as described below. All variables are specified | text that curl thinks fit, as described below. All variables are specified | ||||||
| like %{variable_name} and to output a normal % you just write them like | like %{variable_name} and to output a normal % you just write them like | ||||||
| %%. You can output a newline by using \\n, a carrige return with \\r and a tab | %%. You can output a newline by using \\n, a carriage return with \\r and a tab | ||||||
| space with \\t. | space with \\t. | ||||||
|  |  | ||||||
| .B NOTE: | .B NOTE: | ||||||
| @@ -788,7 +788,7 @@ Internal error. A function was called in a bad order. | |||||||
| .IP 45 | .IP 45 | ||||||
| Interface error. A specified outgoing interface could not be used. | Interface error. A specified outgoing interface could not be used. | ||||||
| .IP 46 | .IP 46 | ||||||
| Bad password entered. An error was signalled when the password was entered. | Bad password entered. An error was signaled when the password was entered. | ||||||
| .IP 47 | .IP 47 | ||||||
| Too many redirects. When following redirects, curl hit the maximum amount. | Too many redirects. When following redirects, curl hit the maximum amount. | ||||||
| .IP 48 | .IP 48 | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| .\" nroff -man [file] | .\" nroff -man [file] | ||||||
| .\" $Id$ | .\" $Id$ | ||||||
| .\" | .\" | ||||||
| .TH curl_easy_init 3 "5 March 2001" "libcurl 7.6.1" "libcurl Manual" | .TH curl_easy_init 3 "31 Jan 2001" "libcurl 7.9.4" "libcurl Manual" | ||||||
| .SH NAME | .SH NAME | ||||||
| curl_easy_getinfo - Extract information from a curl session (added in 7.4) | curl_easy_getinfo - Extract information from a curl session (added in 7.4) | ||||||
| .SH SYNOPSIS | .SH SYNOPSIS | ||||||
| @@ -30,9 +30,11 @@ Pass a pointer to a long to receive the last received HTTP code. | |||||||
| .TP | .TP | ||||||
| .B CURLINFO_FILETIME | .B CURLINFO_FILETIME | ||||||
| Pass a pointer to a long to receive the remote time of the retrieved | Pass a pointer to a long to receive the remote time of the retrieved | ||||||
| document. If you get 0, it can be because of many reasons (unknown, the server | document. If you get -1, it can be because of many reasons (unknown, the | ||||||
| hides it or the server doesn't support the command that tells document time | server hides it or the server doesn't support the command that tells document | ||||||
| etc) and the time of the document is unknown. (Added in 7.5) | time etc) and the time of the document is unknown. Note that you must tell the | ||||||
|  | server to collect this information before the transfer is made, by using the | ||||||
|  | CURLOPT_FILETIME option to \fIcurl_easy_setopt(3)\fP. (Added in 7.5) | ||||||
| .TP | .TP | ||||||
| .B CURLINFO_TOTAL_TIME | .B CURLINFO_TOTAL_TIME | ||||||
| Pass a pointer to a double to receive the total transaction time in seconds | Pass a pointer to a double to receive the total transaction time in seconds | ||||||
| @@ -95,6 +97,12 @@ is the value read from the Content-Length: field.  (Added in 7.6.1) | |||||||
| .B CURLINFO_CONTENT_LENGTH_UPLOAD | .B CURLINFO_CONTENT_LENGTH_UPLOAD | ||||||
| Pass a pointer to a double to receive the specified size of the upload. | Pass a pointer to a double to receive the specified size of the upload. | ||||||
| (Added in 7.6.1) | (Added in 7.6.1) | ||||||
|  | .TP | ||||||
|  | .B CURLINFO_CONTENT_TYPE | ||||||
|  | Pass a pointer to a 'char *' to receive the content-type of the downloaded | ||||||
|  | object. This is the value read from the Content-Type: field. If you get NULL, | ||||||
|  | it means that the server didn't send a valid Content-Type header or that the | ||||||
|  | protocol used doesn't support this.  (Added in 7.9.4) | ||||||
| .PP | .PP | ||||||
|  |  | ||||||
| .SH RETURN VALUE | .SH RETURN VALUE | ||||||
|   | |||||||
| @@ -324,7 +324,8 @@ changed with \fICURLOPT_SSLCERTTYPE\fP. | |||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSLCERTTYPE | .B CURLOPT_SSLCERTTYPE | ||||||
| Pass a pointer to a zero terminated string as parameter. The string should be | 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". | the format of your certificate. Supported formats are "PEM" and "DER".  (Added | ||||||
|  | in 7.9.3) | ||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSLCERTPASSWD | .B CURLOPT_SSLCERTPASSWD | ||||||
| Pass a pointer to a zero terminated string as parameter. It will be used as | Pass a pointer to a zero terminated string as parameter. It will be used as | ||||||
| @@ -339,11 +340,12 @@ a certificate but you need one to load your private key. | |||||||
| .B CURLOPT_SSLKEY | .B CURLOPT_SSLKEY | ||||||
| Pass a pointer to a zero terminated string as parameter. The string should be | 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 | the file name of your private key. The default format is "PEM" and can be | ||||||
| changed with \fICURLOPT_SSLKEYTYPE\fP. | changed with \fICURLOPT_SSLKEYTYPE\fP. (Added in 7.9.3) | ||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSLKEYTYPE | .B CURLOPT_SSLKEYTYPE | ||||||
| Pass a pointer to a zero terminated string as parameter. The string should be | 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". | the format of your private key. Supported formats are "PEM", "DER" and "ENG". | ||||||
|  | (Added in 7.9.3) | ||||||
|  |  | ||||||
| \fBNOTE:\fPThe format "ENG" enables you to load the private key from a crypto | \fBNOTE:\fPThe format "ENG" enables you to load the private key from a crypto | ||||||
| engine. in this case \fICURLOPT_SSLKEY\fP is used as an identifier passed to | engine. in this case \fICURLOPT_SSLKEY\fP is used as an identifier passed to | ||||||
| @@ -351,22 +353,25 @@ the engine. You have to set the crypto engine with \fICURLOPT_SSL_ENGINE\fP. | |||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSLKEYASSWD | .B CURLOPT_SSLKEYASSWD | ||||||
| Pass a pointer to a zero terminated string as parameter. It will be used as | Pass a pointer to a zero terminated string as parameter. It will be used as | ||||||
| the password required to use the \fICURLOPT_SSLKEY\fP private key. If the password | the password required to use the \fICURLOPT_SSLKEY\fP private key. If the | ||||||
| is not supplied, you will be prompted for it. \fICURLOPT_PASSWDFUNCTION\fP can | password is not supplied, you will be prompted for | ||||||
| be used to set your own prompt function. | it. \fICURLOPT_PASSWDFUNCTION\fP can be used to set your own prompt function. | ||||||
|  | (Added in 7.9.3) | ||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSL_ENGINE | .B CURLOPT_SSL_ENGINE | ||||||
| Pass a pointer to a zero terminated string as parameter. It will be used as | Pass a pointer to a zero terminated string as parameter. It will be used as | ||||||
| the identifier for the crypto engine you want to use for your private key. | the identifier for the crypto engine you want to use for your private | ||||||
|  | key. (Added in 7.9.3) | ||||||
|  |  | ||||||
| \fBNOTE:\fPIf the crypto device cannot be loaded, \fICURLE_SSL_ENGINE_NOTFOUND\fP | \fBNOTE:\fPIf the crypto device cannot be loaded, | ||||||
| is returned. | \fICURLE_SSL_ENGINE_NOTFOUND\fP is returned. | ||||||
| .TP | .TP | ||||||
| .B CURLOPT_SSL_ENGINEDEFAULT | .B CURLOPT_SSL_ENGINEDEFAULT | ||||||
| Sets the actual crypto engine as the default for (asymetric) crypto operations. | Sets the actual crypto engine as the default for (asymetric) crypto | ||||||
|  | operations. (Added in 7.9.3) | ||||||
|  |  | ||||||
| \fBNOTE:\fPIf the crypto device cannot be set, \fICURLE_SSL_ENGINE_SETFAILED\fP | \fBNOTE:\fPIf the crypto device cannot be set, | ||||||
| is returned. | \fICURLE_SSL_ENGINE_SETFAILED\fP is returned. | ||||||
| .TP | .TP | ||||||
| .B CURLOPT_CRLF | .B CURLOPT_CRLF | ||||||
| Convert Unix newlines to CRLF newlines on FTP uploads. | Convert Unix newlines to CRLF newlines on FTP uploads. | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|  |  | ||||||
| AUTOMAKE_OPTIONS = foreign no-dependencies | AUTOMAKE_OPTIONS = foreign no-dependencies | ||||||
|  |  | ||||||
| EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit.c postit2.c \ | EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit2.c \ | ||||||
| 	     win32sockets.c persistant.c ftpget.c Makefile.example \ | 	     win32sockets.c persistant.c ftpget.c Makefile.example \ | ||||||
| 	     multithread.c getinmemory.c ftpupload.c httpput.c \ | 	     multithread.c getinmemory.c ftpupload.c httpput.c \ | ||||||
| 	     simplessl.c ftpgetresp.c http-post.c | 	     simplessl.c ftpgetresp.c http-post.c | ||||||
|   | |||||||
| @@ -1,71 +0,0 @@ | |||||||
| /***************************************************************************** |  | ||||||
|  *                                  _   _ ____  _      |  | ||||||
|  *  Project                     ___| | | |  _ \| |     |  | ||||||
|  *                             / __| | | | |_) | |     |  | ||||||
|  *                            | (__| |_| |  _ <| |___  |  | ||||||
|  *                             \___|\___/|_| \_\_____| |  | ||||||
|  * |  | ||||||
|  * $Id$ |  | ||||||
|  * |  | ||||||
|  * Example code that uploads a file name 'foo' to a remote script that accepts |  | ||||||
|  * "HTML form based" (as described in RFC1738) uploads using HTTP POST. |  | ||||||
|  * |  | ||||||
|  * The imaginary form we'll fill in looks like: |  | ||||||
|  * |  | ||||||
|  * <form method="post" enctype="multipart/form-data" action="examplepost.cgi"> |  | ||||||
|  * Enter file: <input type="file" name="sendfile" size="40"> |  | ||||||
|  * Enter file name: <input type="text" name="filename" size="30"> |  | ||||||
|  * <input type="submit" value="send" name="submit"> |  | ||||||
|  * </form> |  | ||||||
|  * |  | ||||||
|  * This exact source code has not been verified to work. |  | ||||||
|  */ |  | ||||||
|  |  | ||||||
| /* to make this work under windows, use the win32-functions from the |  | ||||||
|    win32socket.c file as well */ |  | ||||||
|  |  | ||||||
| #include <stdio.h> |  | ||||||
|  |  | ||||||
| #include <curl/curl.h> |  | ||||||
| #include <curl/types.h> |  | ||||||
| #include <curl/easy.h> |  | ||||||
|  |  | ||||||
| int main(int argc, char **argv) |  | ||||||
| { |  | ||||||
|   CURL *curl; |  | ||||||
|   CURLcode res; |  | ||||||
|  |  | ||||||
|   struct HttpPost *formpost=NULL; |  | ||||||
|   struct HttpPost *lastptr=NULL; |  | ||||||
|  |  | ||||||
|   /* Fill in the file upload field */ |  | ||||||
|   curl_formparse("sendfile=@foo", |  | ||||||
|                  &formpost, |  | ||||||
|                  &lastptr); |  | ||||||
|  |  | ||||||
|   /* Fill in the filename field */ |  | ||||||
|   curl_formparse("filename=foo", |  | ||||||
|                  &formpost, |  | ||||||
|                  &lastptr); |  | ||||||
|    |  | ||||||
|  |  | ||||||
|   /* Fill in the submit field too, even if this is rarely needed */ |  | ||||||
|   curl_formparse("submit=send", |  | ||||||
|                  &formpost, |  | ||||||
|                  &lastptr); |  | ||||||
|  |  | ||||||
|   curl = curl_easy_init(); |  | ||||||
|   if(curl) { |  | ||||||
|     /* what URL that receives this POST */ |  | ||||||
|     curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi"); |  | ||||||
|     curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost); |  | ||||||
|     res = curl_easy_perform(curl); |  | ||||||
|  |  | ||||||
|     /* always cleanup */ |  | ||||||
|     curl_easy_cleanup(curl); |  | ||||||
|  |  | ||||||
|     /* then cleanup the formpost chain */ |  | ||||||
|     curl_formfree(formpost); |  | ||||||
|   } |  | ||||||
|   return 0; |  | ||||||
| } |  | ||||||
| @@ -28,6 +28,9 @@ | |||||||
|    4.2. if the format of the key file is DER, set pKeyType to "DER" |    4.2. if the format of the key file is DER, set pKeyType to "DER" | ||||||
|  |  | ||||||
|    !! verify of the server certificate is not implemented here !! |    !! verify of the server certificate is not implemented here !! | ||||||
|  |  | ||||||
|  |    **** This example only works with libcurl 7.9.3 and later! **** | ||||||
|  |  | ||||||
| */ | */ | ||||||
|  |  | ||||||
| int main(int argc, char **argv) | int main(int argc, char **argv) | ||||||
|   | |||||||
| @@ -10,9 +10,9 @@ PROGRAMMING WITH LIBCURL | |||||||
| About this Document | About this Document | ||||||
|  |  | ||||||
|  This document will attempt to describe the general principle and some basic |  This document will attempt to describe the general principle and some basic | ||||||
|  approach to consider when programming with libcurl. The text will focus |  approaches to consider when programming with libcurl. The text will focus | ||||||
|  mainly on the C/C++ interface but might apply fairly well on other interfaces |  mainly on the C interface but might apply fairly well on other interfaces as | ||||||
|  as well as they usually follow the C one pretty closely. |  well as they usually follow the C one pretty closely. | ||||||
|  |  | ||||||
|  This document will refer to 'the user' as the person writing the source code |  This document will refer to 'the user' as the person writing the source code | ||||||
|  that uses libcurl. That would probably be you or someone in your position. |  that uses libcurl. That would probably be you or someone in your position. | ||||||
| @@ -20,15 +20,62 @@ About this Document | |||||||
|  source code that you write that is using libcurl for transfers. The program |  source code that you write that is using libcurl for transfers. The program | ||||||
|  is outside libcurl and libcurl is outside of the program. |  is outside libcurl and libcurl is outside of the program. | ||||||
|  |  | ||||||
|  |  To get the more details on all options and functions described herein, please | ||||||
|  |  refer to their respective man pages. | ||||||
|  |  | ||||||
| Building | Building | ||||||
|  |  | ||||||
|  |  There are many different ways to build C programs. This chapter will assume a | ||||||
|  |  unix-style build process. If you use a different build system, you can still | ||||||
|  |  read this to get general information that may apply to your environment as | ||||||
|  |  well. | ||||||
|  |  | ||||||
|   Compiling the Program |   Compiling the Program | ||||||
|  |  | ||||||
|  |     Your compiler needs to know where the libcurl headers are | ||||||
|  |     located. Therefore you must set your compiler's include path to point to | ||||||
|  |     the directory where you installed them. The 'curl-config'[3] tool can be | ||||||
|  |     used to get this information: | ||||||
|  |  | ||||||
|  |         $ curl-config --cflags | ||||||
|  |  | ||||||
|   Linking the Program with libcurl |   Linking the Program with libcurl | ||||||
|  |  | ||||||
|  |     When having compiled the program, you need to link your object files to | ||||||
|  |     create a single executable. For that to succeed, you need to link with | ||||||
|  |     libcurl and possibly also with other libraries that libcurl itself depends | ||||||
|  |     on. Like OpenSSL librararies, but even some standard OS libraries may be | ||||||
|  |     needed on the command line. To figure out which flags to use, once again | ||||||
|  |     the 'curl-config' tool comes to the rescue: | ||||||
|  |  | ||||||
|  |         $ curl-config --libs | ||||||
|  |  | ||||||
|   SSL or Not |   SSL or Not | ||||||
|  |  | ||||||
|  |     libcurl can be built and customized in many ways. One of the things that | ||||||
|  |     varies from different libraries and builds is the support for SSL-based | ||||||
|  |     transfers, like HTTPS and FTPS. If OpenSSL was detected properly at | ||||||
|  |     build-time, libcurl will be built with SSL support. To figure out if an | ||||||
|  |     installed libcurl has been built with SSL support enabled, use | ||||||
|  |     'curl-config' like this: | ||||||
|  |  | ||||||
|  |         $ curl-config --feature | ||||||
|  |  | ||||||
|  |     And if SSL is supported, the keyword 'SSL' will be written to stdout, | ||||||
|  |     possibly together with a few other features that can be on and off on | ||||||
|  |     different libcurls. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Portable Code in a Portable World | ||||||
|  |  | ||||||
|  |  The people behind libcurl have put a considerable effort to make libcurl work | ||||||
|  |  on a large amount of different operating systems and environments. | ||||||
|  |  | ||||||
|  |  You program libcurl the same way on all platforms that libcurl runs on. There | ||||||
|  |  are only very few minor considerations that differs. If you just make sure to | ||||||
|  |  write your code portable enough, you may very well create yourself a very | ||||||
|  |  portable program. libcurl shouldn't stop you from that. | ||||||
|  |  | ||||||
|  |  | ||||||
| Global Preparation | Global Preparation | ||||||
|  |  | ||||||
| @@ -69,7 +116,7 @@ Global Preparation | |||||||
|  Repeated calls to curl_global_init() and curl_global_cleanup() should be |  Repeated calls to curl_global_init() and curl_global_cleanup() should be | ||||||
|  avoided. They should be called once each. |  avoided. They should be called once each. | ||||||
|  |  | ||||||
| Handle the easy libcurl | Handle the Easy libcurl | ||||||
|  |  | ||||||
|  libcurl version 7 is oriented around the so called easy interface. All |  libcurl version 7 is oriented around the so called easy interface. All | ||||||
|  operations in the easy interface are prefixed with 'curl_easy'. |  operations in the easy interface are prefixed with 'curl_easy'. | ||||||
| @@ -90,9 +137,22 @@ Handle the easy libcurl | |||||||
|  |  | ||||||
|  It returns an easy handle. Using that you proceed to the next step: setting |  It returns an easy handle. Using that you proceed to the next step: setting | ||||||
|  up your preferred actions. A handle is just a logic entity for the upcoming |  up your preferred actions. A handle is just a logic entity for the upcoming | ||||||
|  transfer or series of transfers. One of the most basic properties to set in |  transfer or series of transfers. | ||||||
|  the handle is the URL. You set your preferred URL to transfer with |  | ||||||
|  CURLOPT_URL in a manner similar to: |  You set properties and options for this handle using curl_easy_setopt(). They | ||||||
|  |  control how the subsequent transfer or transfers will be made. Options remain | ||||||
|  |  set in the handle until set again to something different. Alas, multiple | ||||||
|  |  requests using the same handle will use the same options. | ||||||
|  |  | ||||||
|  |  Many of the informationals you set in libcurl are "strings", pointers to data | ||||||
|  |  terminated with a zero byte. Keep in mind that when you set strings with | ||||||
|  |  curl_easy_setopt(), libcurl will not copy the data. It will merely point to | ||||||
|  |  the data. You MUST make sure that the data remains available for libcurl to | ||||||
|  |  use until finished or until you use the same option again to point to | ||||||
|  |  something else. | ||||||
|  |  | ||||||
|  |  One of the most basic properties to set in the handle is the URL. You set | ||||||
|  |  your preferred URL to transfer with CURLOPT_URL in a manner similar to: | ||||||
|  |  | ||||||
|     curl_easy_setopt(easyhandle, CURLOPT_URL, "http://curl.haxx.se/"); |     curl_easy_setopt(easyhandle, CURLOPT_URL, "http://curl.haxx.se/"); | ||||||
|  |  | ||||||
| @@ -118,6 +178,19 @@ Handle the easy libcurl | |||||||
|  and the function that gets invoked by libcurl. libcurl itself won't touch the |  and the function that gets invoked by libcurl. libcurl itself won't touch the | ||||||
|  data you pass with CURLOPT_FILE. |  data you pass with CURLOPT_FILE. | ||||||
|  |  | ||||||
|  |  libcurl offers its own default internal callback that'll take care of the | ||||||
|  |  data if you don't set the callback with CURLOPT_WRITEFUNCTION. It will then | ||||||
|  |  simply output the received data to stdout. You can have the default callback | ||||||
|  |  write the data to a different file handle by passing a 'FILE *' to a file | ||||||
|  |  opened for writing with the CURLOPT_FILE option. | ||||||
|  |  | ||||||
|  |  Now, we need to take a step back and have a deep breath. Here's one of those | ||||||
|  |  rare platform-dependent nitpicks. Did you spot it? On some platforms[2], | ||||||
|  |  libcurl won't be able to operate on files opened by the program. Thus, if you | ||||||
|  |  use the default callback and pass in a an open file with CURLOPT_FILE, it | ||||||
|  |  will crash. You should therefore avoid this to make your program run fine | ||||||
|  |  virtually everywhere. | ||||||
|  |  | ||||||
|  There are of course many more options you can set, and we'll get back to a |  There are of course many more options you can set, and we'll get back to a | ||||||
|  few of them later. Let's instead continue to the actual transfer: |  few of them later. Let's instead continue to the actual transfer: | ||||||
|  |  | ||||||
| @@ -141,6 +214,7 @@ Handle the easy libcurl | |||||||
|  you intend to make another transfer. libcurl will then attempt to re-use the |  you intend to make another transfer. libcurl will then attempt to re-use the | ||||||
|  previous |  previous | ||||||
|  |  | ||||||
|  |  | ||||||
| When It Doesn't Work | When It Doesn't Work | ||||||
|  |  | ||||||
|  There will always be times when the transfer fails for some reason. You might |  There will always be times when the transfer fails for some reason. You might | ||||||
| @@ -156,6 +230,19 @@ When It Doesn't Work | |||||||
|  wht the server behaves the way it does. Include headers in the normal body |  wht the server behaves the way it does. Include headers in the normal body | ||||||
|  output with CURLOPT_HEADER set TRUE. |  output with CURLOPT_HEADER set TRUE. | ||||||
|  |  | ||||||
|  |  Of course there are bugs left. We need to get to know about them to be able | ||||||
|  |  to fix them, so we're quite dependent on your bug reports! When you do report | ||||||
|  |  suspected bugs in libcurl, please include as much details you possibly can: a | ||||||
|  |  protocol dump that CURLOPT_VERBOSE produces, library version, as much as | ||||||
|  |  possible of your code that uses libcurl, operating system name and version, | ||||||
|  |  compiler name and version etc. | ||||||
|  |  | ||||||
|  |  Getting some in-depth knowledge about the protocols involved is never wrong, | ||||||
|  |  and if you're trying to do funny things, you might very well understand | ||||||
|  |  libcurl and how to use it better if you study the appropriate RFC documents | ||||||
|  |  at least briefly. | ||||||
|  |  | ||||||
|  |  | ||||||
| Upload Data to a Remote Site | Upload Data to a Remote Site | ||||||
|  |  | ||||||
|  libcurl tries to keep a protocol independent approach to most transfers, thus |  libcurl tries to keep a protocol independent approach to most transfers, thus | ||||||
| @@ -171,12 +258,13 @@ Upload Data to a Remote Site | |||||||
|  the custom pointer libcurl will pass to our read callback. The read callback |  the custom pointer libcurl will pass to our read callback. The read callback | ||||||
|  should have a prototype similar to: |  should have a prototype similar to: | ||||||
|  |  | ||||||
|    size_t function(char *buffer, size_t size, size_t nitems, void *userp); |     size_t function(char *bufptr, size_t size, size_t nitems, void *userp); | ||||||
|  |  | ||||||
|  Where buffer is the pointer to a buffer we fill in with data to upload and |  Where bufptr is the pointer to a buffer we fill in with data to upload and | ||||||
|  size*nitems is the size of the buffer. The 'userp' pointer is the custom |  size*nitems is the size of the buffer and therefore also the maximum amount | ||||||
|  pointer we set to point to a struct of ours to pass private data between the |  of data we can return to libcurl in this call. The 'userp' pointer is the | ||||||
|  application and the callback. |  custom pointer we set to point to a struct of ours to pass private data | ||||||
|  |  between the application and the callback. | ||||||
|  |  | ||||||
|     curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function); |     curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function); | ||||||
|  |  | ||||||
| @@ -192,7 +280,7 @@ Upload Data to a Remote Site | |||||||
|  |  | ||||||
|     curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, file_size); |     curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, file_size); | ||||||
|  |  | ||||||
|  So, then you call curl_easy_perform() this time, it'll perform all necessary |  When you call curl_easy_perform() this time, it'll perform all the necessary | ||||||
|  operations and when it has invoked the upload it'll call your supplied |  operations and when it has invoked the upload it'll call your supplied | ||||||
|  callback to get the data to upload. The program should return as much data as |  callback to get the data to upload. The program should return as much data as | ||||||
|  possible in every invoke, as that is likely to make the upload perform as |  possible in every invoke, as that is likely to make the upload perform as | ||||||
| @@ -200,6 +288,525 @@ Upload Data to a Remote Site | |||||||
|  the buffer. Returning 0 will signal the end of the upload. |  the buffer. Returning 0 will signal the end of the upload. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Passwords | ||||||
|  |  | ||||||
|  |  Many protocols use or even require that user name and password are provided | ||||||
|  |  to be able to download or upload the data of your choice. libcurl offers | ||||||
|  |  several ways to specify them. | ||||||
|  |  | ||||||
|  |  Most protocols support that you specify the name and password in the URL | ||||||
|  |  itself. libcurl will detect this and use them accordingly. This is written | ||||||
|  |  like this: | ||||||
|  |  | ||||||
|  |         protocol://user:password@example.com/path/ | ||||||
|  |  | ||||||
|  |  If you need any odd letters in your user name or password, you should enter | ||||||
|  |  them URL encoded, as %XX where XX is a two-digit hexadecimal number. | ||||||
|  |  | ||||||
|  |  libcurl also provides options to set various passwords. The user name and | ||||||
|  |  password as shown embedded in the URL can instead get set with the | ||||||
|  |  CURLOPT_USERPWD option. The argument passed to libcurl should be a char * to | ||||||
|  |  a string in the format "user:password:". In a manner like this: | ||||||
|  |  | ||||||
|  |         curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret"); | ||||||
|  |  | ||||||
|  |  Another case where name and password might be needed at times, is for those | ||||||
|  |  users who need to athenticate themselves to a proxy they use. libcurl offers | ||||||
|  |  another option for this, the CURLOPT_PROXYUSERPWD. It is used quite similar | ||||||
|  |  to the CURLOPT_USERPWD option like this: | ||||||
|  |  | ||||||
|  |         curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret"); | ||||||
|  |   | ||||||
|  |  There's a long time unix "standard" way of storing ftp user names and | ||||||
|  |  passwords, namely in the $HOME/.netrc file. The file should be made private | ||||||
|  |  so that only the user may read it (see also the "Security Considerations" | ||||||
|  |  chapter), as it might contain the password in plain text. libcurl has the | ||||||
|  |  ability to use this file to figure out what set of user name and password to | ||||||
|  |  use for a particular host. As an extension to the normal functionality, | ||||||
|  |  libcurl also supports this file for non-FTP protocols such as HTTP. To make | ||||||
|  |  curl use this file, use the CURLOPT_NETRC option: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_NETRC, TRUE); | ||||||
|  |  | ||||||
|  |  And a very basic example of how such a .netrc file may look like: | ||||||
|  |  | ||||||
|  |     machine myhost.mydomain.com | ||||||
|  |     login userlogin | ||||||
|  |     password secretword | ||||||
|  |  | ||||||
|  |  All these examples have been cases where the password has been optional, or | ||||||
|  |  at least you could leave it out and have libcurl attempt to do its job | ||||||
|  |  without it. There are times when the password isn't optional, like when | ||||||
|  |  you're using an SSL private key for secure transfers. | ||||||
|  |  | ||||||
|  |  You can in this situation either pass a password to libcurl to use to unlock | ||||||
|  |  the private key, or you can let libcurl prompt the user for it. If you prefer | ||||||
|  |  to ask the user, then you can provide your own callback function that will be | ||||||
|  |  called when libcurl wants the password. That way, you can control how the | ||||||
|  |  question will appear to the user. | ||||||
|  |  | ||||||
|  |  To pass the known private key password to libcurl: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_SSLKEYPASSWD, "keypassword"); | ||||||
|  |  | ||||||
|  |  To make a password callback: | ||||||
|  |  | ||||||
|  |     int enter_passwd(void *ourp, const char *prompt, char *buffer, int len); | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_PASSWDFUNCTION, enter_passwd); | ||||||
|  |  | ||||||
|  |  | ||||||
|  | HTTP POSTing | ||||||
|  |  | ||||||
|  |  We get many questions regarding how to issue HTTP POSTs with libcurl the | ||||||
|  |  proper way. This chapter will thus include examples using both different | ||||||
|  |  versions of HTTP POST that libcurl supports. | ||||||
|  |  | ||||||
|  |  The first version is the simple POST, the most common version, that most HTML | ||||||
|  |  pages using the <form> tag uses. We provide a pointer to the data and tell | ||||||
|  |  libcurl to post it all to the remote site: | ||||||
|  |  | ||||||
|  |     char *data="name=daniel&project=curl"; | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data); | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/"); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* post away! */ | ||||||
|  |  | ||||||
|  |  Simple enough, huh? Since you set the POST options with the | ||||||
|  |  CURLOPT_POSTFIELDS, this automaticly switches the handle to use POST in the | ||||||
|  |  upcoming request. | ||||||
|  |  | ||||||
|  |  Ok, so what if you want to post binary data that also requires you to set the | ||||||
|  |  Content-Type: header of the post? Well, binary posts prevents libcurl from | ||||||
|  |  being able to do strlen() on the data to figure out the size, so therefore we | ||||||
|  |  must tell libcurl the size of the post data. Setting headers in libcurl | ||||||
|  |  requests are done in a generic way, by building a list of our own headers and | ||||||
|  |  then passing that list to libcurl. | ||||||
|  |  | ||||||
|  |     struct curl_slist *headers=NULL; | ||||||
|  |     headers = curl_slist_append(headers, "Content-Type: text/xml"); | ||||||
|  |  | ||||||
|  |     /* post binary data */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_POSTFIELD, binaryptr); | ||||||
|  |  | ||||||
|  |     /* set the size of the postfields data */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDSIZE, 23); | ||||||
|  |  | ||||||
|  |     /* pass our list of custom made headers */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* post away! */ | ||||||
|  |  | ||||||
|  |     curl_slist_free_all(headers); /* free the header list */ | ||||||
|  |  | ||||||
|  |  While the simple examples above cover the majority of all cases where HTTP | ||||||
|  |  POST operations are required, they don't do multipart formposts. Multipart | ||||||
|  |  formposts were introduced as a better way to post (possibly large) binary | ||||||
|  |  data and was first documented in the RFC1867. They're called multipart | ||||||
|  |  because they're built by a chain of parts, each being a single unit. Each | ||||||
|  |  part has its own name and contents. You can in fact create and post a | ||||||
|  |  multipart formpost with the regular libcurl POST support described above, but | ||||||
|  |  that would require that you build a formpost yourself and provide to | ||||||
|  |  libcurl. To make that easier, libcurl provides curl_formadd(). Using this | ||||||
|  |  function, you add parts to the form. When you're done adding parts, you post | ||||||
|  |  the whole form. | ||||||
|  |  | ||||||
|  |  The following example sets two simple text parts with plain textual contents, | ||||||
|  |  and then a file with binary contents and upload the whole thing. | ||||||
|  |  | ||||||
|  |     struct HttpPost *post=NULL; | ||||||
|  |     struct HttpPost *last=NULL; | ||||||
|  |     curl_formadd(&post, &last, | ||||||
|  |                  CURLFORM_COPYNAME, "name", | ||||||
|  |                  CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); | ||||||
|  |     curl_formadd(&post, &last, | ||||||
|  |                  CURLFORM_COPYNAME, "project", | ||||||
|  |                  CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); | ||||||
|  |     curl_formadd(&post, &last, | ||||||
|  |                  CURLFORM_COPYNAME, "logotype-image", | ||||||
|  |                  CURLFORM_FILECONTENT, "curl.png", CURLFORM_END); | ||||||
|  |  | ||||||
|  |     /* Set the form info */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_HTTPPOST, post); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* post away! */ | ||||||
|  |  | ||||||
|  |     /* free the post data again */ | ||||||
|  |     curl_formfree(post); | ||||||
|  |  | ||||||
|  |  Multipart formposts are chains of parts using MIME-style separators and | ||||||
|  |  headers. It means that each one of these separate parts get a few headers set | ||||||
|  |  that describe the individual content-type, size etc. To enable your | ||||||
|  |  application to handicraft this formpost even more, libcurl allows you to | ||||||
|  |  supply your own set of custom headers to such an individual form part. You | ||||||
|  |  can of course supply headers to as many parts you like, but this little | ||||||
|  |  example will show how you set headers to one specific part when you add that | ||||||
|  |  to the post handle: | ||||||
|  |  | ||||||
|  |     struct curl_slist *headers=NULL; | ||||||
|  |     headers = curl_slist_append(headers, "Content-Type: text/xml"); | ||||||
|  |  | ||||||
|  |     curl_formadd(&post, &last, | ||||||
|  |                  CURLFORM_COPYNAME, "logotype-image", | ||||||
|  |                  CURLFORM_FILECONTENT, "curl.xml", | ||||||
|  |                  CURLFORM_CONTENTHEADER, headers, | ||||||
|  |                  CURLFORM_END); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* post away! */ | ||||||
|  |  | ||||||
|  |     curl_formfree(post); /* free post */ | ||||||
|  |     curl_slist_free_all(post); /* free custom header list */ | ||||||
|  |  | ||||||
|  |  Since all options on an easyhandle are "sticky", they remain the same until | ||||||
|  |  changed even if you do call curl_easy_perform(), you may need to tell curl to | ||||||
|  |  go back to a plain GET request if you intend to do such a one as your next | ||||||
|  |  request. You force an easyhandle to back to GET by using the CURLOPT_HTTPGET | ||||||
|  |  option: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_HTTPGET, TRUE); | ||||||
|  |  | ||||||
|  |  Just setting CURLOPT_POSTFIELDS to "" or NULL will *not* stop libcurl from | ||||||
|  |  doing a POST. It will just make it POST without any data to send! | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Showing Progress | ||||||
|  |  | ||||||
|  |  [ built-in progress meter, progress callback ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | libcurl with C++ | ||||||
|  |  | ||||||
|  |  There's basicly only one thing to keep in mind when using C++ instead of C | ||||||
|  |  when interfacing libcurl: | ||||||
|  |  | ||||||
|  |     "The Callbacks Must Be Plain C" | ||||||
|  |  | ||||||
|  |  So if you want a write callback set in libcurl, you should put it within | ||||||
|  |  'extern'. Similar to this: | ||||||
|  |  | ||||||
|  |      extern "C" { | ||||||
|  |        size_t write_data(void *ptr, size_t size, size_t nmemb, | ||||||
|  |                          void *ourpointer) | ||||||
|  |        { | ||||||
|  |          /* do what you want with the data */ | ||||||
|  |        } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  This will of course effectively turn the callback code into C. There won't be | ||||||
|  |  any "this" pointer available etc. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Proxies | ||||||
|  |  | ||||||
|  |  What "proxy" means according to Merriam-Webster: "a person authorized to act | ||||||
|  |  for another" but also "the agency, function, or office of a deputy who acts | ||||||
|  |  as a substitute for another". | ||||||
|  |  | ||||||
|  |  Proxies are exceedingly common these days. Companies often only offer | ||||||
|  |  internet access to employees through their HTTP proxies. Network clients or | ||||||
|  |  user-agents ask the proxy for docuements, the proxy does the actual request | ||||||
|  |  and then it returns them. | ||||||
|  |  | ||||||
|  |  libcurl has full support for HTTP proxies, so when a given URL is wanted, | ||||||
|  |  libcurl will ask the proxy for it instead of trying to connect to the actual | ||||||
|  |  host identified in the URL. | ||||||
|  |  | ||||||
|  |  The fact that the proxy is a HTTP proxy puts certain restrictions on what can | ||||||
|  |  actually happen. A requested URL that might not be a HTTP URL will be still | ||||||
|  |  be passed to the HTTP proxy to deliver back to libcurl. This happens | ||||||
|  |  transparantly, and an application may not need to know. I say "may", because | ||||||
|  |  at times it is very important to understand that all operations over a HTTP | ||||||
|  |  proxy is using the HTTP protocol. For example, you can't invoke your own | ||||||
|  |  custom FTP commands or even proper FTP directory listings. | ||||||
|  |  | ||||||
|  |   Proxy Options | ||||||
|  |  | ||||||
|  |     To tell libcurl to use a proxy at a given port number: | ||||||
|  |  | ||||||
|  |        curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080"); | ||||||
|  |  | ||||||
|  |     Some proxies require user authentication before allowing a request, and | ||||||
|  |     you pass that information similar to this: | ||||||
|  |  | ||||||
|  |        curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password"); | ||||||
|  |  | ||||||
|  |     If you want to, you can specify the host name only in the CURLOPT_PROXY | ||||||
|  |     option, and set the port number separately with CURLOPT_PROXYPORT. | ||||||
|  |  | ||||||
|  |   Environment Variables | ||||||
|  |  | ||||||
|  |     libcurl automaticly checks and uses a set of environment variables to know | ||||||
|  |     what proxies to use for certain protocols. The names of the variables are | ||||||
|  |     following an ancient de facto standard and are built up as | ||||||
|  |     "[protocol]_proxy" (note the lower casing). Which makes the variable | ||||||
|  |     'http_proxy' checked for a name of a proxy to use when the input URL is | ||||||
|  |     HTTP. Following the same rule, the variable named 'ftp_proxy' is checked | ||||||
|  |     for FTP URLs. Again, the proxies are always HTTP proxies, the different | ||||||
|  |     names of the variables simply allows different HTTP proxies to be used. | ||||||
|  |  | ||||||
|  |     The proxy environment variable contents should be in the format | ||||||
|  |     "[protocol://]machine[:port]". Where the protocol:// part is simply | ||||||
|  |     ignored if present (so http://proxy and bluerk://proxy will do the same) | ||||||
|  |     and the optional port number specifies on which port the proxy operates on | ||||||
|  |     the host. If not specified, the internal default port number will be used | ||||||
|  |     and that is most likely *not* the one you would like it to be. | ||||||
|  |  | ||||||
|  |     There are two special environment variables. 'all_proxy' is what sets | ||||||
|  |     proxy for any URL in case the protocol specific variable wasn't set, and | ||||||
|  |     'no_proxy' defines a list of hosts that should not use a proxy even though | ||||||
|  |     a variable may say so. If 'no_proxy' is a plain asterisk ("*") it matches | ||||||
|  |     all hosts. | ||||||
|  |  | ||||||
|  |   SSL and Proxies | ||||||
|  |  | ||||||
|  |     SSL is for secure point-to-point connections. This involves strong | ||||||
|  |     encryption and similar things, which effectivly makes it impossible for a | ||||||
|  |     proxy to operate as a "man in between" which the proxy's task is, as | ||||||
|  |     previously discussed. Instead, the only way to have SSL work over a HTTP | ||||||
|  |     proxy is to ask the proxy to tunnel trough everything without being able | ||||||
|  |     to check or fiddle with the traffic. | ||||||
|  |  | ||||||
|  |     Opening an SSL connection over a HTTP proxy is therefor a matter of asking | ||||||
|  |     the proxy for a straight connection to the target host on a specified | ||||||
|  |     port. This is made with the HTTP request CONNECT. ("please mr proxy, | ||||||
|  |     connect me to that remote host"). | ||||||
|  |  | ||||||
|  |     Because of the nature of this operation, where the proxy has no idea what | ||||||
|  |     kind of data that is passed in and out through this tunnel, this breaks | ||||||
|  |     some of the very few advantages that come from using a proxy, such as | ||||||
|  |     caching.  Many organizations prevent this kind of tunneling to other | ||||||
|  |     destination port numbers than 443 (which is the default HTTPS port | ||||||
|  |     number). | ||||||
|  |  | ||||||
|  |   Tunneling Through Proxy | ||||||
|  |  | ||||||
|  |     As explained above, tunneling is required for SSL to work and often even | ||||||
|  |     restricted to the operation intended for SSL; HTTPS. | ||||||
|  |  | ||||||
|  |     This is however not the only time proxy-tunneling might offer benefits to | ||||||
|  |     you or your application. | ||||||
|  |  | ||||||
|  |     As tunneling opens a direct connection from your application to the remote | ||||||
|  |     machine, it suddenly also re-introduces the ability to do non-HTTP | ||||||
|  |     operations over a HTTP proxy. You can in fact use things such as FTP | ||||||
|  |     upload or FTP custom commands this way. | ||||||
|  |  | ||||||
|  |     Again, this is often prevented by the adminstrators of proxies and is | ||||||
|  |     rarely allowed. | ||||||
|  |  | ||||||
|  |     Tell libcurl to use proxy tunneling like this: | ||||||
|  |  | ||||||
|  |        curl_easy_setopt(easyhandle, CURLOPT_HTTPPROXYTUNNEL, TRUE); | ||||||
|  |  | ||||||
|  |     In fact, there might even be times when you want to do plain HTTP | ||||||
|  |     operations using a tunnel like this, as it then enables you to operate on | ||||||
|  |     the remote server instead of asking the proxy to do so. libcurl will not | ||||||
|  |     stand in the way for such innovative actions either! | ||||||
|  |  | ||||||
|  |   Proxy Auto-Config | ||||||
|  |  | ||||||
|  |     Netscape first came up with this. It is basicly a web page (usually using | ||||||
|  |     a .pac extension) with a javascript that when executed by the browser with | ||||||
|  |     the requested URL as input, returns information to the browser on how to | ||||||
|  |     connect to the URL. The returned information might be "DIRECT" (which | ||||||
|  |     means no proxy should be used), "PROXY host:port" (to tell the browser | ||||||
|  |     where the proxy for this particular URL is) or "SOCKS host:port" (to | ||||||
|  |     direct the brower to a SOCKS proxy). | ||||||
|  |  | ||||||
|  |     libcurl has no means to interpret or evaluate javascript and thus it | ||||||
|  |     doesn't support this. If you get yourself in a position where you face | ||||||
|  |     this nasty invention, the following advice have been mentioned and used in | ||||||
|  |     the past: | ||||||
|  |  | ||||||
|  |     - Depending on the javascript complexity, write up a script that | ||||||
|  |       translates it to another language and execute that. | ||||||
|  |  | ||||||
|  |     - Read the javascript code and rewrite the same logic in another language. | ||||||
|  |  | ||||||
|  |     - Implement a javascript interpreted, people have successfully used the | ||||||
|  |       Mozilla javascript engine in the past. | ||||||
|  |  | ||||||
|  |     - Ask your admins to stop this, for a static proxy setup or similar. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Persistancy Is The Way to Happiness | ||||||
|  |  | ||||||
|  |  Re-cycling the same easy handle several times when doing multiple requests is | ||||||
|  |  the way to go. | ||||||
|  |  | ||||||
|  |  After each single curl_easy_perform() operation, libcurl will keep the | ||||||
|  |  connection alive and open. A subsequent request using the same easy handle to | ||||||
|  |  the same host might just be able to use the already open connection! This | ||||||
|  |  reduces network impact a lot. | ||||||
|  |  | ||||||
|  |  Even if the connection is dropped, all connections involving SSL to the same | ||||||
|  |  host again, will benefit from libcurl's session ID cache that drasticly | ||||||
|  |  reduces re-connection time. | ||||||
|  |  | ||||||
|  |  FTP connections that are kept alive saves a lot of time, as the command- | ||||||
|  |  response roundtrips are skipped, and also you don't risk getting blocked | ||||||
|  |  without permission to login again like on many FTP servers only allowing N | ||||||
|  |  persons to be logged in at the same time. | ||||||
|  |  | ||||||
|  |  libcurl caches DNS name resolving results, to make lookups of a previously | ||||||
|  |  looked up name a lot faster. | ||||||
|  |  | ||||||
|  |  Other interesting details that improve performance for subsequent requests | ||||||
|  |  may also be added in the future. | ||||||
|  |  | ||||||
|  |  Each easy handle will attempt to keep the last few connections alive for a | ||||||
|  |  while in case they are to be used again. You can set the size of this "cache" | ||||||
|  |  with the CURLOPT_MAXCONNECTS option. Default is 5. It is very seldom any | ||||||
|  |  point in changing this value, and if you think of changing this it is often | ||||||
|  |  just a matter of thinking again. | ||||||
|  |  | ||||||
|  |  When the connection cache gets filled, libcurl must close an existing | ||||||
|  |  connection in order to get room for the new one. To know which connection to | ||||||
|  |  close, libcurl uses a "close policy" that you can affect with the | ||||||
|  |  CURLOPT_CLOSEPOLICY option. There's only two polices implemented as of this | ||||||
|  |  writing (libcurl 7.9.4) and they are: | ||||||
|  |  | ||||||
|  |   CURLCLOSEPOLICY_LEAST_RECENTLY_USED simply close the one that hasn't been | ||||||
|  |   used for the longest time. This is the default behavior. | ||||||
|  |  | ||||||
|  |   CURLCLOSEPOLICY_OLDEST closes the oldest connection, the one that was | ||||||
|  |   createst the longest time ago. | ||||||
|  |  | ||||||
|  |  There are, or at least were, plans to support a close policy that would call | ||||||
|  |  a user-specified callback to let the user be able to decide which connection | ||||||
|  |  to dump when this is necessary and therefor is the CURLOPT_CLOSEFUNCTION an | ||||||
|  |  existing option still today. Nothing ever uses this though and this will not | ||||||
|  |  be used within the forseeable future either. | ||||||
|  |  | ||||||
|  |  To force your upcoming request to not use an already existing connection (it | ||||||
|  |  will even close one first if there happens to be one alive to the same host | ||||||
|  |  you're about to operate on), you can do that by setting CURLOPT_FRESH_CONNECT | ||||||
|  |  to TRUE. In a similar spirit, you can also forbid the upcoming request to be | ||||||
|  |  "lying" around and possibly get re-used after the request by setting | ||||||
|  |  CURLOPT_FORBID_REUSE to TRUE. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Customizing Operations | ||||||
|  |  | ||||||
|  |  There is an ongoing development today where more and more protocols are built | ||||||
|  |  upon HTTP for transport. This has obvious benefits as HTTP is a tested and | ||||||
|  |  reliable protocol that is widely deployed and have excellent proxy-support. | ||||||
|  |  | ||||||
|  |  When you use one of these protocols, and even when doing other kinds of | ||||||
|  |  programming you may need to change the traditional HTTP (or FTP or...) | ||||||
|  |  manners. You may need to change words, headers or various data. | ||||||
|  |  | ||||||
|  |  libcurl is your friend here too. | ||||||
|  |  | ||||||
|  |  If just changing the actual HTTP request keyword is what you want, like when | ||||||
|  |  GET, HEAD or POST is not good enough for you, CURLOPT_CUSTOMREQUEST is there | ||||||
|  |  for you. It is very simple to use: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "MYOWNRUQUEST"); | ||||||
|  |  | ||||||
|  |  When using the custom request, you change the request keyword of the actual | ||||||
|  |  request you are performing. Thus, by default you make GET request but you can | ||||||
|  |  also make a POST operation (as described before) and then replace the POST | ||||||
|  |  keyword if you want to. You're the boss. | ||||||
|  |  | ||||||
|  |  HTTP-like protocols pass a series of headers to the server when doing the | ||||||
|  |  request, and you're free to pass any amount of extra headers that you think | ||||||
|  |  fit. Adding headers are this easy: | ||||||
|  |  | ||||||
|  |     struct curl_slist *headers; | ||||||
|  |  | ||||||
|  |     headers = curl_slist_append(headers, "Hey-server-hey: how are you?"); | ||||||
|  |     headers = curl_slist_append(headers, "X-silly-content: yes"); | ||||||
|  |  | ||||||
|  |     /* pass our list of custom made headers */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* transfer http */ | ||||||
|  |  | ||||||
|  |     curl_slist_free_all(headers); /* free the header list */ | ||||||
|  |  | ||||||
|  |  ... and if you think some of the internally generated headers, such as | ||||||
|  |  User-Agent:, Accept: or Host: don't contain the data you want them to | ||||||
|  |  contain, you can replace them by simply setting them too: | ||||||
|  |  | ||||||
|  |     headers = curl_slist_append(headers, "User-Agent: 007"); | ||||||
|  |     headers = curl_slist_append(headers, "Host: munged.host.line"); | ||||||
|  |  | ||||||
|  |  If you replace an existing header with one with no contents, you will prevent | ||||||
|  |  the header from being sent. Like if you want to completely prevent the | ||||||
|  |  "Accept:" header to be sent, you can disable it with code similar to this: | ||||||
|  |  | ||||||
|  |     headers = curl_slist_append(headers, "Accept:"); | ||||||
|  |  | ||||||
|  |  Both replacing and cancelling internal headers should be done with careful | ||||||
|  |  consideration and you should be aware that you may violate the HTTP protocol | ||||||
|  |  when doing so. | ||||||
|  |  | ||||||
|  |  Not all protocols are HTTP-like, and thus the above may not help you when you | ||||||
|  |  want to make for example your FTP transfers to behave differently. | ||||||
|  |  | ||||||
|  |  Sending custom commands to a FTP server means that you need to send the | ||||||
|  |  comands exactly as the FTP server expects them (RFC959 is a good guide here), | ||||||
|  |  and you can only use commands that work on the control-connection alone. All | ||||||
|  |  kinds of commands that requires data interchange and thus needs a | ||||||
|  |  data-connection must be left to libcurl's own judgement. Also be aware that | ||||||
|  |  libcurl will do its very best to change directory to the target directory | ||||||
|  |  before doing any transfer, so if you change directory (with CWD or similar) | ||||||
|  |  you might confuse libcurl and then it might not attempt to transfer the file | ||||||
|  |  in the correct remote directory. | ||||||
|  |  | ||||||
|  |  A little example that deletes a given file before an operation: | ||||||
|  |  | ||||||
|  |     headers = curl_slist_append(headers, "DELE file-to-remove"); | ||||||
|  |  | ||||||
|  |     /* pass the list of custom commands to the handle */ | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers); | ||||||
|  |  | ||||||
|  |     curl_easy_perform(easyhandle); /* transfer ftp data! */ | ||||||
|  |  | ||||||
|  |     curl_slist_free_all(headers); /* free the header list */ | ||||||
|  |  | ||||||
|  |  If you would instead want this operation (or chain of operations) to happen | ||||||
|  |  _after_ the data transfer took place the option to curl_easy_setopt() would | ||||||
|  |  instead be called CURLOPT_POSTQUOTE and used the exact same way. | ||||||
|  |  | ||||||
|  |  The custom FTP command will be issued to the server in the same order they | ||||||
|  |  are built in the list, and if a command gets an error code returned back from | ||||||
|  |  the server no more commands will be issued and libcurl will bail out with an | ||||||
|  |  error code. Note that if you use CURLOPT_QUOTE to send commands before a | ||||||
|  |  transfer, no transfer will actually take place then. | ||||||
|  |  | ||||||
|  |  [ custom FTP commands without transfer, FTP "header-only", HTTP 1.0 ] | ||||||
|  |  | ||||||
|  | Cookies Without Chocolate Chips | ||||||
|  |  | ||||||
|  |  [ set cookies, read cookies from file, cookie-jar ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Headers Equal Fun | ||||||
|  |  | ||||||
|  |  [ use the header callback for HTTP, FTP etc ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Post Transfer Information | ||||||
|  |  | ||||||
|  |  [ curl_easy_getinfo ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Security Considerations | ||||||
|  |  | ||||||
|  |  [ ps output, netrc plain text, plain text protocols / base64 ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | SSL, Certificates and Other Tricks | ||||||
|  |  | ||||||
|  |  [ seeding, passwords, keys, certificates, ENGINE, ca certs ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Future | ||||||
|  |  | ||||||
|  |  [ multi interface, sharing between handles, mutexes, pipelining ] | ||||||
|  |  | ||||||
|  |  | ||||||
| ----- | ----- | ||||||
| Footnotes: | Footnotes: | ||||||
|  |  | ||||||
| @@ -207,3 +814,11 @@ Footnotes: | |||||||
|       but libcurl does not support the chunked transfers on uploading that is |       but libcurl does not support the chunked transfers on uploading that is | ||||||
|       necessary for this feature to work. We'd gratefully appreciate patches |       necessary for this feature to work. We'd gratefully appreciate patches | ||||||
|       that bring this functionality... |       that bring this functionality... | ||||||
|  |  | ||||||
|  | [2] = This happens on Windows machines when libcurl is built and used as a | ||||||
|  |       DLL. However, you can still do this on Windows if you link with a static | ||||||
|  |       library. | ||||||
|  |  | ||||||
|  | [3] = The curl-config tool is generated at build-time (on unix-like systems) | ||||||
|  |       and should be installed with the 'make install' or similar instruction | ||||||
|  |       that installs the library, header files, man pages etc. | ||||||
|   | |||||||
| @@ -6,8 +6,10 @@ | |||||||
| .SH NAME | .SH NAME | ||||||
| libcurl \- client-side URL transfers | libcurl \- client-side URL transfers | ||||||
| .SH DESCRIPTION | .SH DESCRIPTION | ||||||
| This is an overview on how to use libcurl in your c/c++ programs. There are | This is an overview on how to use libcurl in your C programs. There are | ||||||
| specific man pages for each function mentioned in here. | specific man pages for each function mentioned in here. There's also the | ||||||
|  | libcurl-the-guide document for a complete tutorial to programming with | ||||||
|  | libcurl. | ||||||
|  |  | ||||||
| libcurl can also be used directly from within your Java, PHP, Perl, Ruby or | libcurl can also be used directly from within your Java, PHP, Perl, Ruby or | ||||||
| Tcl programs as well, look elsewhere for documentation on this! | Tcl programs as well, look elsewhere for documentation on this! | ||||||
| @@ -56,9 +58,6 @@ get information about a performed transfer | |||||||
| .B curl_formadd() | .B curl_formadd() | ||||||
| helps building a HTTP form POST | helps building a HTTP form POST | ||||||
| .TP | .TP | ||||||
| .B curl_formparse() |  | ||||||
| helps building a HTTP form POST (deprecated since 7.9 use curl_formadd()!) |  | ||||||
| .TP |  | ||||||
| .B curl_formfree() | .B curl_formfree() | ||||||
| free a list built with curl_formparse()/curl_formadd() | free a list built with curl_formparse()/curl_formadd() | ||||||
| .TP | .TP | ||||||
|   | |||||||
| @@ -7,7 +7,7 @@ | |||||||
|  *                            | (__| |_| |  _ <| |___  |  *                            | (__| |_| |  _ <| |___  | ||||||
|  *                             \___|\___/|_| \_\_____| |  *                             \___|\___/|_| \_\_____| | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al. |  * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||||
|  * |  * | ||||||
|  * In order to be useful for every potential user, curl and libcurl are |  * In order to be useful for every potential user, curl and libcurl are | ||||||
|  * dual-licensed under the MPL and the MIT/X-derivate licenses. |  * dual-licensed under the MPL and the MIT/X-derivate licenses. | ||||||
| @@ -30,11 +30,11 @@ | |||||||
| # include <time.h> | # include <time.h> | ||||||
| #else | #else | ||||||
| # include <sys/types.h> | # include <sys/types.h> | ||||||
| # if TIME_WITH_SYS_TIME | # ifdef TIME_WITH_SYS_TIME | ||||||
| #  include <sys/time.h> | #  include <sys/time.h> | ||||||
| #  include <time.h> | #  include <time.h> | ||||||
| # else | # else | ||||||
| #  if HAVE_SYS_TIME_H | #  ifdef HAVE_SYS_TIME_H | ||||||
| #   include <sys/time.h> | #   include <sys/time.h> | ||||||
| #  else | #  else | ||||||
| #   include <time.h> | #   include <time.h> | ||||||
| @@ -272,7 +272,7 @@ typedef enum { | |||||||
|   /* Set cookie in request: */ |   /* Set cookie in request: */ | ||||||
|   CINIT(COOKIE, OBJECTPOINT, 22), |   CINIT(COOKIE, OBJECTPOINT, 22), | ||||||
|  |  | ||||||
|   /* This points to a linked list of headers, struct HttpHeader kind */ |   /* This points to a linked list of headers, struct curl_slist kind */ | ||||||
|   CINIT(HTTPHEADER, OBJECTPOINT, 23), |   CINIT(HTTPHEADER, OBJECTPOINT, 23), | ||||||
|  |  | ||||||
|   /* This points to a linked list of post entries, struct HttpPost */ |   /* This points to a linked list of post entries, struct HttpPost */ | ||||||
| @@ -613,8 +613,8 @@ CURLcode curl_global_init(long flags); | |||||||
| void curl_global_cleanup(void); | void curl_global_cleanup(void); | ||||||
|  |  | ||||||
| /* This is the version number */ | /* This is the version number */ | ||||||
| #define LIBCURL_VERSION "7.9.3-pre2" | #define LIBCURL_VERSION "7.9.4" | ||||||
| #define LIBCURL_VERSION_NUM 0x070903 | #define LIBCURL_VERSION_NUM 0x070904 | ||||||
|  |  | ||||||
| /* linked-list structure for the CURLOPT_QUOTE option (and other) */ | /* linked-list structure for the CURLOPT_QUOTE option (and other) */ | ||||||
| struct curl_slist { | struct curl_slist { | ||||||
| @@ -666,7 +666,11 @@ typedef enum { | |||||||
|  |  | ||||||
|   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, |   CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, | ||||||
|  |  | ||||||
|   CURLINFO_LASTONE          = 18 |   CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18, | ||||||
|  |  | ||||||
|  |   /* Fill in new entries here! */ | ||||||
|  |  | ||||||
|  |   CURLINFO_LASTONE          = 19 | ||||||
| } CURLINFO; | } CURLINFO; | ||||||
|  |  | ||||||
| /* unfortunately, the easy.h include file needs the options and info stuff | /* unfortunately, the easy.h include file needs the options and info stuff | ||||||
|   | |||||||
| @@ -6,7 +6,8 @@ AUTOMAKE_OPTIONS = foreign no-dependencies | |||||||
|  |  | ||||||
| EXTRA_DIST = getdate.y \ | EXTRA_DIST = getdate.y \ | ||||||
|        Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \ |        Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \ | ||||||
|        libcurl.def dllinit.c curllib.dsp curllib.dsw |        libcurl.def dllinit.c curllib.dsp curllib.dsw \ | ||||||
|  |        config-vms.h config-win32.h config-riscos.h config-mac.h | ||||||
|  |  | ||||||
| lib_LTLIBRARIES = libcurl.la | lib_LTLIBRARIES = libcurl.la | ||||||
|  |  | ||||||
|   | |||||||
| @@ -35,14 +35,14 @@ libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c \ | |||||||
| 	ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c	\ | 	ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c	\ | ||||||
| 	telnet.h getinfo.c strequal.c strequal.h easy.c security.h		\ | 	telnet.h getinfo.c strequal.c strequal.h easy.c security.h		\ | ||||||
| 	security.c krb4.h krb4.c memdebug.h memdebug.c inet_ntoa_r.h http_chunks.h http_chunks.c \ | 	security.c krb4.h krb4.c memdebug.h memdebug.c inet_ntoa_r.h http_chunks.h http_chunks.c \ | ||||||
| 	strtok.c connect.c | 	strtok.c connect.c hash.c llist.c | ||||||
|  |  | ||||||
| libcurl_a_OBJECTS =  file.o timeval.o base64.o hostip.o progress.o \ | libcurl_a_OBJECTS =  file.o timeval.o base64.o hostip.o progress.o \ | ||||||
| 	formdata.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \ | 	formdata.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \ | ||||||
| 	speedcheck.o getdate.o transfer.o ldap.o ssluse.o version.o \ | 	speedcheck.o getdate.o transfer.o ldap.o ssluse.o version.o \ | ||||||
| 	getenv.o escape.o mprintf.o telnet.o getpass.o netrc.o getinfo.o \ | 	getenv.o escape.o mprintf.o telnet.o getpass.o netrc.o getinfo.o \ | ||||||
| 	strequal.o easy.o security.o krb4.o memdebug.o http_chunks.o \ | 	strequal.o easy.o security.o krb4.o memdebug.o http_chunks.o \ | ||||||
| 	strtok.o connect.o | 	strtok.o connect.o hash.o llist.o | ||||||
|  |  | ||||||
| LIBRARIES =  $(libcurl_a_LIBRARIES) | LIBRARIES =  $(libcurl_a_LIBRARIES) | ||||||
| SOURCES = $(libcurl_a_SOURCES) | SOURCES = $(libcurl_a_SOURCES) | ||||||
|   | |||||||
| @@ -23,13 +23,18 @@ | |||||||
| # CHANGE LOG | # CHANGE LOG | ||||||
| # ------------------------------------------------------------ | # ------------------------------------------------------------ | ||||||
| # 05.11.2001   John Lask   Initial Release | # 05.11.2001   John Lask   Initial Release | ||||||
|  | # 02.05.2002   Miklos Nemeth OPENSSL_PATH environment; no need | ||||||
|  | #              for OpenSSL libraries when creating a  | ||||||
|  | #              static libcurl.lib | ||||||
| # | # | ||||||
| # | # | ||||||
| ############################################################## | ############################################################## | ||||||
|  |  | ||||||
| LIB_NAME       = libcurl | LIB_NAME       = libcurl | ||||||
| LIB_NAME_DEBUG = libcurld | LIB_NAME_DEBUG = libcurld | ||||||
|  | !IFNDEF OPENSSL_PATH | ||||||
| OPENSSL_PATH   = ../../openssl-0.9.6 | OPENSSL_PATH   = ../../openssl-0.9.6 | ||||||
|  | !ENDIF | ||||||
|  |  | ||||||
| ############################################################# | ############################################################# | ||||||
| ## Nothing more to do below this line! | ## Nothing more to do below this line! | ||||||
| @@ -46,6 +51,8 @@ LFLAGSSSL = /LIBPATH:$(OPENSSL_PATH)/out32dll | |||||||
| LINKLIBS  = ws2_32.lib | LINKLIBS  = ws2_32.lib | ||||||
| SSLLIBS   = libeay32.lib ssleay32.lib RSAglue.lib | SSLLIBS   = libeay32.lib ssleay32.lib RSAglue.lib | ||||||
| CFGSET    = FALSE | CFGSET    = FALSE | ||||||
|  | LFLAGSSSL= | ||||||
|  | SSLLIBS  = | ||||||
|  |  | ||||||
| ###################### | ###################### | ||||||
| # release | # release | ||||||
|   | |||||||
| @@ -221,22 +221,22 @@ | |||||||
| #define HAVE_NETINET_IN_H 1 | #define HAVE_NETINET_IN_H 1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/crypto.h> header file.  */ | /* Define if you have the <openssl/crypto.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_CRYPTO_H | #define HAVE_OPENSSL_CRYPTO_H 1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/err.h> header file.  */ | /* Define if you have the <openssl/err.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_ERR_H | #define HAVE_OPENSSL_ERR_H	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/pem.h> header file.  */ | /* Define if you have the <openssl/pem.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_PEM_H | #define HAVE_OPENSSL_PEM_H	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/rsa.h> header file.  */ | /* Define if you have the <openssl/rsa.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_RSA_H | #define HAVE_OPENSSL_RSA_H 1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/ssl.h> header file.  */ | /* Define if you have the <openssl/ssl.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_SSL_H | #define HAVE_OPENSSL_SSL_H	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <openssl/x509.h> header file.  */ | /* Define if you have the <openssl/x509.h> header file.  */ | ||||||
| #undef HAVE_OPENSSL_X509_H | #define HAVE_OPENSSL_X509_H	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the <pem.h> header file.  */ | /* Define if you have the <pem.h> header file.  */ | ||||||
| #undef HAVE_PEM_H | #undef HAVE_PEM_H | ||||||
| @@ -296,7 +296,7 @@ | |||||||
| #undef HAVE_X509_H | #undef HAVE_X509_H | ||||||
| 
 | 
 | ||||||
| /* Define if you have the crypto library (-lcrypto).  */ | /* Define if you have the crypto library (-lcrypto).  */ | ||||||
| #undef HAVE_LIBCRYPTO | #define HAVE_LIBCRYPTO 1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the dl library (-ldl).  */ | /* Define if you have the dl library (-ldl).  */ | ||||||
| #undef HAVE_LIBDL | #undef HAVE_LIBDL | ||||||
| @@ -314,7 +314,7 @@ | |||||||
| #define HAVE_LIBSOCKET 1 | #define HAVE_LIBSOCKET 1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the ssl library (-lssl).  */ | /* Define if you have the ssl library (-lssl).  */ | ||||||
| #undef HAVE_LIBSSL | #define HAVE_LIBSSL	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the ucb library (-lucb).  */ | /* Define if you have the ucb library (-lucb).  */ | ||||||
| #undef HAVE_LIBUCB | #undef HAVE_LIBUCB | ||||||
| @@ -346,7 +346,7 @@ | |||||||
| #undef HAVE_GETPASS | #undef HAVE_GETPASS | ||||||
| 
 | 
 | ||||||
| /* Define if you have a working OpenSSL installation */ | /* Define if you have a working OpenSSL installation */ | ||||||
| #undef OPENSSL_ENABLED | #define OPENSSL_ENABLED	1 | ||||||
| 
 | 
 | ||||||
| /* Define if you have the `dlopen' function. */ | /* Define if you have the `dlopen' function. */ | ||||||
| #undef HAVE_DLOPEN | #undef HAVE_DLOPEN | ||||||
| @@ -365,3 +365,4 @@ | |||||||
| 
 | 
 | ||||||
| #define HAVE_MEMORY_H   1 | #define HAVE_MEMORY_H   1 | ||||||
| 
 | 
 | ||||||
|  | #define HAVE_FIONBIO	1 | ||||||
| @@ -48,6 +48,10 @@ | |||||||
| #include <stdlib.h> /* required for free() prototype, without it, this crashes | #include <stdlib.h> /* required for free() prototype, without it, this crashes | ||||||
|                        on macos 68K */ |                        on macos 68K */ | ||||||
| #endif | #endif | ||||||
|  | #ifdef	VMS | ||||||
|  | #include <in.h> | ||||||
|  | #include <inet.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| @@ -361,7 +365,7 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */ | |||||||
|  |  | ||||||
|     /* get the most strict timeout of the ones converted to milliseconds */ |     /* get the most strict timeout of the ones converted to milliseconds */ | ||||||
|     if(data->set.timeout && |     if(data->set.timeout && | ||||||
|        (data->set.timeout>data->set.connecttimeout)) |        (data->set.timeout < data->set.connecttimeout)) | ||||||
|       timeout_ms = data->set.timeout*1000; |       timeout_ms = data->set.timeout*1000; | ||||||
|     else |     else | ||||||
|       timeout_ms = data->set.connecttimeout*1000; |       timeout_ms = data->set.connecttimeout*1000; | ||||||
| @@ -369,10 +373,12 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */ | |||||||
|     /* subtract the passed time */ |     /* subtract the passed time */ | ||||||
|     timeout_ms -= (long)has_passed; |     timeout_ms -= (long)has_passed; | ||||||
|  |  | ||||||
|     if(timeout_ms < 0) |     if(timeout_ms < 0) { | ||||||
|       /* a precaution, no need to continue if time already is up */ |       /* a precaution, no need to continue if time already is up */ | ||||||
|  |       failf(data, "Connection time-out"); | ||||||
|       return CURLE_OPERATION_TIMEOUTED; |       return CURLE_OPERATION_TIMEOUTED; | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
| #ifdef ENABLE_IPV6 | #ifdef ENABLE_IPV6 | ||||||
|   /* |   /* | ||||||
|   | |||||||
| @@ -38,7 +38,7 @@ struct Cookie { | |||||||
|   char *value;       /* name = <this> */ |   char *value;       /* name = <this> */ | ||||||
|   char *path;	      /* path = <this> */ |   char *path;	      /* path = <this> */ | ||||||
|   char *domain;      /* domain = <this> */ |   char *domain;      /* domain = <this> */ | ||||||
|   time_t expires;    /* expires = <this> */ |   long expires;    /* expires = <this> */ | ||||||
|   char *expirestr;   /* the plain text version */ |   char *expirestr;   /* the plain text version */ | ||||||
|  |  | ||||||
|   char field1;       /* read from a cookie file, 1 => FALSE, 2=> TRUE */ |   char field1;       /* read from a cookie file, 1 => FALSE, 2=> TRUE */ | ||||||
|   | |||||||
| @@ -81,6 +81,10 @@ DllMain ( | |||||||
|     } |     } | ||||||
|   return TRUE; |   return TRUE; | ||||||
| } | } | ||||||
|  | #else | ||||||
|  | #ifdef VMS | ||||||
|  | int VOID_VAR_DLLINIT;	 | ||||||
|  | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -235,7 +235,6 @@ int FormParse(char *input, | |||||||
| 	     | 	     | ||||||
| 	    if(2 != sscanf(type, "%127[^/]/%127[^,\n]", | 	    if(2 != sscanf(type, "%127[^/]/%127[^,\n]", | ||||||
| 			   major, minor)) { | 			   major, minor)) { | ||||||
| 	      fprintf(stderr, "Illegally formatted content-type field!\n"); |  | ||||||
|               free(contents); |               free(contents); | ||||||
| 	      return 2; /* illegal content-type syntax! */ | 	      return 2; /* illegal content-type syntax! */ | ||||||
| 	    } | 	    } | ||||||
| @@ -371,7 +370,6 @@ int FormParse(char *input, | |||||||
|  |  | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
|     fprintf(stderr, "Illegally formatted input field!\n"); |  | ||||||
|     free(contents); |     free(contents); | ||||||
|     return 1; |     return 1; | ||||||
|   } |   } | ||||||
| @@ -841,7 +839,6 @@ FORMcode FormAdd(struct HttpPost **httppost, | |||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|     default: |     default: | ||||||
|       fprintf (stderr, "got unknown CURLFORM_OPTION: %d\n", option); |  | ||||||
|       return_value = FORMADD_UNKNOWN_OPTION; |       return_value = FORMADD_UNKNOWN_OPTION; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -1068,8 +1065,11 @@ struct FormData *Curl_getFormData(struct HttpPost *post, | |||||||
|    |    | ||||||
|   do { |   do { | ||||||
|  |  | ||||||
|  |     if(size) | ||||||
|  |       size += AddFormDataf(&form, "\r\n"); | ||||||
|  |  | ||||||
|     /* boundary */ |     /* boundary */ | ||||||
|     size += AddFormDataf(&form, "\r\n--%s\r\n", boundary); |     size += AddFormDataf(&form, "--%s\r\n", boundary); | ||||||
|  |  | ||||||
|     size += AddFormData(&form, |     size += AddFormData(&form, | ||||||
|                         "Content-Disposition: form-data; name=\"", 0); |                         "Content-Disposition: form-data; name=\"", 0); | ||||||
| @@ -1155,10 +1155,13 @@ struct FormData *Curl_getFormData(struct HttpPost *post, | |||||||
| 	  } | 	  } | ||||||
|           if(fileread != stdin) |           if(fileread != stdin) | ||||||
|             fclose(fileread); |             fclose(fileread); | ||||||
| 	} else { |  | ||||||
| 	  size += AddFormData(&form, "[File wasn't found by client]", 0); |  | ||||||
| 	} | 	} | ||||||
|       } else { |         else { | ||||||
|  |           /* File wasn't found, add a nothing field! */ | ||||||
|  | 	  size += AddFormData(&form, "", 0); | ||||||
|  | 	} | ||||||
|  |       } | ||||||
|  |  else { | ||||||
| 	/* include the contents we got */ | 	/* include the contents we got */ | ||||||
| 	size += AddFormData(&form, post->contents, post->contentslength); | 	size += AddFormData(&form, post->contents, post->contentslength); | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -55,6 +55,7 @@ | |||||||
| #include <netdb.h> | #include <netdb.h> | ||||||
| #endif | #endif | ||||||
| #ifdef	VMS | #ifdef	VMS | ||||||
|  | #include <in.h> | ||||||
| #include <inet.h> | #include <inet.h> | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
| @@ -358,7 +359,7 @@ int Curl_GetFTPResponse(char *buf, | |||||||
|   if(!error) |   if(!error) | ||||||
|     code = atoi(buf); |     code = atoi(buf); | ||||||
|  |  | ||||||
| #if KRB4 | #ifdef KRB4 | ||||||
|   /* handle the security-oriented responses 6xx ***/ |   /* handle the security-oriented responses 6xx ***/ | ||||||
|   /* FIXME: some errorchecking perhaps... ***/ |   /* FIXME: some errorchecking perhaps... ***/ | ||||||
|   switch(code) { |   switch(code) { | ||||||
| @@ -911,7 +912,7 @@ ftp_pasv_verbose(struct connectdata *conn, | |||||||
| #  ifdef HAVE_GETHOSTBYADDR_R_7 | #  ifdef HAVE_GETHOSTBYADDR_R_7 | ||||||
|   /* Solaris and IRIX */ |   /* Solaris and IRIX */ | ||||||
|   answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET, |   answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET, | ||||||
|                            (struct hostent *)hostent_buf, |                            (struct hostent *)bigbuf, | ||||||
|                            hostent_buf + sizeof(*answer), |                            hostent_buf + sizeof(*answer), | ||||||
|                            sizeof(hostent_buf) - sizeof(*answer), |                            sizeof(hostent_buf) - sizeof(*answer), | ||||||
|                            &h_errnop); |                            &h_errnop); | ||||||
| @@ -1575,7 +1576,7 @@ CURLcode ftp_perform(struct connectdata *conn) | |||||||
|       struct tm buffer; |       struct tm buffer; | ||||||
|       tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); |       tm = (struct tm *)localtime_r(&data->info.filetime, &buffer); | ||||||
| #else | #else | ||||||
|       tm = localtime(&data->info.filetime); |       tm = localtime((unsigned long *)&data->info.filetime); | ||||||
| #endif | #endif | ||||||
|       /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ |       /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */ | ||||||
|       strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", |       strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n", | ||||||
|   | |||||||
							
								
								
									
										523
									
								
								lib/getdate.c
									
									
									
									
									
								
							
							
						
						
									
										523
									
								
								lib/getdate.c
									
									
									
									
									
								
							| @@ -34,8 +34,6 @@ | |||||||
|  |  | ||||||
| #include "setup.h" | #include "setup.h" | ||||||
|  |  | ||||||
| #ifdef HAVE_CONFIG_H |  | ||||||
| # include "config.h" |  | ||||||
| # ifdef HAVE_ALLOCA_H | # ifdef HAVE_ALLOCA_H | ||||||
| #  include <alloca.h> | #  include <alloca.h> | ||||||
| # endif | # endif | ||||||
| @@ -43,6 +41,10 @@ | |||||||
| # ifdef HAVE_TIME_H | # ifdef HAVE_TIME_H | ||||||
| #  include <time.h> | #  include <time.h> | ||||||
| # endif | # endif | ||||||
|  |  | ||||||
|  | #ifndef YYDEBUG | ||||||
|  |   /* to satisfy gcc -Wundef, we set this to 0 */ | ||||||
|  | #define YYDEBUG 0 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* Since the code of getdate.y is not included in the Emacs executable | /* Since the code of getdate.y is not included in the Emacs executable | ||||||
| @@ -192,38 +194,40 @@ typedef enum _MERIDIAN { | |||||||
|     MERam, MERpm, MER24 |     MERam, MERpm, MER24 | ||||||
| } MERIDIAN; | } MERIDIAN; | ||||||
|  |  | ||||||
|  | /* parse results and input string */ | ||||||
|  | typedef struct _CONTEXT { | ||||||
|  |     const char	*yyInput; | ||||||
|  |     int		yyDayOrdinal; | ||||||
|  |     int		yyDayNumber; | ||||||
|  |     int		yyHaveDate; | ||||||
|  |     int		yyHaveDay; | ||||||
|  |     int		yyHaveRel; | ||||||
|  |     int		yyHaveTime; | ||||||
|  |     int		yyHaveZone; | ||||||
|  |     int		yyTimezone; | ||||||
|  |     int		yyDay; | ||||||
|  |     int		yyHour; | ||||||
|  |     int		yyMinutes; | ||||||
|  |     int		yyMonth; | ||||||
|  |     int		yySeconds; | ||||||
|  |     int		yyYear; | ||||||
|  |     MERIDIAN	yyMeridian; | ||||||
|  |     int		yyRelDay; | ||||||
|  |     int		yyRelHour; | ||||||
|  |     int		yyRelMinutes; | ||||||
|  |     int		yyRelMonth; | ||||||
|  |     int		yyRelSeconds; | ||||||
|  |     int		yyRelYear; | ||||||
|  | } CONTEXT; | ||||||
|  |  | ||||||
| /* | /* enable use of extra argument to yyparse and yylex which can be used to pass | ||||||
| **  Global variables.  We could get rid of most of these by using a good | **  in a user defined value (CONTEXT struct in our case) | ||||||
| **  union as the yacc stack.  (This routine was originally written before |  | ||||||
| **  yacc had the %union construct.)  Maybe someday; right now we only use |  | ||||||
| **  the %union very rarely. |  | ||||||
| */ | */ | ||||||
| static const char	*yyInput; | #define YYPARSE_PARAM cookie | ||||||
| static int	yyDayOrdinal; | #define YYLEX_PARAM cookie | ||||||
| static int	yyDayNumber; | #define context ((CONTEXT *) cookie) | ||||||
| static int	yyHaveDate; |  | ||||||
| static int	yyHaveDay; |  | ||||||
| static int	yyHaveRel; |  | ||||||
| static int	yyHaveTime; |  | ||||||
| static int	yyHaveZone; |  | ||||||
| static int	yyTimezone; |  | ||||||
| static int	yyDay; |  | ||||||
| static int	yyHour; |  | ||||||
| static int	yyMinutes; |  | ||||||
| static int	yyMonth; |  | ||||||
| static int	yySeconds; |  | ||||||
| static int	yyYear; |  | ||||||
| static MERIDIAN	yyMeridian; |  | ||||||
| static int	yyRelDay; |  | ||||||
| static int	yyRelHour; |  | ||||||
| static int	yyRelMinutes; |  | ||||||
| static int	yyRelMonth; |  | ||||||
| static int	yyRelSeconds; |  | ||||||
| static int	yyRelYear; |  | ||||||
|  |  | ||||||
|  | #line 215 "getdate.y" | ||||||
| #line 206 "getdate.y" |  | ||||||
| typedef union { | typedef union { | ||||||
|     int			Number; |     int			Number; | ||||||
|     enum _MERIDIAN	Meridian; |     enum _MERIDIAN	Meridian; | ||||||
| @@ -306,11 +310,11 @@ static const short yyrhs[] = {    -1, | |||||||
|  |  | ||||||
| #if YYDEBUG != 0 | #if YYDEBUG != 0 | ||||||
| static const short yyrline[] = { 0, | static const short yyrline[] = { 0, | ||||||
|    222,   223,   226,   229,   232,   235,   238,   241,   244,   250, |    231,   232,   235,   238,   241,   244,   247,   250,   253,   259, | ||||||
|    256,   265,   271,   283,   286,   289,   295,   299,   303,   309, |    265,   274,   280,   292,   295,   298,   304,   308,   312,   318, | ||||||
|    313,   331,   337,   343,   347,   352,   356,   363,   371,   374, |    322,   340,   346,   352,   356,   361,   365,   372,   380,   383, | ||||||
|    377,   380,   383,   386,   389,   392,   395,   398,   401,   404, |    386,   389,   392,   395,   398,   401,   404,   407,   410,   413, | ||||||
|    407,   410,   413,   416,   419,   422,   425,   430,   463,   467 |    416,   419,   422,   425,   428,   431,   434,   439,   473,   477 | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -390,6 +394,8 @@ static const short yycheck[] = {     0, | |||||||
|     11,    15,    13,    14,    16,    19,    17,    16,    21,     0, |     11,    15,    13,    14,    16,    19,    17,    16,    21,     0, | ||||||
|     56 |     56 | ||||||
| }; | }; | ||||||
|  | #define YYPURE 1 | ||||||
|  |  | ||||||
| /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */ | /* -*-C-*-  Note some compilers choke on comments on `#line' lines.  */ | ||||||
| #line 3 "/usr/local/share/bison.simple" | #line 3 "/usr/local/share/bison.simple" | ||||||
| /* This file comes from bison-1.28.  */ | /* This file comes from bison-1.28.  */ | ||||||
| @@ -934,135 +940,135 @@ yyreduce: | |||||||
|   switch (yyn) { |   switch (yyn) { | ||||||
|  |  | ||||||
| case 3: | case 3: | ||||||
| #line 226 "getdate.y" | #line 235 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveTime++; | 	    context->yyHaveTime++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 4: | case 4: | ||||||
| #line 229 "getdate.y" | #line 238 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 5: | case 5: | ||||||
| #line 232 "getdate.y" | #line 241 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveDate++; | 	    context->yyHaveDate++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 6: | case 6: | ||||||
| #line 235 "getdate.y" | #line 244 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveDay++; | 	    context->yyHaveDay++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 7: | case 7: | ||||||
| #line 238 "getdate.y" | #line 247 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveRel++; | 	    context->yyHaveRel++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 9: | case 9: | ||||||
| #line 244 "getdate.y" | #line 253 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHour = yyvsp[-1].Number; | 	    context->yyHour = yyvsp[-1].Number; | ||||||
| 	    yyMinutes = 0; | 	    context->yyMinutes = 0; | ||||||
| 	    yySeconds = 0; | 	    context->yySeconds = 0; | ||||||
| 	    yyMeridian = yyvsp[0].Meridian; | 	    context->yyMeridian = yyvsp[0].Meridian; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 10: | case 10: | ||||||
| #line 250 "getdate.y" | #line 259 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHour = yyvsp[-3].Number; | 	    context->yyHour = yyvsp[-3].Number; | ||||||
| 	    yyMinutes = yyvsp[-1].Number; | 	    context->yyMinutes = yyvsp[-1].Number; | ||||||
| 	    yySeconds = 0; | 	    context->yySeconds = 0; | ||||||
| 	    yyMeridian = yyvsp[0].Meridian; | 	    context->yyMeridian = yyvsp[0].Meridian; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 11: | case 11: | ||||||
| #line 256 "getdate.y" | #line 265 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHour = yyvsp[-3].Number; | 	    context->yyHour = yyvsp[-3].Number; | ||||||
| 	    yyMinutes = yyvsp[-1].Number; | 	    context->yyMinutes = yyvsp[-1].Number; | ||||||
| 	    yyMeridian = MER24; | 	    context->yyMeridian = MER24; | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	    yyTimezone = (yyvsp[0].Number < 0 | 	    context->yyTimezone = (yyvsp[0].Number < 0 | ||||||
| 				   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 | 				   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 | ||||||
| 				   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); | 				   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 12: | case 12: | ||||||
| #line 265 "getdate.y" | #line 274 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHour = yyvsp[-5].Number; | 	    context->yyHour = yyvsp[-5].Number; | ||||||
| 	    yyMinutes = yyvsp[-3].Number; | 	    context->yyMinutes = yyvsp[-3].Number; | ||||||
| 	    yySeconds = yyvsp[-1].Number; | 	    context->yySeconds = yyvsp[-1].Number; | ||||||
| 	    yyMeridian = yyvsp[0].Meridian; | 	    context->yyMeridian = yyvsp[0].Meridian; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 13: | case 13: | ||||||
| #line 271 "getdate.y" | #line 280 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHour = yyvsp[-5].Number; | 	    context->yyHour = yyvsp[-5].Number; | ||||||
| 	    yyMinutes = yyvsp[-3].Number; | 	    context->yyMinutes = yyvsp[-3].Number; | ||||||
| 	    yySeconds = yyvsp[-1].Number; | 	    context->yySeconds = yyvsp[-1].Number; | ||||||
| 	    yyMeridian = MER24; | 	    context->yyMeridian = MER24; | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	    yyTimezone = (yyvsp[0].Number < 0 | 	    context->yyTimezone = (yyvsp[0].Number < 0 | ||||||
| 				   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 | 				   ? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60 | ||||||
| 				   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); | 				   : - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60)); | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 14: | case 14: | ||||||
| #line 283 "getdate.y" | #line 292 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[0].Number; | 	    context->yyTimezone = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 15: | case 15: | ||||||
| #line 286 "getdate.y" | #line 295 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[0].Number - 60; | 	    context->yyTimezone = yyvsp[0].Number - 60; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 16: | case 16: | ||||||
| #line 290 "getdate.y" | #line 299 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[-1].Number - 60; | 	    context->yyTimezone = yyvsp[-1].Number - 60; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 17: | case 17: | ||||||
| #line 295 "getdate.y" | #line 304 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyDayOrdinal = 1; | 	    context->yyDayOrdinal = 1; | ||||||
| 	    yyDayNumber = yyvsp[0].Number; | 	    context->yyDayNumber = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 18: | case 18: | ||||||
| #line 299 "getdate.y" | #line 308 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyDayOrdinal = 1; | 	    context->yyDayOrdinal = 1; | ||||||
| 	    yyDayNumber = yyvsp[-1].Number; | 	    context->yyDayNumber = yyvsp[-1].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 19: | case 19: | ||||||
| #line 303 "getdate.y" | #line 312 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyDayOrdinal = yyvsp[-1].Number; | 	    context->yyDayOrdinal = yyvsp[-1].Number; | ||||||
| 	    yyDayNumber = yyvsp[0].Number; | 	    context->yyDayNumber = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 20: | case 20: | ||||||
| #line 309 "getdate.y" | #line 318 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyMonth = yyvsp[-2].Number; | 	    context->yyMonth = yyvsp[-2].Number; | ||||||
| 	    yyDay = yyvsp[0].Number; | 	    context->yyDay = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 21: | case 21: | ||||||
| #line 313 "getdate.y" | #line 322 "getdate.y" | ||||||
| { | { | ||||||
| 	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. | 	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. | ||||||
| 	     The goal in recognizing YYYY/MM/DD is solely to support legacy | 	     The goal in recognizing YYYY/MM/DD is solely to support legacy | ||||||
| @@ -1070,226 +1076,227 @@ case 21: | |||||||
| 	     you want portability, use the ISO 8601 format.  */ | 	     you want portability, use the ISO 8601 format.  */ | ||||||
| 	  if (yyvsp[-4].Number >= 1000) | 	  if (yyvsp[-4].Number >= 1000) | ||||||
| 	    { | 	    { | ||||||
| 	      yyYear = yyvsp[-4].Number; | 	      context->yyYear = yyvsp[-4].Number; | ||||||
| 	      yyMonth = yyvsp[-2].Number; | 	      context->yyMonth = yyvsp[-2].Number; | ||||||
| 	      yyDay = yyvsp[0].Number; | 	      context->yyDay = yyvsp[0].Number; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    { | 	    { | ||||||
| 	      yyMonth = yyvsp[-4].Number; | 	      context->yyMonth = yyvsp[-4].Number; | ||||||
| 	      yyDay = yyvsp[-2].Number; | 	      context->yyDay = yyvsp[-2].Number; | ||||||
| 	      yyYear = yyvsp[0].Number; | 	      context->yyYear = yyvsp[0].Number; | ||||||
| 	    } | 	    } | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 22: | case 22: | ||||||
| #line 331 "getdate.y" | #line 340 "getdate.y" | ||||||
| { | { | ||||||
| 	    /* ISO 8601 format.  yyyy-mm-dd.  */ | 	    /* ISO 8601 format.  yyyy-mm-dd.  */ | ||||||
| 	    yyYear = yyvsp[-2].Number; | 	    context->yyYear = yyvsp[-2].Number; | ||||||
| 	    yyMonth = -yyvsp[-1].Number; | 	    context->yyMonth = -yyvsp[-1].Number; | ||||||
| 	    yyDay = -yyvsp[0].Number; | 	    context->yyDay = -yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 23: | case 23: | ||||||
| #line 337 "getdate.y" | #line 346 "getdate.y" | ||||||
| { | { | ||||||
| 	    /* e.g. 17-JUN-1992.  */ | 	    /* e.g. 17-JUN-1992.  */ | ||||||
| 	    yyDay = yyvsp[-2].Number; | 	    context->yyDay = yyvsp[-2].Number; | ||||||
| 	    yyMonth = yyvsp[-1].Number; | 	    context->yyMonth = yyvsp[-1].Number; | ||||||
| 	    yyYear = -yyvsp[0].Number; | 	    context->yyYear = -yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 24: | case 24: | ||||||
| #line 343 "getdate.y" | #line 352 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyMonth = yyvsp[-1].Number; | 	    context->yyMonth = yyvsp[-1].Number; | ||||||
| 	    yyDay = yyvsp[0].Number; | 	    context->yyDay = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 25: | case 25: | ||||||
| #line 347 "getdate.y" | #line 356 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyMonth = yyvsp[-3].Number; | 	    context->yyMonth = yyvsp[-3].Number; | ||||||
| 	    yyDay = yyvsp[-2].Number; | 	    context->yyDay = yyvsp[-2].Number; | ||||||
| 	    yyYear = yyvsp[0].Number; | 	    context->yyYear = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 26: | case 26: | ||||||
| #line 352 "getdate.y" | #line 361 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyMonth = yyvsp[0].Number; | 	    context->yyMonth = yyvsp[0].Number; | ||||||
| 	    yyDay = yyvsp[-1].Number; | 	    context->yyDay = yyvsp[-1].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 27: | case 27: | ||||||
| #line 356 "getdate.y" | #line 365 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyMonth = yyvsp[-1].Number; | 	    context->yyMonth = yyvsp[-1].Number; | ||||||
| 	    yyDay = yyvsp[-2].Number; | 	    context->yyDay = yyvsp[-2].Number; | ||||||
| 	    yyYear = yyvsp[0].Number; | 	    context->yyYear = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 28: | case 28: | ||||||
| #line 363 "getdate.y" | #line 372 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelSeconds = -yyRelSeconds; | 	    context->yyRelSeconds = -context->yyRelSeconds; | ||||||
| 	    yyRelMinutes = -yyRelMinutes; | 	    context->yyRelMinutes = -context->yyRelMinutes; | ||||||
| 	    yyRelHour = -yyRelHour; | 	    context->yyRelHour = -context->yyRelHour; | ||||||
| 	    yyRelDay = -yyRelDay; | 	    context->yyRelDay = -context->yyRelDay; | ||||||
| 	    yyRelMonth = -yyRelMonth; | 	    context->yyRelMonth = -context->yyRelMonth; | ||||||
| 	    yyRelYear = -yyRelYear; | 	    context->yyRelYear = -context->yyRelYear; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 30: | case 30: | ||||||
| #line 374 "getdate.y" | #line 383 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 31: | case 31: | ||||||
| #line 377 "getdate.y" | #line 386 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 32: | case 32: | ||||||
| #line 380 "getdate.y" | #line 389 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelYear += yyvsp[0].Number; | 	    context->yyRelYear += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 33: | case 33: | ||||||
| #line 383 "getdate.y" | #line 392 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 34: | case 34: | ||||||
| #line 386 "getdate.y" | #line 395 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 35: | case 35: | ||||||
| #line 389 "getdate.y" | #line 398 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMonth += yyvsp[0].Number; | 	    context->yyRelMonth += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 36: | case 36: | ||||||
| #line 392 "getdate.y" | #line 401 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 37: | case 37: | ||||||
| #line 395 "getdate.y" | #line 404 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 38: | case 38: | ||||||
| #line 398 "getdate.y" | #line 407 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelDay += yyvsp[0].Number; | 	    context->yyRelDay += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 39: | case 39: | ||||||
| #line 401 "getdate.y" | #line 410 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 40: | case 40: | ||||||
| #line 404 "getdate.y" | #line 413 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 41: | case 41: | ||||||
| #line 407 "getdate.y" | #line 416 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelHour += yyvsp[0].Number; | 	    context->yyRelHour += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 42: | case 42: | ||||||
| #line 410 "getdate.y" | #line 419 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 43: | case 43: | ||||||
| #line 413 "getdate.y" | #line 422 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 44: | case 44: | ||||||
| #line 416 "getdate.y" | #line 425 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMinutes += yyvsp[0].Number; | 	    context->yyRelMinutes += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 45: | case 45: | ||||||
| #line 419 "getdate.y" | #line 428 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 46: | case 46: | ||||||
| #line 422 "getdate.y" | #line 431 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; | 	    context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 47: | case 47: | ||||||
| #line 425 "getdate.y" | #line 434 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelSeconds += yyvsp[0].Number; | 	    context->yyRelSeconds += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 48: | case 48: | ||||||
| #line 431 "getdate.y" | #line 440 "getdate.y" | ||||||
| { | { | ||||||
| 	    if (yyHaveTime && yyHaveDate && !yyHaveRel) | 	    if (context->yyHaveTime && context->yyHaveDate && | ||||||
| 	      yyYear = yyvsp[0].Number; | 		!context->yyHaveRel) | ||||||
|  | 	      context->yyYear = yyvsp[0].Number; | ||||||
| 	    else | 	    else | ||||||
| 	      { | 	      { | ||||||
| 		if (yyvsp[0].Number>10000) | 		if (yyvsp[0].Number>10000) | ||||||
| 		  { | 		  { | ||||||
| 		    yyHaveDate++; | 		    context->yyHaveDate++; | ||||||
| 		    yyDay= (yyvsp[0].Number)%100; | 		    context->yyDay= (yyvsp[0].Number)%100; | ||||||
| 		    yyMonth= (yyvsp[0].Number/100)%100; | 		    context->yyMonth= (yyvsp[0].Number/100)%100; | ||||||
| 		    yyYear = yyvsp[0].Number/10000; | 		    context->yyYear = yyvsp[0].Number/10000; | ||||||
| 		  } | 		  } | ||||||
| 		else | 		else | ||||||
| 		  { | 		  { | ||||||
| 		    yyHaveTime++; | 		    context->yyHaveTime++; | ||||||
| 		    if (yyvsp[0].Number < 100) | 		    if (yyvsp[0].Number < 100) | ||||||
| 		      { | 		      { | ||||||
| 			yyHour = yyvsp[0].Number; | 			context->yyHour = yyvsp[0].Number; | ||||||
| 			yyMinutes = 0; | 			context->yyMinutes = 0; | ||||||
| 		      } | 		      } | ||||||
| 		    else | 		    else | ||||||
| 		      { | 		      { | ||||||
| 		    	yyHour = yyvsp[0].Number / 100; | 		    	context->yyHour = yyvsp[0].Number / 100; | ||||||
| 		    	yyMinutes = yyvsp[0].Number % 100; | 		    	context->yyMinutes = yyvsp[0].Number % 100; | ||||||
| 		      } | 		      } | ||||||
| 		    yySeconds = 0; | 		    context->yySeconds = 0; | ||||||
| 		    yyMeridian = MER24; | 		    context->yyMeridian = MER24; | ||||||
| 		  } | 		  } | ||||||
| 	      } | 	      } | ||||||
| 	  ; | 	  ; | ||||||
|     break;} |     break;} | ||||||
| case 49: | case 49: | ||||||
| #line 464 "getdate.y" | #line 474 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyval.Meridian = MER24; | 	    yyval.Meridian = MER24; | ||||||
| 	  ; | 	  ; | ||||||
|     break;} |     break;} | ||||||
| case 50: | case 50: | ||||||
| #line 468 "getdate.y" | #line 478 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyval.Meridian = yyvsp[0].Meridian; | 	    yyval.Meridian = yyvsp[0].Meridian; | ||||||
| 	  ; | 	  ; | ||||||
| @@ -1516,7 +1523,7 @@ yyerrhandle: | |||||||
|     } |     } | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
| #line 473 "getdate.y" | #line 483 "getdate.y" | ||||||
|  |  | ||||||
|  |  | ||||||
| /* Include this file down here because bison inserts code above which | /* Include this file down here because bison inserts code above which | ||||||
| @@ -1772,7 +1779,8 @@ ToYear (Year) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| LookupWord (buff) | LookupWord (yylval, buff) | ||||||
|  |      YYSTYPE *yylval; | ||||||
|      char *buff; |      char *buff; | ||||||
| { | { | ||||||
|   register char *p; |   register char *p; | ||||||
| @@ -1788,12 +1796,12 @@ LookupWord (buff) | |||||||
|  |  | ||||||
|   if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) |   if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) | ||||||
|     { |     { | ||||||
|       yylval.Meridian = MERam; |       yylval->Meridian = MERam; | ||||||
|       return tMERIDIAN; |       return tMERIDIAN; | ||||||
|     } |     } | ||||||
|   if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) |   if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) | ||||||
|     { |     { | ||||||
|       yylval.Meridian = MERpm; |       yylval->Meridian = MERpm; | ||||||
|       return tMERIDIAN; |       return tMERIDIAN; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1814,13 +1822,13 @@ LookupWord (buff) | |||||||
| 	{ | 	{ | ||||||
| 	  if (strncmp (buff, tp->name, 3) == 0) | 	  if (strncmp (buff, tp->name, 3) == 0) | ||||||
| 	    { | 	    { | ||||||
| 	      yylval.Number = tp->value; | 	      yylval->Number = tp->value; | ||||||
| 	      return tp->type; | 	      return tp->type; | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
|       else if (strcmp (buff, tp->name) == 0) |       else if (strcmp (buff, tp->name) == 0) | ||||||
| 	{ | 	{ | ||||||
| 	  yylval.Number = tp->value; | 	  yylval->Number = tp->value; | ||||||
| 	  return tp->type; | 	  return tp->type; | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| @@ -1828,7 +1836,7 @@ LookupWord (buff) | |||||||
|   for (tp = TimezoneTable; tp->name; tp++) |   for (tp = TimezoneTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1838,7 +1846,7 @@ LookupWord (buff) | |||||||
|   for (tp = UnitsTable; tp->name; tp++) |   for (tp = UnitsTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1850,7 +1858,7 @@ LookupWord (buff) | |||||||
|       for (tp = UnitsTable; tp->name; tp++) |       for (tp = UnitsTable; tp->name; tp++) | ||||||
| 	if (strcmp (buff, tp->name) == 0) | 	if (strcmp (buff, tp->name) == 0) | ||||||
| 	  { | 	  { | ||||||
| 	    yylval.Number = tp->value; | 	    yylval->Number = tp->value; | ||||||
| 	    return tp->type; | 	    return tp->type; | ||||||
| 	  } | 	  } | ||||||
|       buff[i] = 's';		/* Put back for "this" in OtherTable. */ |       buff[i] = 's';		/* Put back for "this" in OtherTable. */ | ||||||
| @@ -1859,7 +1867,7 @@ LookupWord (buff) | |||||||
|   for (tp = OtherTable; tp->name; tp++) |   for (tp = OtherTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1869,7 +1877,7 @@ LookupWord (buff) | |||||||
|       for (tp = MilitaryTable; tp->name; tp++) |       for (tp = MilitaryTable; tp->name; tp++) | ||||||
| 	if (strcmp (buff, tp->name) == 0) | 	if (strcmp (buff, tp->name) == 0) | ||||||
| 	  { | 	  { | ||||||
| 	    yylval.Number = tp->value; | 	    yylval->Number = tp->value; | ||||||
| 	    return tp->type; | 	    return tp->type; | ||||||
| 	  } | 	  } | ||||||
|     } |     } | ||||||
| @@ -1885,7 +1893,7 @@ LookupWord (buff) | |||||||
|     for (tp = TimezoneTable; tp->name; tp++) |     for (tp = TimezoneTable; tp->name; tp++) | ||||||
|       if (strcmp (buff, tp->name) == 0) |       if (strcmp (buff, tp->name) == 0) | ||||||
| 	{ | 	{ | ||||||
| 	  yylval.Number = tp->value; | 	  yylval->Number = tp->value; | ||||||
| 	  return tp->type; | 	  return tp->type; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1893,7 +1901,9 @@ LookupWord (buff) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| yylex () | yylex (yylval, cookie) | ||||||
|  |      YYSTYPE *yylval; | ||||||
|  |      void *cookie; | ||||||
| { | { | ||||||
|   register unsigned char c; |   register unsigned char c; | ||||||
|   register char *p; |   register char *p; | ||||||
| @@ -1903,42 +1913,42 @@ yylex () | |||||||
|  |  | ||||||
|   for (;;) |   for (;;) | ||||||
|     { |     { | ||||||
|       while (ISSPACE ((unsigned char) *yyInput)) |       while (ISSPACE ((unsigned char) *context->yyInput)) | ||||||
| 	yyInput++; | 	context->yyInput++; | ||||||
|  |  | ||||||
|       if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') |       if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+') | ||||||
| 	{ | 	{ | ||||||
| 	  if (c == '-' || c == '+') | 	  if (c == '-' || c == '+') | ||||||
| 	    { | 	    { | ||||||
| 	      sign = c == '-' ? -1 : 1; | 	      sign = c == '-' ? -1 : 1; | ||||||
| 	      if (!ISDIGIT (*++yyInput)) | 	      if (!ISDIGIT (*++context->yyInput)) | ||||||
| 		/* skip the '-' sign */ | 		/* skip the '-' sign */ | ||||||
| 		continue; | 		continue; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    sign = 0; | 	    sign = 0; | ||||||
| 	  for (yylval.Number = 0; ISDIGIT (c = *yyInput++);) | 	  for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);) | ||||||
| 	    yylval.Number = 10 * yylval.Number + c - '0'; | 	    yylval->Number = 10 * yylval->Number + c - '0'; | ||||||
| 	  yyInput--; | 	  context->yyInput--; | ||||||
| 	  if (sign < 0) | 	  if (sign < 0) | ||||||
| 	    yylval.Number = -yylval.Number; | 	    yylval->Number = -yylval->Number; | ||||||
| 	  return sign ? tSNUMBER : tUNUMBER; | 	  return sign ? tSNUMBER : tUNUMBER; | ||||||
| 	} | 	} | ||||||
|       if (ISALPHA (c)) |       if (ISALPHA (c)) | ||||||
| 	{ | 	{ | ||||||
| 	  for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';) | 	  for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';) | ||||||
| 	    if (p < &buff[sizeof buff - 1]) | 	    if (p < &buff[sizeof buff - 1]) | ||||||
| 	      *p++ = c; | 	      *p++ = c; | ||||||
| 	  *p = '\0'; | 	  *p = '\0'; | ||||||
| 	  yyInput--; | 	  context->yyInput--; | ||||||
| 	  return LookupWord (buff); | 	  return LookupWord (yylval, buff); | ||||||
| 	} | 	} | ||||||
|       if (c != '(') |       if (c != '(') | ||||||
| 	return *yyInput++; | 	return *context->yyInput++; | ||||||
|       Count = 0; |       Count = 0; | ||||||
|       do |       do | ||||||
| 	{ | 	{ | ||||||
| 	  c = *yyInput++; | 	  c = *context->yyInput++; | ||||||
| 	  if (c == '\0') | 	  if (c == '\0') | ||||||
| 	    return c; | 	    return c; | ||||||
| 	  if (c == '(') | 	  if (c == '(') | ||||||
| @@ -1978,10 +1988,11 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| { | { | ||||||
|   struct tm tm, tm0, *tmp; |   struct tm tm, tm0, *tmp; | ||||||
|   time_t Start; |   time_t Start; | ||||||
|  |   CONTEXT cookie; | ||||||
| #ifdef HAVE_LOCALTIME_R | #ifdef HAVE_LOCALTIME_R | ||||||
|   struct tm keeptime; |   struct tm keeptime; | ||||||
| #endif | #endif | ||||||
|   yyInput = p; |   cookie.yyInput = p; | ||||||
|   Start = now ? *now : time ((time_t *) NULL); |   Start = now ? *now : time ((time_t *) NULL); | ||||||
| #ifdef HAVE_LOCALTIME_R | #ifdef HAVE_LOCALTIME_R | ||||||
|   tmp = (struct tm *)localtime_r(&Start, &keeptime); |   tmp = (struct tm *)localtime_r(&Start, &keeptime); | ||||||
| @@ -1990,52 +2001,55 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| #endif | #endif | ||||||
|   if (!tmp) |   if (!tmp) | ||||||
|     return -1; |     return -1; | ||||||
|   yyYear = tmp->tm_year + TM_YEAR_ORIGIN; |   cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN; | ||||||
|   yyMonth = tmp->tm_mon + 1; |   cookie.yyMonth = tmp->tm_mon + 1; | ||||||
|   yyDay = tmp->tm_mday; |   cookie.yyDay = tmp->tm_mday; | ||||||
|   yyHour = tmp->tm_hour; |   cookie.yyHour = tmp->tm_hour; | ||||||
|   yyMinutes = tmp->tm_min; |   cookie.yyMinutes = tmp->tm_min; | ||||||
|   yySeconds = tmp->tm_sec; |   cookie.yySeconds = tmp->tm_sec; | ||||||
|   tm.tm_isdst = tmp->tm_isdst; |   tm.tm_isdst = tmp->tm_isdst; | ||||||
|   yyMeridian = MER24; |   cookie.yyMeridian = MER24; | ||||||
|   yyRelSeconds = 0; |   cookie.yyRelSeconds = 0; | ||||||
|   yyRelMinutes = 0; |   cookie.yyRelMinutes = 0; | ||||||
|   yyRelHour = 0; |   cookie.yyRelHour = 0; | ||||||
|   yyRelDay = 0; |   cookie.yyRelDay = 0; | ||||||
|   yyRelMonth = 0; |   cookie.yyRelMonth = 0; | ||||||
|   yyRelYear = 0; |   cookie.yyRelYear = 0; | ||||||
|   yyHaveDate = 0; |   cookie.yyHaveDate = 0; | ||||||
|   yyHaveDay = 0; |   cookie.yyHaveDay = 0; | ||||||
|   yyHaveRel = 0; |   cookie.yyHaveRel = 0; | ||||||
|   yyHaveTime = 0; |   cookie.yyHaveTime = 0; | ||||||
|   yyHaveZone = 0; |   cookie.yyHaveZone = 0; | ||||||
|  |  | ||||||
|   if (yyparse () |   if (yyparse (&cookie) | ||||||
|       || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) |       || cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 || | ||||||
|  |       cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1) | ||||||
|     return -1; |     return -1; | ||||||
|  |  | ||||||
|   tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear; |   tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear; | ||||||
|   tm.tm_mon = yyMonth - 1 + yyRelMonth; |   tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth; | ||||||
|   tm.tm_mday = yyDay + yyRelDay; |   tm.tm_mday = cookie.yyDay + cookie.yyRelDay; | ||||||
|   if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay)) |   if (cookie.yyHaveTime || | ||||||
|  |       (cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay)) | ||||||
|     { |     { | ||||||
|       tm.tm_hour = ToHour (yyHour, yyMeridian); |       tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian); | ||||||
|       if (tm.tm_hour < 0) |       if (tm.tm_hour < 0) | ||||||
| 	return -1; | 	return -1; | ||||||
|       tm.tm_min = yyMinutes; |       tm.tm_min = cookie.yyMinutes; | ||||||
|       tm.tm_sec = yySeconds; |       tm.tm_sec = cookie.yySeconds; | ||||||
|     } |     } | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
|       tm.tm_hour = tm.tm_min = tm.tm_sec = 0; |       tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | ||||||
|     } |     } | ||||||
|   tm.tm_hour += yyRelHour; |   tm.tm_hour += cookie.yyRelHour; | ||||||
|   tm.tm_min += yyRelMinutes; |   tm.tm_min += cookie.yyRelMinutes; | ||||||
|   tm.tm_sec += yyRelSeconds; |   tm.tm_sec += cookie.yyRelSeconds; | ||||||
|  |  | ||||||
|   /* Let mktime deduce tm_isdst if we have an absolute timestamp, |   /* Let mktime deduce tm_isdst if we have an absolute timestamp, | ||||||
|      or if the relative timestamp mentions days, months, or years.  */ |      or if the relative timestamp mentions days, months, or years.  */ | ||||||
|   if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear) |   if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime | | ||||||
|  |       cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear) | ||||||
|     tm.tm_isdst = -1; |     tm.tm_isdst = -1; | ||||||
|  |  | ||||||
|   tm0 = tm; |   tm0 = tm; | ||||||
| @@ -2053,18 +2067,18 @@ curl_getdate (const char *p, const time_t *now) | |||||||
|          we apply mktime to 1970-01-02 08:00:00 instead and adjust the time |          we apply mktime to 1970-01-02 08:00:00 instead and adjust the time | ||||||
|          zone by 24 hours to compensate.  This algorithm assumes that |          zone by 24 hours to compensate.  This algorithm assumes that | ||||||
|          there is no DST transition within a day of the time_t boundaries.  */ |          there is no DST transition within a day of the time_t boundaries.  */ | ||||||
|       if (yyHaveZone) |       if (cookie.yyHaveZone) | ||||||
| 	{ | 	{ | ||||||
| 	  tm = tm0; | 	  tm = tm0; | ||||||
| 	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) | 	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) | ||||||
| 	    { | 	    { | ||||||
| 	      tm.tm_mday++; | 	      tm.tm_mday++; | ||||||
| 	      yyTimezone -= 24 * 60; | 	      cookie.yyTimezone -= 24 * 60; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    { | 	    { | ||||||
| 	      tm.tm_mday--; | 	      tm.tm_mday--; | ||||||
| 	      yyTimezone += 24 * 60; | 	      cookie.yyTimezone += 24 * 60; | ||||||
| 	    } | 	    } | ||||||
| 	  Start = mktime (&tm); | 	  Start = mktime (&tm); | ||||||
| 	} | 	} | ||||||
| @@ -2073,22 +2087,29 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| 	return Start; | 	return Start; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (yyHaveDay && !yyHaveDate) |   if (cookie.yyHaveDay && !cookie.yyHaveDate) | ||||||
|     { |     { | ||||||
|       tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7 |       tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7 | ||||||
| 		     + 7 * (yyDayOrdinal - (0 < yyDayOrdinal))); | 		     + 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal))); | ||||||
|       Start = mktime (&tm); |       Start = mktime (&tm); | ||||||
|       if (Start == (time_t) -1) |       if (Start == (time_t) -1) | ||||||
| 	return Start; | 	return Start; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (yyHaveZone) |   if (cookie.yyHaveZone) | ||||||
|     { |     { | ||||||
|       long delta; |       long delta; | ||||||
|       struct tm *gmt = gmtime (&Start); |       struct tm *gmt; | ||||||
|  | #ifdef HAVE_GMTIME_R | ||||||
|  |       /* thread-safe version */ | ||||||
|  |       struct tm keeptime; | ||||||
|  |       gmt = (struct tm *)gmtime_r(&Start, &keeptime); | ||||||
|  | #else | ||||||
|  |       gmt = gmtime(&Start); | ||||||
|  | #endif | ||||||
|       if (!gmt) |       if (!gmt) | ||||||
| 	return -1; | 	return -1; | ||||||
|       delta = yyTimezone * 60L + difftm (&tm, gmt); |       delta = cookie.yyTimezone * 60L + difftm (&tm, gmt); | ||||||
|       if ((Start + delta < Start) != (delta < 0)) |       if ((Start + delta < Start) != (delta < 0)) | ||||||
| 	return -1;		/* time_t overflow */ | 	return -1;		/* time_t overflow */ | ||||||
|       Start += delta; |       Start += delta; | ||||||
| @@ -2126,11 +2147,3 @@ main (ac, av) | |||||||
|   /* NOTREACHED */ |   /* NOTREACHED */ | ||||||
| } | } | ||||||
| #endif /* defined (TEST) */ | #endif /* defined (TEST) */ | ||||||
|  |  | ||||||
| /* |  | ||||||
|  * local variables: |  | ||||||
|  * eval: (load-file "../curl-mode.el") |  | ||||||
|  * end: |  | ||||||
|  * vim600: fdm=marker |  | ||||||
|  * vim: et sw=2 ts=2 sts=2 tw=78 |  | ||||||
|  */ |  | ||||||
|   | |||||||
| @@ -7,9 +7,7 @@ | |||||||
| **  This code is in the public domain and has no copyright. | **  This code is in the public domain and has no copyright. | ||||||
| */ | */ | ||||||
|  |  | ||||||
| #if HAVE_CONFIG_H | # include "setup.h" | ||||||
| # include <config.h> |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef PARAMS | #ifndef PARAMS | ||||||
| # if defined PROTOTYPES || (defined __STDC__ && __STDC__) | # if defined PROTOTYPES || (defined __STDC__ && __STDC__) | ||||||
|   | |||||||
							
								
								
									
										412
									
								
								lib/getdate.y
									
									
									
									
									
								
							
							
						
						
									
										412
									
								
								lib/getdate.y
									
									
									
									
									
								
							| @@ -10,8 +10,6 @@ | |||||||
|  |  | ||||||
| #include "setup.h" | #include "setup.h" | ||||||
|  |  | ||||||
| #ifdef HAVE_CONFIG_H |  | ||||||
| # include "config.h" |  | ||||||
| # ifdef HAVE_ALLOCA_H | # ifdef HAVE_ALLOCA_H | ||||||
| #  include <alloca.h> | #  include <alloca.h> | ||||||
| # endif | # endif | ||||||
| @@ -19,6 +17,10 @@ | |||||||
| # ifdef HAVE_TIME_H | # ifdef HAVE_TIME_H | ||||||
| #  include <time.h> | #  include <time.h> | ||||||
| # endif | # endif | ||||||
|  |  | ||||||
|  | #ifndef YYDEBUG | ||||||
|  |   /* to satisfy gcc -Wundef, we set this to 0 */ | ||||||
|  | #define YYDEBUG 0 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* Since the code of getdate.y is not included in the Emacs executable | /* Since the code of getdate.y is not included in the Emacs executable | ||||||
| @@ -168,41 +170,48 @@ typedef enum _MERIDIAN { | |||||||
|     MERam, MERpm, MER24 |     MERam, MERpm, MER24 | ||||||
| } MERIDIAN; | } MERIDIAN; | ||||||
|  |  | ||||||
|  | /* parse results and input string */ | ||||||
|  | typedef struct _CONTEXT { | ||||||
|  |     const char	*yyInput; | ||||||
|  |     int		yyDayOrdinal; | ||||||
|  |     int		yyDayNumber; | ||||||
|  |     int		yyHaveDate; | ||||||
|  |     int		yyHaveDay; | ||||||
|  |     int		yyHaveRel; | ||||||
|  |     int		yyHaveTime; | ||||||
|  |     int		yyHaveZone; | ||||||
|  |     int		yyTimezone; | ||||||
|  |     int		yyDay; | ||||||
|  |     int		yyHour; | ||||||
|  |     int		yyMinutes; | ||||||
|  |     int		yyMonth; | ||||||
|  |     int		yySeconds; | ||||||
|  |     int		yyYear; | ||||||
|  |     MERIDIAN	yyMeridian; | ||||||
|  |     int		yyRelDay; | ||||||
|  |     int		yyRelHour; | ||||||
|  |     int		yyRelMinutes; | ||||||
|  |     int		yyRelMonth; | ||||||
|  |     int		yyRelSeconds; | ||||||
|  |     int		yyRelYear; | ||||||
|  | } CONTEXT; | ||||||
|  |  | ||||||
| /* | /* enable use of extra argument to yyparse and yylex which can be used to pass | ||||||
| **  Global variables.  We could get rid of most of these by using a good | **  in a user defined value (CONTEXT struct in our case) | ||||||
| **  union as the yacc stack.  (This routine was originally written before |  | ||||||
| **  yacc had the %union construct.)  Maybe someday; right now we only use |  | ||||||
| **  the %union very rarely. |  | ||||||
| */ | */ | ||||||
| static const char	*yyInput; | #define YYPARSE_PARAM cookie | ||||||
| static int	yyDayOrdinal; | #define YYLEX_PARAM cookie | ||||||
| static int	yyDayNumber; | #define context ((CONTEXT *) cookie) | ||||||
| static int	yyHaveDate; |  | ||||||
| static int	yyHaveDay; |  | ||||||
| static int	yyHaveRel; |  | ||||||
| static int	yyHaveTime; |  | ||||||
| static int	yyHaveZone; |  | ||||||
| static int	yyTimezone; |  | ||||||
| static int	yyDay; |  | ||||||
| static int	yyHour; |  | ||||||
| static int	yyMinutes; |  | ||||||
| static int	yyMonth; |  | ||||||
| static int	yySeconds; |  | ||||||
| static int	yyYear; |  | ||||||
| static MERIDIAN	yyMeridian; |  | ||||||
| static int	yyRelDay; |  | ||||||
| static int	yyRelHour; |  | ||||||
| static int	yyRelMinutes; |  | ||||||
| static int	yyRelMonth; |  | ||||||
| static int	yyRelSeconds; |  | ||||||
| static int	yyRelYear; |  | ||||||
|  |  | ||||||
| %} | %} | ||||||
|  |  | ||||||
| /* This grammar has 13 shift/reduce conflicts. */ | /* This grammar has 13 shift/reduce conflicts. */ | ||||||
| %expect 13 | %expect 13 | ||||||
|  |  | ||||||
|  | /* turn global variables into locals, additionally enable extra arguments | ||||||
|  | ** for yylex (pointer to yylval and user defined value) | ||||||
|  | */ | ||||||
|  | %pure_parser | ||||||
|  |  | ||||||
| %union { | %union { | ||||||
|     int			Number; |     int			Number; | ||||||
|     enum _MERIDIAN	Meridian; |     enum _MERIDIAN	Meridian; | ||||||
| @@ -224,91 +233,91 @@ spec	: /* NULL */ | |||||||
| 	; | 	; | ||||||
|  |  | ||||||
| item	: time { | item	: time { | ||||||
| 	    yyHaveTime++; | 	    context->yyHaveTime++; | ||||||
| 	} | 	} | ||||||
| 	| zone { | 	| zone { | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	} | 	} | ||||||
| 	| date { | 	| date { | ||||||
| 	    yyHaveDate++; | 	    context->yyHaveDate++; | ||||||
| 	} | 	} | ||||||
| 	| day { | 	| day { | ||||||
| 	    yyHaveDay++; | 	    context->yyHaveDay++; | ||||||
| 	} | 	} | ||||||
| 	| rel { | 	| rel { | ||||||
| 	    yyHaveRel++; | 	    context->yyHaveRel++; | ||||||
| 	} | 	} | ||||||
| 	| number | 	| number | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| time	: tUNUMBER tMERIDIAN { | time	: tUNUMBER tMERIDIAN { | ||||||
| 	    yyHour = $1; | 	    context->yyHour = $1; | ||||||
| 	    yyMinutes = 0; | 	    context->yyMinutes = 0; | ||||||
| 	    yySeconds = 0; | 	    context->yySeconds = 0; | ||||||
| 	    yyMeridian = $2; | 	    context->yyMeridian = $2; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER ':' tUNUMBER o_merid { | 	| tUNUMBER ':' tUNUMBER o_merid { | ||||||
| 	    yyHour = $1; | 	    context->yyHour = $1; | ||||||
| 	    yyMinutes = $3; | 	    context->yyMinutes = $3; | ||||||
| 	    yySeconds = 0; | 	    context->yySeconds = 0; | ||||||
| 	    yyMeridian = $4; | 	    context->yyMeridian = $4; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER ':' tUNUMBER tSNUMBER { | 	| tUNUMBER ':' tUNUMBER tSNUMBER { | ||||||
| 	    yyHour = $1; | 	    context->yyHour = $1; | ||||||
| 	    yyMinutes = $3; | 	    context->yyMinutes = $3; | ||||||
| 	    yyMeridian = MER24; | 	    context->yyMeridian = MER24; | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	    yyTimezone = ($4 < 0 | 	    context->yyTimezone = ($4 < 0 | ||||||
| 				   ? -$4 % 100 + (-$4 / 100) * 60 | 				   ? -$4 % 100 + (-$4 / 100) * 60 | ||||||
| 				   : - ($4 % 100 + ($4 / 100) * 60)); | 				   : - ($4 % 100 + ($4 / 100) * 60)); | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { | 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid { | ||||||
| 	    yyHour = $1; | 	    context->yyHour = $1; | ||||||
| 	    yyMinutes = $3; | 	    context->yyMinutes = $3; | ||||||
| 	    yySeconds = $5; | 	    context->yySeconds = $5; | ||||||
| 	    yyMeridian = $6; | 	    context->yyMeridian = $6; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { | 	| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER { | ||||||
| 	    yyHour = $1; | 	    context->yyHour = $1; | ||||||
| 	    yyMinutes = $3; | 	    context->yyMinutes = $3; | ||||||
| 	    yySeconds = $5; | 	    context->yySeconds = $5; | ||||||
| 	    yyMeridian = MER24; | 	    context->yyMeridian = MER24; | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	    yyTimezone = ($6 < 0 | 	    context->yyTimezone = ($6 < 0 | ||||||
| 				   ? -$6 % 100 + (-$6 / 100) * 60 | 				   ? -$6 % 100 + (-$6 / 100) * 60 | ||||||
| 				   : - ($6 % 100 + ($6 / 100) * 60)); | 				   : - ($6 % 100 + ($6 / 100) * 60)); | ||||||
| 	} | 	} | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| zone	: tZONE { | zone	: tZONE { | ||||||
| 	    yyTimezone = $1; | 	    context->yyTimezone = $1; | ||||||
| 	} | 	} | ||||||
| 	| tDAYZONE { | 	| tDAYZONE { | ||||||
| 	    yyTimezone = $1 - 60; | 	    context->yyTimezone = $1 - 60; | ||||||
| 	} | 	} | ||||||
| 	| | 	| | ||||||
| 	  tZONE tDST { | 	  tZONE tDST { | ||||||
| 	    yyTimezone = $1 - 60; | 	    context->yyTimezone = $1 - 60; | ||||||
| 	} | 	} | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| day	: tDAY { | day	: tDAY { | ||||||
| 	    yyDayOrdinal = 1; | 	    context->yyDayOrdinal = 1; | ||||||
| 	    yyDayNumber = $1; | 	    context->yyDayNumber = $1; | ||||||
| 	} | 	} | ||||||
| 	| tDAY ',' { | 	| tDAY ',' { | ||||||
| 	    yyDayOrdinal = 1; | 	    context->yyDayOrdinal = 1; | ||||||
| 	    yyDayNumber = $1; | 	    context->yyDayNumber = $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tDAY { | 	| tUNUMBER tDAY { | ||||||
| 	    yyDayOrdinal = $1; | 	    context->yyDayOrdinal = $1; | ||||||
| 	    yyDayNumber = $2; | 	    context->yyDayNumber = $2; | ||||||
| 	} | 	} | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| date	: tUNUMBER '/' tUNUMBER { | date	: tUNUMBER '/' tUNUMBER { | ||||||
| 	    yyMonth = $1; | 	    context->yyMonth = $1; | ||||||
| 	    yyDay = $3; | 	    context->yyDay = $3; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER '/' tUNUMBER '/' tUNUMBER { | 	| tUNUMBER '/' tUNUMBER '/' tUNUMBER { | ||||||
| 	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. | 	  /* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY. | ||||||
| @@ -317,144 +326,145 @@ date	: tUNUMBER '/' tUNUMBER { | |||||||
| 	     you want portability, use the ISO 8601 format.  */ | 	     you want portability, use the ISO 8601 format.  */ | ||||||
| 	  if ($1 >= 1000) | 	  if ($1 >= 1000) | ||||||
| 	    { | 	    { | ||||||
| 	      yyYear = $1; | 	      context->yyYear = $1; | ||||||
| 	      yyMonth = $3; | 	      context->yyMonth = $3; | ||||||
| 	      yyDay = $5; | 	      context->yyDay = $5; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    { | 	    { | ||||||
| 	      yyMonth = $1; | 	      context->yyMonth = $1; | ||||||
| 	      yyDay = $3; | 	      context->yyDay = $3; | ||||||
| 	      yyYear = $5; | 	      context->yyYear = $5; | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tSNUMBER tSNUMBER { | 	| tUNUMBER tSNUMBER tSNUMBER { | ||||||
| 	    /* ISO 8601 format.  yyyy-mm-dd.  */ | 	    /* ISO 8601 format.  yyyy-mm-dd.  */ | ||||||
| 	    yyYear = $1; | 	    context->yyYear = $1; | ||||||
| 	    yyMonth = -$2; | 	    context->yyMonth = -$2; | ||||||
| 	    yyDay = -$3; | 	    context->yyDay = -$3; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tMONTH tSNUMBER { | 	| tUNUMBER tMONTH tSNUMBER { | ||||||
| 	    /* e.g. 17-JUN-1992.  */ | 	    /* e.g. 17-JUN-1992.  */ | ||||||
| 	    yyDay = $1; | 	    context->yyDay = $1; | ||||||
| 	    yyMonth = $2; | 	    context->yyMonth = $2; | ||||||
| 	    yyYear = -$3; | 	    context->yyYear = -$3; | ||||||
| 	} | 	} | ||||||
| 	| tMONTH tUNUMBER { | 	| tMONTH tUNUMBER { | ||||||
| 	    yyMonth = $1; | 	    context->yyMonth = $1; | ||||||
| 	    yyDay = $2; | 	    context->yyDay = $2; | ||||||
| 	} | 	} | ||||||
| 	| tMONTH tUNUMBER ',' tUNUMBER { | 	| tMONTH tUNUMBER ',' tUNUMBER { | ||||||
| 	    yyMonth = $1; | 	    context->yyMonth = $1; | ||||||
| 	    yyDay = $2; | 	    context->yyDay = $2; | ||||||
| 	    yyYear = $4; | 	    context->yyYear = $4; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tMONTH { | 	| tUNUMBER tMONTH { | ||||||
| 	    yyMonth = $2; | 	    context->yyMonth = $2; | ||||||
| 	    yyDay = $1; | 	    context->yyDay = $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tMONTH tUNUMBER { | 	| tUNUMBER tMONTH tUNUMBER { | ||||||
| 	    yyMonth = $2; | 	    context->yyMonth = $2; | ||||||
| 	    yyDay = $1; | 	    context->yyDay = $1; | ||||||
| 	    yyYear = $3; | 	    context->yyYear = $3; | ||||||
| 	} | 	} | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| rel	: relunit tAGO { | rel	: relunit tAGO { | ||||||
| 	    yyRelSeconds = -yyRelSeconds; | 	    context->yyRelSeconds = -context->yyRelSeconds; | ||||||
| 	    yyRelMinutes = -yyRelMinutes; | 	    context->yyRelMinutes = -context->yyRelMinutes; | ||||||
| 	    yyRelHour = -yyRelHour; | 	    context->yyRelHour = -context->yyRelHour; | ||||||
| 	    yyRelDay = -yyRelDay; | 	    context->yyRelDay = -context->yyRelDay; | ||||||
| 	    yyRelMonth = -yyRelMonth; | 	    context->yyRelMonth = -context->yyRelMonth; | ||||||
| 	    yyRelYear = -yyRelYear; | 	    context->yyRelYear = -context->yyRelYear; | ||||||
| 	} | 	} | ||||||
| 	| relunit | 	| relunit | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| relunit	: tUNUMBER tYEAR_UNIT { | relunit	: tUNUMBER tYEAR_UNIT { | ||||||
| 	    yyRelYear += $1 * $2; | 	    context->yyRelYear += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tYEAR_UNIT { | 	| tSNUMBER tYEAR_UNIT { | ||||||
| 	    yyRelYear += $1 * $2; | 	    context->yyRelYear += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tYEAR_UNIT { | 	| tYEAR_UNIT { | ||||||
| 	    yyRelYear += $1; | 	    context->yyRelYear += $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tMONTH_UNIT { | 	| tUNUMBER tMONTH_UNIT { | ||||||
| 	    yyRelMonth += $1 * $2; | 	    context->yyRelMonth += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tMONTH_UNIT { | 	| tSNUMBER tMONTH_UNIT { | ||||||
| 	    yyRelMonth += $1 * $2; | 	    context->yyRelMonth += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tMONTH_UNIT { | 	| tMONTH_UNIT { | ||||||
| 	    yyRelMonth += $1; | 	    context->yyRelMonth += $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tDAY_UNIT { | 	| tUNUMBER tDAY_UNIT { | ||||||
| 	    yyRelDay += $1 * $2; | 	    context->yyRelDay += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tDAY_UNIT { | 	| tSNUMBER tDAY_UNIT { | ||||||
| 	    yyRelDay += $1 * $2; | 	    context->yyRelDay += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tDAY_UNIT { | 	| tDAY_UNIT { | ||||||
| 	    yyRelDay += $1; | 	    context->yyRelDay += $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tHOUR_UNIT { | 	| tUNUMBER tHOUR_UNIT { | ||||||
| 	    yyRelHour += $1 * $2; | 	    context->yyRelHour += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tHOUR_UNIT { | 	| tSNUMBER tHOUR_UNIT { | ||||||
| 	    yyRelHour += $1 * $2; | 	    context->yyRelHour += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tHOUR_UNIT { | 	| tHOUR_UNIT { | ||||||
| 	    yyRelHour += $1; | 	    context->yyRelHour += $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tMINUTE_UNIT { | 	| tUNUMBER tMINUTE_UNIT { | ||||||
| 	    yyRelMinutes += $1 * $2; | 	    context->yyRelMinutes += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tMINUTE_UNIT { | 	| tSNUMBER tMINUTE_UNIT { | ||||||
| 	    yyRelMinutes += $1 * $2; | 	    context->yyRelMinutes += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tMINUTE_UNIT { | 	| tMINUTE_UNIT { | ||||||
| 	    yyRelMinutes += $1; | 	    context->yyRelMinutes += $1; | ||||||
| 	} | 	} | ||||||
| 	| tUNUMBER tSEC_UNIT { | 	| tUNUMBER tSEC_UNIT { | ||||||
| 	    yyRelSeconds += $1 * $2; | 	    context->yyRelSeconds += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSNUMBER tSEC_UNIT { | 	| tSNUMBER tSEC_UNIT { | ||||||
| 	    yyRelSeconds += $1 * $2; | 	    context->yyRelSeconds += $1 * $2; | ||||||
| 	} | 	} | ||||||
| 	| tSEC_UNIT { | 	| tSEC_UNIT { | ||||||
| 	    yyRelSeconds += $1; | 	    context->yyRelSeconds += $1; | ||||||
| 	} | 	} | ||||||
| 	; | 	; | ||||||
|  |  | ||||||
| number	: tUNUMBER | number	: tUNUMBER | ||||||
|           { |           { | ||||||
| 	    if (yyHaveTime && yyHaveDate && !yyHaveRel) | 	    if (context->yyHaveTime && context->yyHaveDate && | ||||||
| 	      yyYear = $1; | 		!context->yyHaveRel) | ||||||
|  | 	      context->yyYear = $1; | ||||||
| 	    else | 	    else | ||||||
| 	      { | 	      { | ||||||
| 		if ($1>10000) | 		if ($1>10000) | ||||||
| 		  { | 		  { | ||||||
| 		    yyHaveDate++; | 		    context->yyHaveDate++; | ||||||
| 		    yyDay= ($1)%100; | 		    context->yyDay= ($1)%100; | ||||||
| 		    yyMonth= ($1/100)%100; | 		    context->yyMonth= ($1/100)%100; | ||||||
| 		    yyYear = $1/10000; | 		    context->yyYear = $1/10000; | ||||||
| 		  } | 		  } | ||||||
| 		else | 		else | ||||||
| 		  { | 		  { | ||||||
| 		    yyHaveTime++; | 		    context->yyHaveTime++; | ||||||
| 		    if ($1 < 100) | 		    if ($1 < 100) | ||||||
| 		      { | 		      { | ||||||
| 			yyHour = $1; | 			context->yyHour = $1; | ||||||
| 			yyMinutes = 0; | 			context->yyMinutes = 0; | ||||||
| 		      } | 		      } | ||||||
| 		    else | 		    else | ||||||
| 		      { | 		      { | ||||||
| 		    	yyHour = $1 / 100; | 		    	context->yyHour = $1 / 100; | ||||||
| 		    	yyMinutes = $1 % 100; | 		    	context->yyMinutes = $1 % 100; | ||||||
| 		      } | 		      } | ||||||
| 		    yySeconds = 0; | 		    context->yySeconds = 0; | ||||||
| 		    yyMeridian = MER24; | 		    context->yyMeridian = MER24; | ||||||
| 		  } | 		  } | ||||||
| 	      } | 	      } | ||||||
| 	  } | 	  } | ||||||
| @@ -725,7 +735,8 @@ ToYear (Year) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| LookupWord (buff) | LookupWord (yylval, buff) | ||||||
|  |      YYSTYPE *yylval; | ||||||
|      char *buff; |      char *buff; | ||||||
| { | { | ||||||
|   register char *p; |   register char *p; | ||||||
| @@ -741,12 +752,12 @@ LookupWord (buff) | |||||||
|  |  | ||||||
|   if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) |   if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0) | ||||||
|     { |     { | ||||||
|       yylval.Meridian = MERam; |       yylval->Meridian = MERam; | ||||||
|       return tMERIDIAN; |       return tMERIDIAN; | ||||||
|     } |     } | ||||||
|   if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) |   if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0) | ||||||
|     { |     { | ||||||
|       yylval.Meridian = MERpm; |       yylval->Meridian = MERpm; | ||||||
|       return tMERIDIAN; |       return tMERIDIAN; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -767,13 +778,13 @@ LookupWord (buff) | |||||||
| 	{ | 	{ | ||||||
| 	  if (strncmp (buff, tp->name, 3) == 0) | 	  if (strncmp (buff, tp->name, 3) == 0) | ||||||
| 	    { | 	    { | ||||||
| 	      yylval.Number = tp->value; | 	      yylval->Number = tp->value; | ||||||
| 	      return tp->type; | 	      return tp->type; | ||||||
| 	    } | 	    } | ||||||
| 	} | 	} | ||||||
|       else if (strcmp (buff, tp->name) == 0) |       else if (strcmp (buff, tp->name) == 0) | ||||||
| 	{ | 	{ | ||||||
| 	  yylval.Number = tp->value; | 	  yylval->Number = tp->value; | ||||||
| 	  return tp->type; | 	  return tp->type; | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| @@ -781,7 +792,7 @@ LookupWord (buff) | |||||||
|   for (tp = TimezoneTable; tp->name; tp++) |   for (tp = TimezoneTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -791,7 +802,7 @@ LookupWord (buff) | |||||||
|   for (tp = UnitsTable; tp->name; tp++) |   for (tp = UnitsTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -803,7 +814,7 @@ LookupWord (buff) | |||||||
|       for (tp = UnitsTable; tp->name; tp++) |       for (tp = UnitsTable; tp->name; tp++) | ||||||
| 	if (strcmp (buff, tp->name) == 0) | 	if (strcmp (buff, tp->name) == 0) | ||||||
| 	  { | 	  { | ||||||
| 	    yylval.Number = tp->value; | 	    yylval->Number = tp->value; | ||||||
| 	    return tp->type; | 	    return tp->type; | ||||||
| 	  } | 	  } | ||||||
|       buff[i] = 's';		/* Put back for "this" in OtherTable. */ |       buff[i] = 's';		/* Put back for "this" in OtherTable. */ | ||||||
| @@ -812,7 +823,7 @@ LookupWord (buff) | |||||||
|   for (tp = OtherTable; tp->name; tp++) |   for (tp = OtherTable; tp->name; tp++) | ||||||
|     if (strcmp (buff, tp->name) == 0) |     if (strcmp (buff, tp->name) == 0) | ||||||
|       { |       { | ||||||
| 	yylval.Number = tp->value; | 	yylval->Number = tp->value; | ||||||
| 	return tp->type; | 	return tp->type; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -822,7 +833,7 @@ LookupWord (buff) | |||||||
|       for (tp = MilitaryTable; tp->name; tp++) |       for (tp = MilitaryTable; tp->name; tp++) | ||||||
| 	if (strcmp (buff, tp->name) == 0) | 	if (strcmp (buff, tp->name) == 0) | ||||||
| 	  { | 	  { | ||||||
| 	    yylval.Number = tp->value; | 	    yylval->Number = tp->value; | ||||||
| 	    return tp->type; | 	    return tp->type; | ||||||
| 	  } | 	  } | ||||||
|     } |     } | ||||||
| @@ -838,7 +849,7 @@ LookupWord (buff) | |||||||
|     for (tp = TimezoneTable; tp->name; tp++) |     for (tp = TimezoneTable; tp->name; tp++) | ||||||
|       if (strcmp (buff, tp->name) == 0) |       if (strcmp (buff, tp->name) == 0) | ||||||
| 	{ | 	{ | ||||||
| 	  yylval.Number = tp->value; | 	  yylval->Number = tp->value; | ||||||
| 	  return tp->type; | 	  return tp->type; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -846,7 +857,9 @@ LookupWord (buff) | |||||||
| } | } | ||||||
|  |  | ||||||
| static int | static int | ||||||
| yylex () | yylex (yylval, cookie) | ||||||
|  |      YYSTYPE *yylval; | ||||||
|  |      void *cookie; | ||||||
| { | { | ||||||
|   register unsigned char c; |   register unsigned char c; | ||||||
|   register char *p; |   register char *p; | ||||||
| @@ -856,42 +869,42 @@ yylex () | |||||||
|  |  | ||||||
|   for (;;) |   for (;;) | ||||||
|     { |     { | ||||||
|       while (ISSPACE ((unsigned char) *yyInput)) |       while (ISSPACE ((unsigned char) *context->yyInput)) | ||||||
| 	yyInput++; | 	context->yyInput++; | ||||||
|  |  | ||||||
|       if (ISDIGIT (c = *yyInput) || c == '-' || c == '+') |       if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+') | ||||||
| 	{ | 	{ | ||||||
| 	  if (c == '-' || c == '+') | 	  if (c == '-' || c == '+') | ||||||
| 	    { | 	    { | ||||||
| 	      sign = c == '-' ? -1 : 1; | 	      sign = c == '-' ? -1 : 1; | ||||||
| 	      if (!ISDIGIT (*++yyInput)) | 	      if (!ISDIGIT (*++context->yyInput)) | ||||||
| 		/* skip the '-' sign */ | 		/* skip the '-' sign */ | ||||||
| 		continue; | 		continue; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    sign = 0; | 	    sign = 0; | ||||||
| 	  for (yylval.Number = 0; ISDIGIT (c = *yyInput++);) | 	  for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);) | ||||||
| 	    yylval.Number = 10 * yylval.Number + c - '0'; | 	    yylval->Number = 10 * yylval->Number + c - '0'; | ||||||
| 	  yyInput--; | 	  context->yyInput--; | ||||||
| 	  if (sign < 0) | 	  if (sign < 0) | ||||||
| 	    yylval.Number = -yylval.Number; | 	    yylval->Number = -yylval->Number; | ||||||
| 	  return sign ? tSNUMBER : tUNUMBER; | 	  return sign ? tSNUMBER : tUNUMBER; | ||||||
| 	} | 	} | ||||||
|       if (ISALPHA (c)) |       if (ISALPHA (c)) | ||||||
| 	{ | 	{ | ||||||
| 	  for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';) | 	  for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';) | ||||||
| 	    if (p < &buff[sizeof buff - 1]) | 	    if (p < &buff[sizeof buff - 1]) | ||||||
| 	      *p++ = c; | 	      *p++ = c; | ||||||
| 	  *p = '\0'; | 	  *p = '\0'; | ||||||
| 	  yyInput--; | 	  context->yyInput--; | ||||||
| 	  return LookupWord (buff); | 	  return LookupWord (yylval, buff); | ||||||
| 	} | 	} | ||||||
|       if (c != '(') |       if (c != '(') | ||||||
| 	return *yyInput++; | 	return *context->yyInput++; | ||||||
|       Count = 0; |       Count = 0; | ||||||
|       do |       do | ||||||
| 	{ | 	{ | ||||||
| 	  c = *yyInput++; | 	  c = *context->yyInput++; | ||||||
| 	  if (c == '\0') | 	  if (c == '\0') | ||||||
| 	    return c; | 	    return c; | ||||||
| 	  if (c == '(') | 	  if (c == '(') | ||||||
| @@ -931,10 +944,11 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| { | { | ||||||
|   struct tm tm, tm0, *tmp; |   struct tm tm, tm0, *tmp; | ||||||
|   time_t Start; |   time_t Start; | ||||||
|  |   CONTEXT cookie; | ||||||
| #ifdef HAVE_LOCALTIME_R | #ifdef HAVE_LOCALTIME_R | ||||||
|   struct tm keeptime; |   struct tm keeptime; | ||||||
| #endif | #endif | ||||||
|   yyInput = p; |   cookie.yyInput = p; | ||||||
|   Start = now ? *now : time ((time_t *) NULL); |   Start = now ? *now : time ((time_t *) NULL); | ||||||
| #ifdef HAVE_LOCALTIME_R | #ifdef HAVE_LOCALTIME_R | ||||||
|   tmp = (struct tm *)localtime_r(&Start, &keeptime); |   tmp = (struct tm *)localtime_r(&Start, &keeptime); | ||||||
| @@ -943,52 +957,55 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| #endif | #endif | ||||||
|   if (!tmp) |   if (!tmp) | ||||||
|     return -1; |     return -1; | ||||||
|   yyYear = tmp->tm_year + TM_YEAR_ORIGIN; |   cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN; | ||||||
|   yyMonth = tmp->tm_mon + 1; |   cookie.yyMonth = tmp->tm_mon + 1; | ||||||
|   yyDay = tmp->tm_mday; |   cookie.yyDay = tmp->tm_mday; | ||||||
|   yyHour = tmp->tm_hour; |   cookie.yyHour = tmp->tm_hour; | ||||||
|   yyMinutes = tmp->tm_min; |   cookie.yyMinutes = tmp->tm_min; | ||||||
|   yySeconds = tmp->tm_sec; |   cookie.yySeconds = tmp->tm_sec; | ||||||
|   tm.tm_isdst = tmp->tm_isdst; |   tm.tm_isdst = tmp->tm_isdst; | ||||||
|   yyMeridian = MER24; |   cookie.yyMeridian = MER24; | ||||||
|   yyRelSeconds = 0; |   cookie.yyRelSeconds = 0; | ||||||
|   yyRelMinutes = 0; |   cookie.yyRelMinutes = 0; | ||||||
|   yyRelHour = 0; |   cookie.yyRelHour = 0; | ||||||
|   yyRelDay = 0; |   cookie.yyRelDay = 0; | ||||||
|   yyRelMonth = 0; |   cookie.yyRelMonth = 0; | ||||||
|   yyRelYear = 0; |   cookie.yyRelYear = 0; | ||||||
|   yyHaveDate = 0; |   cookie.yyHaveDate = 0; | ||||||
|   yyHaveDay = 0; |   cookie.yyHaveDay = 0; | ||||||
|   yyHaveRel = 0; |   cookie.yyHaveRel = 0; | ||||||
|   yyHaveTime = 0; |   cookie.yyHaveTime = 0; | ||||||
|   yyHaveZone = 0; |   cookie.yyHaveZone = 0; | ||||||
|  |  | ||||||
|   if (yyparse () |   if (yyparse (&cookie) | ||||||
|       || yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1) |       || cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 || | ||||||
|  |       cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1) | ||||||
|     return -1; |     return -1; | ||||||
|  |  | ||||||
|   tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear; |   tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear; | ||||||
|   tm.tm_mon = yyMonth - 1 + yyRelMonth; |   tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth; | ||||||
|   tm.tm_mday = yyDay + yyRelDay; |   tm.tm_mday = cookie.yyDay + cookie.yyRelDay; | ||||||
|   if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay)) |   if (cookie.yyHaveTime || | ||||||
|  |       (cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay)) | ||||||
|     { |     { | ||||||
|       tm.tm_hour = ToHour (yyHour, yyMeridian); |       tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian); | ||||||
|       if (tm.tm_hour < 0) |       if (tm.tm_hour < 0) | ||||||
| 	return -1; | 	return -1; | ||||||
|       tm.tm_min = yyMinutes; |       tm.tm_min = cookie.yyMinutes; | ||||||
|       tm.tm_sec = yySeconds; |       tm.tm_sec = cookie.yySeconds; | ||||||
|     } |     } | ||||||
|   else |   else | ||||||
|     { |     { | ||||||
|       tm.tm_hour = tm.tm_min = tm.tm_sec = 0; |       tm.tm_hour = tm.tm_min = tm.tm_sec = 0; | ||||||
|     } |     } | ||||||
|   tm.tm_hour += yyRelHour; |   tm.tm_hour += cookie.yyRelHour; | ||||||
|   tm.tm_min += yyRelMinutes; |   tm.tm_min += cookie.yyRelMinutes; | ||||||
|   tm.tm_sec += yyRelSeconds; |   tm.tm_sec += cookie.yyRelSeconds; | ||||||
|  |  | ||||||
|   /* Let mktime deduce tm_isdst if we have an absolute timestamp, |   /* Let mktime deduce tm_isdst if we have an absolute timestamp, | ||||||
|      or if the relative timestamp mentions days, months, or years.  */ |      or if the relative timestamp mentions days, months, or years.  */ | ||||||
|   if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear) |   if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime | | ||||||
|  |       cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear) | ||||||
|     tm.tm_isdst = -1; |     tm.tm_isdst = -1; | ||||||
|  |  | ||||||
|   tm0 = tm; |   tm0 = tm; | ||||||
| @@ -1006,18 +1023,18 @@ curl_getdate (const char *p, const time_t *now) | |||||||
|          we apply mktime to 1970-01-02 08:00:00 instead and adjust the time |          we apply mktime to 1970-01-02 08:00:00 instead and adjust the time | ||||||
|          zone by 24 hours to compensate.  This algorithm assumes that |          zone by 24 hours to compensate.  This algorithm assumes that | ||||||
|          there is no DST transition within a day of the time_t boundaries.  */ |          there is no DST transition within a day of the time_t boundaries.  */ | ||||||
|       if (yyHaveZone) |       if (cookie.yyHaveZone) | ||||||
| 	{ | 	{ | ||||||
| 	  tm = tm0; | 	  tm = tm0; | ||||||
| 	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) | 	  if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN) | ||||||
| 	    { | 	    { | ||||||
| 	      tm.tm_mday++; | 	      tm.tm_mday++; | ||||||
| 	      yyTimezone -= 24 * 60; | 	      cookie.yyTimezone -= 24 * 60; | ||||||
| 	    } | 	    } | ||||||
| 	  else | 	  else | ||||||
| 	    { | 	    { | ||||||
| 	      tm.tm_mday--; | 	      tm.tm_mday--; | ||||||
| 	      yyTimezone += 24 * 60; | 	      cookie.yyTimezone += 24 * 60; | ||||||
| 	    } | 	    } | ||||||
| 	  Start = mktime (&tm); | 	  Start = mktime (&tm); | ||||||
| 	} | 	} | ||||||
| @@ -1026,22 +1043,29 @@ curl_getdate (const char *p, const time_t *now) | |||||||
| 	return Start; | 	return Start; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (yyHaveDay && !yyHaveDate) |   if (cookie.yyHaveDay && !cookie.yyHaveDate) | ||||||
|     { |     { | ||||||
|       tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7 |       tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7 | ||||||
| 		     + 7 * (yyDayOrdinal - (0 < yyDayOrdinal))); | 		     + 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal))); | ||||||
|       Start = mktime (&tm); |       Start = mktime (&tm); | ||||||
|       if (Start == (time_t) -1) |       if (Start == (time_t) -1) | ||||||
| 	return Start; | 	return Start; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|   if (yyHaveZone) |   if (cookie.yyHaveZone) | ||||||
|     { |     { | ||||||
|       long delta; |       long delta; | ||||||
|       struct tm *gmt = gmtime (&Start); |       struct tm *gmt; | ||||||
|  | #ifdef HAVE_GMTIME_R | ||||||
|  |       /* thread-safe version */ | ||||||
|  |       struct tm keeptime; | ||||||
|  |       gmt = (struct tm *)gmtime_r(&Start, &keeptime); | ||||||
|  | #else | ||||||
|  |       gmt = gmtime(&Start); | ||||||
|  | #endif | ||||||
|       if (!gmt) |       if (!gmt) | ||||||
| 	return -1; | 	return -1; | ||||||
|       delta = yyTimezone * 60L + difftm (&tm, gmt); |       delta = cookie.yyTimezone * 60L + difftm (&tm, gmt); | ||||||
|       if ((Start + delta < Start) != (delta < 0)) |       if ((Start + delta < Start) != (delta < 0)) | ||||||
| 	return -1;		/* time_t overflow */ | 	return -1;		/* time_t overflow */ | ||||||
|       Start += delta; |       Start += delta; | ||||||
|   | |||||||
| @@ -31,6 +31,10 @@ | |||||||
| #include <string.h> | #include <string.h> | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
|  |  | ||||||
|  | #ifdef	VMS | ||||||
|  | #include	<stdlib.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| /* | /* | ||||||
|  * This is supposed to be called in the beginning of a permform() session |  * This is supposed to be called in the beginning of a permform() session | ||||||
|  * and should reset all session-info variables |  * and should reset all session-info variables | ||||||
| @@ -44,11 +48,18 @@ CURLcode Curl_initinfo(struct SessionHandle *data) | |||||||
|   pro->t_connect = 0; |   pro->t_connect = 0; | ||||||
|   pro->t_pretransfer = 0; |   pro->t_pretransfer = 0; | ||||||
|   pro->t_starttransfer = 0; |   pro->t_starttransfer = 0; | ||||||
|  |   pro->timespent = 0; | ||||||
|  |  | ||||||
|   info->httpcode = 0; |   info->httpcode = 0; | ||||||
|   info->httpversion=0; |   info->httpversion=0; | ||||||
|   info->filetime=-1; /* -1 is an illegal time and thus means unknown */ |   info->filetime=-1; /* -1 is an illegal time and thus means unknown */ | ||||||
|    |    | ||||||
|  |   if (info->contenttype) | ||||||
|  |     free(info->contenttype); | ||||||
|  |   info->contenttype = NULL; | ||||||
|  |  | ||||||
|  |   info->header_size = 0; | ||||||
|  |   info->request_size = 0; | ||||||
|   return CURLE_OK; |   return CURLE_OK; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -132,6 +143,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...) | |||||||
|   case CURLINFO_CONTENT_LENGTH_UPLOAD: |   case CURLINFO_CONTENT_LENGTH_UPLOAD: | ||||||
|     *param_doublep = data->progress.size_ul; |     *param_doublep = data->progress.size_ul; | ||||||
|     break; |     break; | ||||||
|  |   case CURLINFO_CONTENT_TYPE: | ||||||
|  |     *param_charp = data->info.contenttype; | ||||||
|  |     break; | ||||||
|   default: |   default: | ||||||
|     return CURLE_BAD_FUNCTION_ARGUMENT; |     return CURLE_BAD_FUNCTION_ARGUMENT; | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  *                            | (__| |_| |  _ <| |___  |  *                            | (__| |_| |  _ <| |___  | ||||||
|  *                             \___|\___/|_| \_\_____| |  *                             \___|\___/|_| \_\_____| | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al |  * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al | ||||||
|  * |  * | ||||||
|  * In order to be useful for every potential user, curl and libcurl are |  * In order to be useful for every potential user, curl and libcurl are | ||||||
|  * dual-licensed under the MPL and the MIT/X-derivate licenses. |  * dual-licensed under the MPL and the MIT/X-derivate licenses. | ||||||
| @@ -24,7 +24,7 @@ | |||||||
| #include "setup.h" | #include "setup.h" | ||||||
|  |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
| #include "hash.h" | #include "hash.h" | ||||||
| #include "llist.h" | #include "llist.h" | ||||||
|  |  | ||||||
| @@ -101,7 +101,10 @@ curl_hash_alloc(int slots, curl_hash_dtor dtor) | |||||||
| { | { | ||||||
|   curl_hash *h; |   curl_hash *h; | ||||||
|  |  | ||||||
|   h = malloc(sizeof(curl_hash)); |   h = (curl_hash *)malloc(sizeof(curl_hash)); | ||||||
|  |   if(NULL == h) | ||||||
|  |     return NULL; | ||||||
|  |  | ||||||
|   curl_hash_init(h, slots, dtor); |   curl_hash_init(h, slots, dtor); | ||||||
|  |  | ||||||
|   return h; |   return h; | ||||||
|   | |||||||
							
								
								
									
										107
									
								
								lib/hostip.c
									
									
									
									
									
								
							
							
						
						
									
										107
									
								
								lib/hostip.c
									
									
									
									
									
								
							| @@ -50,6 +50,7 @@ | |||||||
| #include <stdlib.h>	/* required for free() prototypes */ | #include <stdlib.h>	/* required for free() prototypes */ | ||||||
| #endif | #endif | ||||||
| #ifdef	VMS | #ifdef	VMS | ||||||
|  | #include <in.h> | ||||||
| #include <inet.h> | #include <inet.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
| #endif | #endif | ||||||
| @@ -60,6 +61,9 @@ | |||||||
| #include "hostip.h" | #include "hostip.h" | ||||||
| #include "hash.h" | #include "hash.h" | ||||||
|  |  | ||||||
|  | #define _MPRINTF_REPLACE /* use our functions only */ | ||||||
|  | #include <curl/mprintf.h> | ||||||
|  |  | ||||||
| #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) | #if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL) | ||||||
| #include "inet_ntoa_r.h" | #include "inet_ntoa_r.h" | ||||||
| #endif | #endif | ||||||
| @@ -98,13 +102,71 @@ struct curl_dns_cache_entry { | |||||||
|   time_t timestamp; |   time_t timestamp; | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  | /* count the number of characters that an integer takes up */ | ||||||
|  | static int _num_chars(int i) | ||||||
|  | { | ||||||
|  |   int chars = 0; | ||||||
|  |  | ||||||
|  |   /* While the number divided by 10 is greater than one,  | ||||||
|  |    * re-divide the number by 10, and increment the number of  | ||||||
|  |    * characters by 1. | ||||||
|  |    * | ||||||
|  |    * this relies on the fact that for every multiple of 10,  | ||||||
|  |    * a new digit is added onto every number | ||||||
|  |    */ | ||||||
|  |   do { | ||||||
|  |     chars++; | ||||||
|  |  | ||||||
|  |     i = (int) i / 10; | ||||||
|  |   } while (i >= 1); | ||||||
|  |  | ||||||
|  |   return chars; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Create a hostcache id */ | ||||||
|  | static char * | ||||||
|  | _create_hostcache_id(char *server, int port, ssize_t *entry_len) | ||||||
|  | { | ||||||
|  |   char *id = NULL; | ||||||
|  |  | ||||||
|  |   /* Get the length of the new entry id */ | ||||||
|  |   *entry_len = *entry_len +      /* Hostname length */ | ||||||
|  |                1 +               /* The ':' seperator */ | ||||||
|  |                _num_chars(port); /* The number of characters the port will take up */ | ||||||
|  |    | ||||||
|  |   /* Allocate the new entry id */ | ||||||
|  |   id = malloc(*entry_len + 1); | ||||||
|  |   if (!id) { | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   /* Create the new entry */ | ||||||
|  |   /* If sprintf() doesn't return the entry length, that signals failure */ | ||||||
|  |   if (sprintf(id, "%s:%d", server, port) != *entry_len) { | ||||||
|  |     /* Free the allocated id, set length to zero and return NULL */ | ||||||
|  |     *entry_len = 0; | ||||||
|  |     free(id); | ||||||
|  |     return NULL; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   return id; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* Macro to save redundant free'ing of entry_id */ | ||||||
|  | #define _hostcache_return(__v) \ | ||||||
|  | { \ | ||||||
|  |   free(entry_id); \ | ||||||
|  |   return (__v); \ | ||||||
|  | } | ||||||
|  |  | ||||||
| Curl_addrinfo *Curl_resolv(struct SessionHandle *data, | Curl_addrinfo *Curl_resolv(struct SessionHandle *data, | ||||||
|                            char *hostname, |                            char *hostname, | ||||||
|                            int port, |                            int port, | ||||||
|                            char **bufp) |                            char **bufp) | ||||||
| { | { | ||||||
|  |   char *entry_id = NULL; | ||||||
|   struct curl_dns_cache_entry *p = NULL; |   struct curl_dns_cache_entry *p = NULL; | ||||||
|   size_t hostname_len; |   ssize_t entry_len; | ||||||
|   time_t now; |   time_t now; | ||||||
|  |  | ||||||
|   /* If the host cache timeout is 0, we don't do DNS cach'ing |   /* If the host cache timeout is 0, we don't do DNS cach'ing | ||||||
| @@ -113,40 +175,47 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data, | |||||||
|     return Curl_getaddrinfo(data, hostname, port, bufp); |     return Curl_getaddrinfo(data, hostname, port, bufp); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   hostname_len = strlen(hostname)+1; |   /* Create an entry id, based upon the hostname and port */ | ||||||
|  |   entry_len = strlen(hostname); | ||||||
|  |   entry_id = _create_hostcache_id(hostname, port, &entry_len); | ||||||
|  |   /* If we can't create the entry id, don't cache, just fall-through | ||||||
|  |      to the plain Curl_getaddrinfo() */ | ||||||
|  |   if (!entry_id) { | ||||||
|  |     return Curl_getaddrinfo(data, hostname, port, bufp); | ||||||
|  |   } | ||||||
|    |    | ||||||
|   time(&now); |   time(&now); | ||||||
|   /* See if its already in our dns cache */ |   /* See if its already in our dns cache */ | ||||||
|   if (curl_hash_find(data->hostcache, hostname, hostname_len, (void **) &p)) { |   if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) { | ||||||
|     /* Do we need to check for a cache timeout? */ |     /* Do we need to check for a cache timeout? */ | ||||||
|     if (data->set.dns_cache_timeout != -1) { |     if (data->set.dns_cache_timeout != -1) { | ||||||
|       /* Return if the entry has not timed out */ |       /* Return if the entry has not timed out */ | ||||||
|       if ((now - p->timestamp) < data->set.dns_cache_timeout) { |       if ((now - p->timestamp) < data->set.dns_cache_timeout) { | ||||||
|         return p->addr; |         _hostcache_return(p->addr); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|     else { |     else { | ||||||
|       return p->addr; |       _hostcache_return(p->addr); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   /* Create a new cache entry */ |   /* Create a new cache entry */ | ||||||
|   p = (struct curl_dns_cache_entry *) |   p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry)); | ||||||
|     malloc(sizeof(struct curl_dns_cache_entry)); |   if (!p) { | ||||||
|   if (!p) |    _hostcache_return(NULL); | ||||||
|     return NULL; |   } | ||||||
|  |  | ||||||
|   p->addr = Curl_getaddrinfo(data, hostname, port, bufp); |   p->addr = Curl_getaddrinfo(data, hostname, port, bufp); | ||||||
|   if (!p->addr) { |   if (!p->addr) { | ||||||
|     free(p); |     free(p); | ||||||
|     return NULL; |     _hostcache_return(NULL); | ||||||
|   } |   } | ||||||
|   p->timestamp = now; |   p->timestamp = now; | ||||||
|  |  | ||||||
|   /* Save it in our host cache */ |   /* Save it in our host cache */ | ||||||
|   curl_hash_update(data->hostcache, hostname, hostname_len, (const void *) p); |   curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p); | ||||||
|  |  | ||||||
|   return p->addr; |   _hostcache_return(p->addr); | ||||||
| } | } | ||||||
|  |  | ||||||
| /* | /* | ||||||
| @@ -224,7 +293,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | |||||||
|   char sbuf[NI_MAXSERV]; |   char sbuf[NI_MAXSERV]; | ||||||
|  |  | ||||||
|   memset(&hints, 0, sizeof(hints)); |   memset(&hints, 0, sizeof(hints)); | ||||||
|   hints.ai_family = PF_UNSPEC; |   hints.ai_family = PF_INET; | ||||||
|   hints.ai_socktype = SOCK_STREAM; |   hints.ai_socktype = SOCK_STREAM; | ||||||
|   hints.ai_flags = AI_CANONNAME; |   hints.ai_flags = AI_CANONNAME; | ||||||
|   snprintf(sbuf, sizeof(sbuf), "%d", port); |   snprintf(sbuf, sizeof(sbuf), "%d", port); | ||||||
| @@ -341,7 +410,7 @@ static char *MakeIP(unsigned long num,char *addr, int addr_len) | |||||||
|    considerably. */ |    considerably. */ | ||||||
|  |  | ||||||
| #ifndef INADDR_NONE | #ifndef INADDR_NONE | ||||||
| #define INADDR_NONE (unsigned long) ~0 | #define INADDR_NONE (in_addr_t) ~0 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | ||||||
| @@ -358,10 +427,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | |||||||
|    * everything. OSF1 is known to require at least 8872 bytes. The buffer |    * everything. OSF1 is known to require at least 8872 bytes. The buffer | ||||||
|    * required for storing all possible aliases and IP numbers is according to |    * required for storing all possible aliases and IP numbers is according to | ||||||
|    * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */ |    * Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */ | ||||||
|   char *buf = (char *)malloc(CURL_NAMELOOKUP_SIZE); |   int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE); | ||||||
|   if(!buf) |   if(!buf) | ||||||
|     return NULL; /* major failure */ |     return NULL; /* major failure */ | ||||||
|   *bufp = buf; |   *bufp = (char *)buf; | ||||||
|  |  | ||||||
|   port=0; /* unused in IPv4 code */ |   port=0; /* unused in IPv4 code */ | ||||||
|   ret = 0; /* to prevent the compiler warning */ |   ret = 0; /* to prevent the compiler warning */ | ||||||
| @@ -391,7 +460,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | |||||||
|     /* Solaris, IRIX and more */ |     /* Solaris, IRIX and more */ | ||||||
|     if ((h = gethostbyname_r(hostname, |     if ((h = gethostbyname_r(hostname, | ||||||
|                              (struct hostent *)buf, |                              (struct hostent *)buf, | ||||||
|                              buf + sizeof(struct hostent), |                              (char *)buf + sizeof(struct hostent), | ||||||
|                              CURL_NAMELOOKUP_SIZE - sizeof(struct hostent), |                              CURL_NAMELOOKUP_SIZE - sizeof(struct hostent), | ||||||
|                              &h_errnop)) == NULL ) |                              &h_errnop)) == NULL ) | ||||||
| #endif | #endif | ||||||
| @@ -399,7 +468,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | |||||||
|     /* Linux */ |     /* Linux */ | ||||||
|     if( gethostbyname_r(hostname, |     if( gethostbyname_r(hostname, | ||||||
|                         (struct hostent *)buf, |                         (struct hostent *)buf, | ||||||
|                         buf + sizeof(struct hostent), |                         (char *)buf + sizeof(struct hostent), | ||||||
|                         CURL_NAMELOOKUP_SIZE - sizeof(struct hostent), |                         CURL_NAMELOOKUP_SIZE - sizeof(struct hostent), | ||||||
|                         &h, /* DIFFERENCE */ |                         &h, /* DIFFERENCE */ | ||||||
|                         &h_errnop)) |                         &h_errnop)) | ||||||
| @@ -442,7 +511,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data, | |||||||
|       /* we make a copy of the hostent right now, right here, as the |       /* we make a copy of the hostent right now, right here, as the | ||||||
|          static one we got a pointer to might get removed when we don't |          static one we got a pointer to might get removed when we don't | ||||||
|          want/expect that */ |          want/expect that */ | ||||||
|       h = pack_hostent(buf, h); |       h = pack_hostent((char *)buf, h); | ||||||
| #endif | #endif | ||||||
|   } |   } | ||||||
|   return (h); |   return (h); | ||||||
|   | |||||||
							
								
								
									
										23
									
								
								lib/http.c
									
									
									
									
									
								
							
							
						
						
									
										23
									
								
								lib/http.c
									
									
									
									
									
								
							| @@ -151,7 +151,7 @@ CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in, | |||||||
|       break; |       break; | ||||||
|  |  | ||||||
|     if(amount != size) { |     if(amount != size) { | ||||||
|       size += amount; |       size -= amount; | ||||||
|       ptr += amount; |       ptr += amount; | ||||||
|     } |     } | ||||||
|     else |     else | ||||||
| @@ -815,8 +815,6 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     if(HTTPREQ_POST_FORM == data->set.httpreq) { |     if(HTTPREQ_POST_FORM == data->set.httpreq) { | ||||||
|       char contentType[256]; |  | ||||||
|       int linelength=0; |  | ||||||
|       if(Curl_FormInit(&http->form, http->sendit)) { |       if(Curl_FormInit(&http->form, http->sendit)) { | ||||||
|         failf(data, "Internal HTTP POST error!"); |         failf(data, "Internal HTTP POST error!"); | ||||||
|         return CURLE_HTTP_POST_ERROR; |         return CURLE_HTTP_POST_ERROR; | ||||||
| @@ -831,7 +829,7 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|       data->set.in = (FILE *)&http->form; |       data->set.in = (FILE *)&http->form; | ||||||
|  |  | ||||||
|       add_bufferf(req_buffer, |       add_bufferf(req_buffer, | ||||||
|                   "Content-Length: %d\r\n", http->postsize-2); |                   "Content-Length: %d\r\n", http->postsize); | ||||||
|  |  | ||||||
|       if(!checkheaders(data, "Expect:")) { |       if(!checkheaders(data, "Expect:")) { | ||||||
|         /* if not disabled explicitly we add a Expect: 100-continue |         /* if not disabled explicitly we add a Expect: 100-continue | ||||||
| @@ -840,10 +838,19 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|         add_bufferf(req_buffer, |         add_bufferf(req_buffer, | ||||||
|                     "Expect: 100-continue\r\n"); |                     "Expect: 100-continue\r\n"); | ||||||
|         data->set.expect100header = TRUE; |         data->set.expect100header = TRUE; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       if(!checkheaders(data, "Content-Type:")) { | ||||||
|         /* Get Content-Type: line from Curl_FormReadOneLine, which happens |         /* Get Content-Type: line from Curl_FormReadOneLine, which happens | ||||||
|            to always be the first line. We can know this for sure since |            to always be the first line. We can know this for sure since | ||||||
|            we always build the formpost linked list the same way! */ |            we always build the formpost linked list the same way! | ||||||
|  |  | ||||||
|  |            The Content-Type header line also contains the MIME boundary | ||||||
|  |            string etc why disabling this header is likely to not make things | ||||||
|  |            work, but we support it anyway. | ||||||
|  |         */ | ||||||
|  |         char contentType[256]; | ||||||
|  |         int linelength=0; | ||||||
|         linelength = Curl_FormReadOneLine (contentType, |         linelength = Curl_FormReadOneLine (contentType, | ||||||
|                                            sizeof(contentType), |                                            sizeof(contentType), | ||||||
|                                            1, |                                            1, | ||||||
| @@ -855,6 +862,9 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|         add_buffer(req_buffer, contentType, linelength); |         add_buffer(req_buffer, contentType, linelength); | ||||||
|       } |       } | ||||||
|  |  | ||||||
|  |       /* make the request end in a true CRLF */ | ||||||
|  |       add_buffer(req_buffer, "\r\n", 2); | ||||||
|  |  | ||||||
|       /* set upload size to the progress meter */ |       /* set upload size to the progress meter */ | ||||||
|       Curl_pgrsSetUploadSize(data, http->postsize); |       Curl_pgrsSetUploadSize(data, http->postsize); | ||||||
|  |  | ||||||
| @@ -935,12 +945,11 @@ CURLcode Curl_http(struct connectdata *conn) | |||||||
|           add_buffer(req_buffer, "\r\n", 2); |           add_buffer(req_buffer, "\r\n", 2); | ||||||
|           add_buffer(req_buffer, data->set.postfields, |           add_buffer(req_buffer, data->set.postfields, | ||||||
|                      data->set.postfieldsize); |                      data->set.postfieldsize); | ||||||
|           add_buffer(req_buffer, "\r\n", 2); |  | ||||||
|         } |         } | ||||||
|         else { |         else { | ||||||
|           add_bufferf(req_buffer, |           add_bufferf(req_buffer, | ||||||
|                       "\r\n" |                       "\r\n" | ||||||
|                       "%s\r\n", |                       "%s", | ||||||
|                       data->set.postfields ); |                       data->set.postfields ); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  *                            | (__| |_| |  _ <| |___  |  *                            | (__| |_| |  _ <| |___  | ||||||
|  *                             \___|\___/|_| \_\_____| |  *                             \___|\___/|_| \_\_____| | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al |  * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al | ||||||
|  * |  * | ||||||
|  * In order to be useful for every potential user, curl and libcurl are |  * In order to be useful for every potential user, curl and libcurl are | ||||||
|  * dual-licensed under the MPL and the MIT/X-derivate licenses. |  * dual-licensed under the MPL and the MIT/X-derivate licenses. | ||||||
| @@ -23,8 +23,8 @@ | |||||||
|  |  | ||||||
| #include "setup.h" | #include "setup.h" | ||||||
|  |  | ||||||
|  |  | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
| #include "llist.h" | #include "llist.h" | ||||||
|  |  | ||||||
| @@ -46,7 +46,10 @@ curl_llist_alloc(curl_llist_dtor dtor) | |||||||
| { | { | ||||||
|   curl_llist *list; |   curl_llist *list; | ||||||
|  |  | ||||||
|   list = malloc(sizeof(curl_llist)); |   list = (curl_llist *)malloc(sizeof(curl_llist)); | ||||||
|  |   if(NULL == list) | ||||||
|  |     return NULL; | ||||||
|  |  | ||||||
|   curl_llist_init(list, dtor); |   curl_llist_init(list, dtor); | ||||||
|  |  | ||||||
|   return list; |   return list; | ||||||
|   | |||||||
| @@ -168,7 +168,10 @@ int curl_fclose(FILE *file, int line, const char *source) | |||||||
|             source, line, file); |             source, line, file); | ||||||
|   return res; |   return res; | ||||||
| } | } | ||||||
|  | #else | ||||||
|  | #ifdef VMS | ||||||
|  | int VOID_VAR_MEMDEBUG;	 | ||||||
|  | #endif | ||||||
| #endif /* MALLOCDEBUG */ | #endif /* MALLOCDEBUG */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -24,73 +24,11 @@ | |||||||
|  * - Max 128 parameters |  * - Max 128 parameters | ||||||
|  * - No 'long double' support. |  * - No 'long double' support. | ||||||
|  * |  * | ||||||
|  ************************************************************************* |  * If you ever want truly portable and good *printf() clones, the project that | ||||||
|  * |  * took on from here is named 'Trio' and you find more details on the trio web | ||||||
|  * |  * page at http://daniel.haxx.se/trio/ | ||||||
|  * 1998/01/10  (v2.8) |  */ | ||||||
|  *   Daniel |  | ||||||
|  *   - Updated version number. |  | ||||||
|  *   - Corrected a static non-zero prefixed width problem. |  | ||||||
|  * |  | ||||||
|  * 1998/11/17 - Daniel |  | ||||||
|  *   Added daprintf() and dvaprintf() for allocated printf() and vprintf(). |  | ||||||
|  *   They return an allocated buffer with the result inside. The result must |  | ||||||
|  *   be free()ed! |  | ||||||
|  * |  | ||||||
|  * 1998/08/23 - breese |  | ||||||
|  * |  | ||||||
|  *   Converted all non-printable (and non-whitespace) characters into |  | ||||||
|  *   their decimal ASCII value preceeded by a '\' character |  | ||||||
|  *   (this only applies to snprintf family so far) |  | ||||||
|  * |  | ||||||
|  *   Added %S (which is the same as %#s) |  | ||||||
|  * |  | ||||||
|  * 1998/05/05 (v2.7) |  | ||||||
|  * |  | ||||||
|  *   Fixed precision and width qualifiers (%.*s) |  | ||||||
|  * |  | ||||||
|  *   Added support for snprintf() |  | ||||||
|  * |  | ||||||
|  *   Quoting (%#s) is disabled for the (nil) pointer |  | ||||||
|  * |  | ||||||
|  * 1997/06/09 (v2.6) |  | ||||||
|  * |  | ||||||
|  *   %#s means that the string will be quoted with " |  | ||||||
|  *   (I was getting tired of writing \"%s\" all the time) |  | ||||||
|  * |  | ||||||
|  *   [ERR] for strings changed to (nil) |  | ||||||
|  * |  | ||||||
|  * v2.5 |  | ||||||
|  * - Added C++ support |  | ||||||
|  * - Prepended all internal functions with dprintf_ |  | ||||||
|  * - Defined the booleans |  | ||||||
|  * |  | ||||||
|  * v2.4 |  | ||||||
|  * - Added dvsprintf(), dvfprintf() and dvprintf(). |  | ||||||
|  * - Made the formatting function available with the name _formatf() to enable |  | ||||||
|  *   other *printf()-inspired functions. (I considered adding a dmsprintf() |  | ||||||
|  *   that works like sprintf() but allocates the destination string and |  | ||||||
|  *   possibly enlarges it itself, but things like that should be done with the |  | ||||||
|  *   new _formatf() instead.) |  | ||||||
|  * |  | ||||||
|  * v2.3 |  | ||||||
|  * - Small modifications to make it compile nicely at both Daniel's and |  | ||||||
|  *   Bjorn's place. |  | ||||||
|  * |  | ||||||
|  * v2.2 |  | ||||||
|  * - Made it work with text to the right of the last %! |  | ||||||
|  * - Introduced dprintf(), dsprintf() and dfprintf(). |  | ||||||
|  * - Float/double support enabled. This system is currently using the ordinary |  | ||||||
|  *   sprintf() function. NOTE that positional parameters, widths and precisions |  | ||||||
|  *   will still work like it should since the d-system takes care of that and |  | ||||||
|  *   passes that information re-formatted to the old sprintf(). |  | ||||||
|  * |  | ||||||
|  * v2.1 |  | ||||||
|  * - Fixed space padding (i.e %d was extra padded previously) |  | ||||||
|  * - long long output is supported |  | ||||||
|  * - alternate output is done correct like in %#08x |  | ||||||
|  * |  | ||||||
|  ****************************************************************************/ |  | ||||||
|  |  | ||||||
| #include "setup.h" | #include "setup.h" | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| @@ -100,6 +38,15 @@ | |||||||
| #include <ctype.h> | #include <ctype.h> | ||||||
| #include <string.h> | #include <string.h> | ||||||
|  |  | ||||||
|  | #ifndef SIZEOF_LONG_LONG | ||||||
|  | /* prevents warnings on picky compilers */ | ||||||
|  | #define SIZEOF_LONG_LONG 0 | ||||||
|  | #endif | ||||||
|  | #ifndef SIZEOF_LONG_DOUBLE | ||||||
|  | #define SIZEOF_LONG_DOUBLE 0 | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |  | ||||||
| /* The last #include file should be: */ | /* The last #include file should be: */ | ||||||
| #ifdef MALLOCDEBUG | #ifdef MALLOCDEBUG | ||||||
| #include "memdebug.h" | #include "memdebug.h" | ||||||
| @@ -752,9 +699,8 @@ static int dprintf_formatf( | |||||||
| #if SIZEOF_LONG_LONG | #if SIZEOF_LONG_LONG | ||||||
|       if(p->flags & FLAGS_LONGLONG) { |       if(p->flags & FLAGS_LONGLONG) { | ||||||
| 	 /* long long */ | 	 /* long long */ | ||||||
| 	num = p->data.lnum; | 	is_neg = p->data.lnum < 0; | ||||||
| 	is_neg = num < 0; | 	num = is_neg ? (- p->data.lnum) : p->data.lnum; | ||||||
| 	num = is_neg ? (- num) : num; |  | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
| #endif | #endif | ||||||
| @@ -1191,7 +1137,7 @@ int main() | |||||||
| { | { | ||||||
|   char buffer[129]; |   char buffer[129]; | ||||||
|   char *ptr; |   char *ptr; | ||||||
| #ifdef SIZEOF_LONG_LONG | #if SIZEOF_LONG_LONG>0 | ||||||
|   long long hullo; |   long long hullo; | ||||||
|   dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65); |   dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65); | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -44,12 +44,16 @@ | |||||||
|   o Enable the application to select() on its own file descriptors and curl's |   o Enable the application to select() on its own file descriptors and curl's | ||||||
|     file descriptors simultaneous easily. |     file descriptors simultaneous easily. | ||||||
|    |    | ||||||
|   Example source using this interface: http://curl.haxx.se/dev/multi-app.c |   Example sources using this interface is here: ../multi/ | ||||||
|  |  | ||||||
| */ | */ | ||||||
| #ifdef HAVE_SYS_SOCKET_H | #ifdef HAVE_SYS_SOCKET_H | ||||||
| #include <sys/socket.h> | #include <sys/socket.h> | ||||||
| #endif | #endif | ||||||
|  | #ifdef HAVE_WINSOCK_H | ||||||
|  | #include <winsock.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <curl/curl.h> | #include <curl/curl.h> | ||||||
|  |  | ||||||
| typedef void CURLM; | typedef void CURLM; | ||||||
|   | |||||||
| @@ -157,7 +157,7 @@ int Curl_parsenetrc(char *host, | |||||||
| 	  } | 	  } | ||||||
| 	  else if(state_password) { | 	  else if(state_password) { | ||||||
| 	    strncpy(password, tok, PASSWORDSIZE-1); | 	    strncpy(password, tok, PASSWORDSIZE-1); | ||||||
| #if _NETRC_DEBUG | #ifdef _NETRC_DEBUG | ||||||
| 	    printf("PASSWORD: %s\n", password); | 	    printf("PASSWORD: %s\n", password); | ||||||
| #endif | #endif | ||||||
| 	    state_password=0; | 	    state_password=0; | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								lib/sendf.c
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								lib/sendf.c
									
									
									
									
									
								
							| @@ -5,7 +5,7 @@ | |||||||
|  *                            | (__| |_| |  _ <| |___  |  *                            | (__| |_| |  _ <| |___  | ||||||
|  *                             \___|\___/|_| \_\_____| |  *                             \___|\___/|_| \_\_____| | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al. |  * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||||
|  * |  * | ||||||
|  * In order to be useful for every potential user, curl and libcurl are |  * In order to be useful for every potential user, curl and libcurl are | ||||||
|  * dual-licensed under the MPL and the MIT/X-derivate licenses. |  * dual-licensed under the MPL and the MIT/X-derivate licenses. | ||||||
| @@ -26,6 +26,8 @@ | |||||||
| #include <stdio.h> | #include <stdio.h> | ||||||
| #include <stdarg.h> | #include <stdarg.h> | ||||||
| #include <stdlib.h> | #include <stdlib.h> | ||||||
|  | #include <errno.h> | ||||||
|  |  | ||||||
| #ifdef HAVE_SYS_TYPES_H | #ifdef HAVE_SYS_TYPES_H | ||||||
| #include <sys/types.h> | #include <sys/types.h> | ||||||
| #endif | #endif | ||||||
| @@ -212,6 +214,7 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd, | |||||||
|       failf(conn->data, "SSL_write() return error %d\n", err); |       failf(conn->data, "SSL_write() return error %d\n", err); | ||||||
|       return CURLE_WRITE_ERROR; |       return CURLE_WRITE_ERROR; | ||||||
|     } |     } | ||||||
|  |     bytes_written = rc; | ||||||
|   } |   } | ||||||
|   else { |   else { | ||||||
| #endif | #endif | ||||||
| @@ -226,7 +229,7 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd, | |||||||
|     } |     } | ||||||
|     if(-1 == bytes_written) { |     if(-1 == bytes_written) { | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
|       if(EWOULDBLOCK == GetLastError()) |       if(WSAEWOULDBLOCK == GetLastError()) | ||||||
| #else | #else | ||||||
|       if(EWOULDBLOCK == errno) |       if(EWOULDBLOCK == errno) | ||||||
| #endif | #endif | ||||||
| @@ -307,7 +310,7 @@ int Curl_read(struct connectdata *conn, | |||||||
|     do { |     do { | ||||||
|       nread = SSL_read(conn->ssl.handle, buf, buffersize); |       nread = SSL_read(conn->ssl.handle, buf, buffersize); | ||||||
|  |  | ||||||
|       if(nread > 0) |       if(nread >= 0) | ||||||
|         /* successful read */ |         /* successful read */ | ||||||
|         break; |         break; | ||||||
|  |  | ||||||
| @@ -323,7 +326,7 @@ int Curl_read(struct connectdata *conn, | |||||||
|         /* if there's data pending, then we re-invoke SSL_read() */ |         /* if there's data pending, then we re-invoke SSL_read() */ | ||||||
|         break; |         break; | ||||||
|       } |       } | ||||||
|     } while(0); |     } while(loop); | ||||||
|     if(loop && SSL_pending(conn->ssl.handle)) |     if(loop && SSL_pending(conn->ssl.handle)) | ||||||
|       return -1; /* basicly EWOULDBLOCK */ |       return -1; /* basicly EWOULDBLOCK */ | ||||||
|   } |   } | ||||||
| @@ -338,7 +341,7 @@ int Curl_read(struct connectdata *conn, | |||||||
|  |  | ||||||
|     if(-1 == nread) { |     if(-1 == nread) { | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
|       if(EWOULDBLOCK == GetLastError()) |       if(WSAEWOULDBLOCK == GetLastError()) | ||||||
| #else | #else | ||||||
|       if(EWOULDBLOCK == errno) |       if(EWOULDBLOCK == errno) | ||||||
| #endif | #endif | ||||||
|   | |||||||
							
								
								
									
										13
									
								
								lib/setup.h
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								lib/setup.h
									
									
									
									
									
								
							| @@ -34,19 +34,19 @@ | |||||||
| #ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H | ||||||
|  |  | ||||||
| #ifdef VMS | #ifdef VMS | ||||||
| #include "../config-vms.h" | #include "config-vms.h" | ||||||
| #else | #else | ||||||
| #include "../config.h" /* the configure script results */ | #include "config.h" /* the configure script results */ | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #else | #else | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
| /* hand-modified win32 config.h! */ | /* hand-modified win32 config.h! */ | ||||||
| #include "../config-win32.h" | #include "config-win32.h" | ||||||
| #endif | #endif | ||||||
| #ifdef macintosh | #ifdef macintosh | ||||||
| /* hand-modified MacOS config.h! */ | /* hand-modified MacOS config.h! */ | ||||||
| #include "../config-mac.h" | #include "config-mac.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #endif | #endif | ||||||
| @@ -94,11 +94,12 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO) | |||||||
| #ifdef	VMS | #ifdef	VMS | ||||||
| #include "../include/curl/stdcheaders.h" | #include "../include/curl/stdcheaders.h" | ||||||
| #else | #else | ||||||
| #include "curl/stdcheaders.h" | #include <curl/stdcheaders.h> | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #else | #else | ||||||
| #ifdef _AIX | #ifdef _AIX | ||||||
| #include "curl/stdcheaders.h" | #include <curl/stdcheaders.h> | ||||||
| #endif | #endif | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										50
									
								
								lib/ssluse.c
									
									
									
									
									
								
							
							
						
						
									
										50
									
								
								lib/ssluse.c
									
									
									
									
									
								
							| @@ -43,6 +43,12 @@ | |||||||
| #include "memdebug.h" | #include "memdebug.h" | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
|  | #if OPENSSL_VERSION_NUMBER >= 0x0090581fL | ||||||
|  | #define HAVE_SSL_GET1_SESSION 1 | ||||||
|  | #else | ||||||
|  | #undef HAVE_SSL_GET1_SESSION | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #if OPENSSL_VERSION_NUMBER >= 0x00904100L | #if OPENSSL_VERSION_NUMBER >= 0x00904100L | ||||||
| #define HAVE_USERDATA_IN_PWD_CALLBACK 1 | #define HAVE_USERDATA_IN_PWD_CALLBACK 1 | ||||||
| #else | #else | ||||||
| @@ -74,10 +80,8 @@ static int passwd_callback(char *buf, int num, int verify | |||||||
| } | } | ||||||
|  |  | ||||||
| static | static | ||||||
| bool seed_enough(struct connectdata *conn, /* unused for now */ | bool seed_enough(int nread) | ||||||
|                  int nread) |  | ||||||
| { | { | ||||||
|   conn = NULL; /* to prevent compiler warnings */ |  | ||||||
| #ifdef HAVE_RAND_STATUS | #ifdef HAVE_RAND_STATUS | ||||||
|   nread = 0; /* to prevent compiler warnings */ |   nread = 0; /* to prevent compiler warnings */ | ||||||
|  |  | ||||||
| @@ -93,11 +97,10 @@ bool seed_enough(struct connectdata *conn, /* unused for now */ | |||||||
| } | } | ||||||
|  |  | ||||||
| static | static | ||||||
| int random_the_seed(struct connectdata *conn) | int random_the_seed(struct SessionHandle *data) | ||||||
| { | { | ||||||
|   char *buf = conn->data->state.buffer; /* point to the big buffer */ |   char *buf = data->state.buffer; /* point to the big buffer */ | ||||||
|   int nread=0; |   int nread=0; | ||||||
|   struct SessionHandle *data=conn->data; |  | ||||||
|  |  | ||||||
|   /* Q: should we add support for a random file name as a libcurl option? |   /* Q: should we add support for a random file name as a libcurl option? | ||||||
|      A: Yes, it is here */ |      A: Yes, it is here */ | ||||||
| @@ -113,7 +116,7 @@ int random_the_seed(struct connectdata *conn) | |||||||
|     nread += RAND_load_file((data->set.ssl.random_file? |     nread += RAND_load_file((data->set.ssl.random_file? | ||||||
|                              data->set.ssl.random_file:RANDOM_FILE), |                              data->set.ssl.random_file:RANDOM_FILE), | ||||||
|                             16384); |                             16384); | ||||||
|     if(seed_enough(conn, nread)) |     if(seed_enough(nread)) | ||||||
|       return nread; |       return nread; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -132,7 +135,7 @@ int random_the_seed(struct connectdata *conn) | |||||||
|     int ret = RAND_egd(data->set.ssl.egdsocket?data->set.ssl.egdsocket:EGD_SOCKET); |     int ret = RAND_egd(data->set.ssl.egdsocket?data->set.ssl.egdsocket:EGD_SOCKET); | ||||||
|     if(-1 != ret) { |     if(-1 != ret) { | ||||||
|       nread += ret; |       nread += ret; | ||||||
|       if(seed_enough(conn, nread)) |       if(seed_enough(nread)) | ||||||
|         return nread; |         return nread; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -164,11 +167,11 @@ int random_the_seed(struct connectdata *conn) | |||||||
|   if ( buf[0] ) { |   if ( buf[0] ) { | ||||||
|     /* we got a file name to try */ |     /* we got a file name to try */ | ||||||
|     nread += RAND_load_file(buf, 16384); |     nread += RAND_load_file(buf, 16384); | ||||||
|     if(seed_enough(conn, nread)) |     if(seed_enough(nread)) | ||||||
|       return nread; |       return nread; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   infof(conn->data, "Your connection is using a weak random seed!\n"); |   infof(data, "libcurl is now using a weak random seed!\n"); | ||||||
|   return nread; |   return nread; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -357,6 +360,10 @@ int cert_verify_callback(int ok, X509_STORE_CTX *ctx) | |||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
| /* "global" init done? */ | /* "global" init done? */ | ||||||
| static int init_ssl=0; | static int init_ssl=0; | ||||||
|  |  | ||||||
|  | /* we have the "SSL is seeded" boolean global for the application to | ||||||
|  |    prevent multiple time-consuming seedings in vain */ | ||||||
|  | static bool ssl_seeded = FALSE; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| /* Global init */ | /* Global init */ | ||||||
| @@ -558,11 +565,26 @@ static int Store_SSL_Session(struct connectdata *conn) | |||||||
|   int oldest_age=data->state.session[0].age; /* zero if unused */ |   int oldest_age=data->state.session[0].age; /* zero if unused */ | ||||||
|  |  | ||||||
|   /* ask OpenSSL, say please */ |   /* ask OpenSSL, say please */ | ||||||
|  |  | ||||||
|  | #ifdef HAVE_SSL_GET1_SESSION | ||||||
|   ssl_sessionid = SSL_get1_session(conn->ssl.handle); |   ssl_sessionid = SSL_get1_session(conn->ssl.handle); | ||||||
|  |  | ||||||
|   /* SSL_get1_session() will increment the reference |   /* SSL_get1_session() will increment the reference | ||||||
|      count and the session will stay in memory until explicitly freed with |      count and the session will stay in memory until explicitly freed with | ||||||
|      SSL_SESSION_free(3), regardless of its state. */ |      SSL_SESSION_free(3), regardless of its state.  | ||||||
|  |      This function was introduced in openssl 0.9.5a. */ | ||||||
|  | #else | ||||||
|  |   ssl_sessionid = SSL_get_session(conn->ssl.handle); | ||||||
|  |  | ||||||
|  |   /* if SSL_get1_session() is unavailable, use SSL_get_session(). | ||||||
|  |      This is an inferior option because the session can be flushed | ||||||
|  |      at any time by openssl. It is included only so curl compiles | ||||||
|  |      under versions of openssl < 0.9.5a. | ||||||
|  |       | ||||||
|  |      WARNING: How curl behaves if it's session is flushed is | ||||||
|  |      untested.  | ||||||
|  |   */ | ||||||
|  | #endif | ||||||
|  |  | ||||||
|   /* Now we should add the session ID and the host name to the cache, (remove |   /* Now we should add the session ID and the host name to the cache, (remove | ||||||
|      the oldest if necessary) */ |      the oldest if necessary) */ | ||||||
| @@ -656,8 +678,12 @@ Curl_SSLConnect(struct connectdata *conn) | |||||||
|   /* mark this is being ssl enabled from here on out. */ |   /* mark this is being ssl enabled from here on out. */ | ||||||
|   conn->ssl.use = TRUE; |   conn->ssl.use = TRUE; | ||||||
|  |  | ||||||
|  |   if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) { | ||||||
|     /* Make funny stuff to get random input */ |     /* Make funny stuff to get random input */ | ||||||
|   random_the_seed(conn); |     random_the_seed(data); | ||||||
|  |  | ||||||
|  |     ssl_seeded = TRUE; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   /* check to see if we've been told to use an explicit SSL/TLS version */ |   /* check to see if we've been told to use an explicit SSL/TLS version */ | ||||||
|   switch(data->set.ssl.version) { |   switch(data->set.ssl.version) { | ||||||
|   | |||||||
| @@ -193,7 +193,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|       if ((k->bytecount == 0) && (k->writebytecount == 0)) |       if ((k->bytecount == 0) && (k->writebytecount == 0)) | ||||||
|         Curl_pgrsTime(data, TIMER_STARTTRANSFER); |         Curl_pgrsTime(data, TIMER_STARTTRANSFER); | ||||||
|  |  | ||||||
|  |  | ||||||
|       didwhat |= KEEP_READ; |       didwhat |= KEEP_READ; | ||||||
|  |  | ||||||
|       /* NULL terminate, allowing string ops to be used */ |       /* NULL terminate, allowing string ops to be used */ | ||||||
| @@ -313,6 +312,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|               k->headerline = 0; /* restart the header line counter */ |               k->headerline = 0; /* restart the header line counter */ | ||||||
|               /* if we did wait for this do enable write now! */ |               /* if we did wait for this do enable write now! */ | ||||||
|               if (k->write_after_100_header) { |               if (k->write_after_100_header) { | ||||||
|  |  | ||||||
|                 k->write_after_100_header = FALSE; |                 k->write_after_100_header = FALSE; | ||||||
|                 FD_SET (conn->writesockfd, &k->writefd); /* write */ |                 FD_SET (conn->writesockfd, &k->writefd); /* write */ | ||||||
|                 k->keepon |= KEEP_WRITE; |                 k->keepon |= KEEP_WRITE; | ||||||
| @@ -356,10 +356,11 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|                * If we requested a "no body", this is a good time to get |                * If we requested a "no body", this is a good time to get | ||||||
|                * out and return home. |                * out and return home. | ||||||
|                */ |                */ | ||||||
|               if(data->set.no_body) |               bool stop_reading = FALSE; | ||||||
|                 return CURLE_OK; |  | ||||||
|  |  | ||||||
|               if(!conn->bits.close) { |               if(data->set.no_body) | ||||||
|  |                 stop_reading = TRUE; | ||||||
|  |               else if(!conn->bits.close) { | ||||||
|                 /* If this is not the last request before a close, we must |                 /* If this is not the last request before a close, we must | ||||||
|                    set the maximum download size to the size of the |                    set the maximum download size to the size of the | ||||||
|                    expected document or else, we won't know when to stop |                    expected document or else, we won't know when to stop | ||||||
| @@ -370,10 +371,20 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|                 /* If max download size is *zero* (nothing) we already |                 /* If max download size is *zero* (nothing) we already | ||||||
|                    have nothing and can safely return ok now! */ |                    have nothing and can safely return ok now! */ | ||||||
|                 if(0 == conn->maxdownload) |                 if(0 == conn->maxdownload) | ||||||
|                   return CURLE_OK; |                   stop_reading = TRUE; | ||||||
|                      |                      | ||||||
|                 /* What to do if the size is *not* known? */ |                 /* What to do if the size is *not* known? */ | ||||||
|               } |               } | ||||||
|  |  | ||||||
|  |               if(stop_reading) { | ||||||
|  |                 /* we make sure that this socket isn't read more now */ | ||||||
|  |                 k->keepon &= ~KEEP_READ; | ||||||
|  |                 FD_ZERO(&k->rkeepfd); | ||||||
|  |                 /* for a progress meter/info update before going away */ | ||||||
|  |                 Curl_pgrsUpdate(conn); | ||||||
|  |                 return CURLE_OK; | ||||||
|  |               } | ||||||
|  |  | ||||||
|               break;		/* exit header line loop */ |               break;		/* exit header line loop */ | ||||||
|             } |             } | ||||||
|  |  | ||||||
| @@ -457,6 +468,31 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|             conn->size = k->contentlength; |             conn->size = k->contentlength; | ||||||
|             Curl_pgrsSetDownloadSize(data, k->contentlength); |             Curl_pgrsSetDownloadSize(data, k->contentlength); | ||||||
|           } |           } | ||||||
|  |           /* check for Content-Type: header lines to get the mime-type */ | ||||||
|  |           else if (strnequal("Content-Type:", k->p, 13)) { | ||||||
|  |             char *start; | ||||||
|  |             char *end; | ||||||
|  |             int len; | ||||||
|  |  | ||||||
|  |             /* Find the first non-space letter */ | ||||||
|  |             for(start=k->p+14; | ||||||
|  |                 *start && isspace((int)*start); | ||||||
|  |                 start++); | ||||||
|  |  | ||||||
|  |             /* count all non-space letters following */ | ||||||
|  |             for(end=start, len=0; | ||||||
|  |                 *end && !isspace((int)*end); | ||||||
|  |                 end++, len++); | ||||||
|  |  | ||||||
|  |             /* allocate memory of a cloned copy */ | ||||||
|  |             data->info.contenttype = malloc(len + 1); | ||||||
|  |             if (NULL == data->info.contenttype) | ||||||
|  | 	      return CURLE_OUT_OF_MEMORY; | ||||||
|  |  | ||||||
|  |             /* copy the content-type string */ | ||||||
|  | 	    memcpy(data->info.contenttype, start, len); | ||||||
|  |             data->info.contenttype[len] = 0; /* zero terminate */ | ||||||
|  |           } | ||||||
|           else if((k->httpversion == 10) && |           else if((k->httpversion == 10) && | ||||||
|                   conn->bits.httpproxy && |                   conn->bits.httpproxy && | ||||||
|                   compareheader(k->p, "Proxy-Connection:", "keep-alive")) { |                   compareheader(k->p, "Proxy-Connection:", "keep-alive")) { | ||||||
| @@ -601,6 +637,8 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|             if (conn->newurl) { |             if (conn->newurl) { | ||||||
|               /* abort after the headers if "follow Location" is set */ |               /* abort after the headers if "follow Location" is set */ | ||||||
|               infof (data, "Follow to new URL: %s\n", conn->newurl); |               infof (data, "Follow to new URL: %s\n", conn->newurl); | ||||||
|  |                 k->keepon &= ~KEEP_READ; | ||||||
|  |                 FD_ZERO(&k->rkeepfd); | ||||||
|               return CURLE_OK; |               return CURLE_OK; | ||||||
|             } |             } | ||||||
|             else if (conn->resume_from && |             else if (conn->resume_from && | ||||||
| @@ -713,8 +751,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|         conn->upload_fromhere = k->uploadbuf; |         conn->upload_fromhere = k->uploadbuf; | ||||||
|  |  | ||||||
|         nread = data->set.fread(conn->upload_fromhere, 1, |         nread = data->set.fread(conn->upload_fromhere, 1, | ||||||
|                                 conn->upload_bufsize, |                                 BUFSIZE, data->set.in); | ||||||
|                                 data->set.in); |  | ||||||
|  |  | ||||||
|         /* the signed int typecase of nread of for systems that has |         /* the signed int typecase of nread of for systems that has | ||||||
|            unsigned size_t */ |            unsigned size_t */ | ||||||
| @@ -746,7 +783,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|       else { |       else { | ||||||
|         /* We have a partial buffer left from a previous "round". Use |         /* We have a partial buffer left from a previous "round". Use | ||||||
|            that instead of reading more data */ |            that instead of reading more data */ | ||||||
|  |  | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       /* write to socket */ |       /* write to socket */ | ||||||
| @@ -775,7 +811,7 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|         conn->upload_present = 0; /* no more bytes left */ |         conn->upload_present = 0; /* no more bytes left */ | ||||||
|       } |       } | ||||||
|  |  | ||||||
|       k->writebytecount += nread; |       k->writebytecount += bytes_written; | ||||||
|       Curl_pgrsSetUploadCounter(data, (double)k->writebytecount); |       Curl_pgrsSetUploadCounter(data, (double)k->writebytecount); | ||||||
|  |  | ||||||
|     } |     } | ||||||
| @@ -810,15 +846,6 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|   if (result) |   if (result) | ||||||
|     return result; |     return result; | ||||||
|      |      | ||||||
|   if(data->progress.ulspeed > conn->upload_bufsize) { |  | ||||||
|     /* If we're transfering more data per second than fits in our buffer, |  | ||||||
|        we increase the buffer size to adjust to the current |  | ||||||
|        speed. However, we must not set it larger than BUFSIZE. We don't |  | ||||||
|        adjust it downwards again since we don't see any point in that! |  | ||||||
|     */ |  | ||||||
|     conn->upload_bufsize=(long)min(data->progress.ulspeed, BUFSIZE); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|   if (data->set.timeout && |   if (data->set.timeout && | ||||||
|       ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) { |       ((Curl_tvdiff(k->now, k->start)/1000) >= data->set.timeout)) { | ||||||
|     failf (data, "Operation timed out with %d out of %d bytes received", |     failf (data, "Operation timed out with %d out of %d bytes received", | ||||||
| @@ -988,6 +1015,7 @@ Transfer(struct connectdata *conn) | |||||||
|     case 0:  /* timeout */ |     case 0:  /* timeout */ | ||||||
|       result = Curl_readwrite(conn, &done); |       result = Curl_readwrite(conn, &done); | ||||||
|       break; |       break; | ||||||
|  |  | ||||||
|     default: /* readable descriptors */ |     default: /* readable descriptors */ | ||||||
|       result = Curl_readwrite(conn, &done); |       result = Curl_readwrite(conn, &done); | ||||||
|       break; |       break; | ||||||
|   | |||||||
							
								
								
									
										10
									
								
								lib/url.c
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								lib/url.c
									
									
									
									
									
								
							| @@ -191,6 +191,9 @@ CURLcode Curl_close(struct SessionHandle *data) | |||||||
|   /* free the connection cache */ |   /* free the connection cache */ | ||||||
|   free(data->state.connects); |   free(data->state.connects); | ||||||
|  |  | ||||||
|  |   if(data->info.contenttype) | ||||||
|  |     free(data->info.contenttype); | ||||||
|  |  | ||||||
|   free(data); |   free(data); | ||||||
|   return CURLE_OK; |   return CURLE_OK; | ||||||
| } | } | ||||||
| @@ -559,8 +562,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...) | |||||||
|      * Set a custom string to use as request |      * Set a custom string to use as request | ||||||
|      */ |      */ | ||||||
|     data->set.customrequest = va_arg(param, char *); |     data->set.customrequest = va_arg(param, char *); | ||||||
|     if(data->set.customrequest) |  | ||||||
|  |     /* we don't set | ||||||
|        data->set.httpreq = HTTPREQ_CUSTOM; |        data->set.httpreq = HTTPREQ_CUSTOM; | ||||||
|  |        here, we continue as if we were using the already set type | ||||||
|  |        and this just changes the actual request keyword */ | ||||||
|     break; |     break; | ||||||
|   case CURLOPT_HTTPPOST: |   case CURLOPT_HTTPPOST: | ||||||
|     /* |     /* | ||||||
| @@ -1286,7 +1292,6 @@ static CURLcode CreateConnection(struct SessionHandle *data, | |||||||
|  |  | ||||||
|   /* and we setup a few fields in case we end up actually using this struct */ |   /* and we setup a few fields in case we end up actually using this struct */ | ||||||
|   conn->data = data;           /* remember our daddy */ |   conn->data = data;           /* remember our daddy */ | ||||||
|   conn->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */ |  | ||||||
|   conn->firstsocket = -1;     /* no file descriptor */ |   conn->firstsocket = -1;     /* no file descriptor */ | ||||||
|   conn->secondarysocket = -1; /* no file descriptor */ |   conn->secondarysocket = -1; /* no file descriptor */ | ||||||
|   conn->connectindex = -1;    /* no index */ |   conn->connectindex = -1;    /* no index */ | ||||||
| @@ -1979,6 +1984,7 @@ static CURLcode CreateConnection(struct SessionHandle *data, | |||||||
|  |  | ||||||
|     /* we need these pointers if we speak over a proxy */ |     /* we need these pointers if we speak over a proxy */ | ||||||
|     conn->hostname = old_conn->gname; |     conn->hostname = old_conn->gname; | ||||||
|  |     conn->name = old_conn->name; | ||||||
|  |  | ||||||
|     free(conn->path);    /* free the previously allocated path pointer */ |     free(conn->path);    /* free the previously allocated path pointer */ | ||||||
|  |  | ||||||
|   | |||||||
| @@ -85,11 +85,6 @@ | |||||||
| /* Download buffer size, keep it fairly big for speed reasons */ | /* Download buffer size, keep it fairly big for speed reasons */ | ||||||
| #define BUFSIZE (1024*20) | #define BUFSIZE (1024*20) | ||||||
|  |  | ||||||
| /* Defaul upload buffer size, keep it smallish to get faster progress meter |  | ||||||
|    updates. This is just default, it is dynamic and adjusts to the upload |  | ||||||
|    speed. */ |  | ||||||
| #define UPLOAD_BUFSIZE (1024*2) |  | ||||||
|  |  | ||||||
| /* Initial size of the buffer to store headers in, it'll be enlarged in case | /* Initial size of the buffer to store headers in, it'll be enlarged in case | ||||||
|    of need. */ |    of need. */ | ||||||
| #define HEADERSIZE 256 | #define HEADERSIZE 256 | ||||||
| @@ -317,10 +312,6 @@ struct connectdata { | |||||||
|   struct timeval created; /* creation time */ |   struct timeval created; /* creation time */ | ||||||
|   int firstsocket;     /* the main socket to use */ |   int firstsocket;     /* the main socket to use */ | ||||||
|   int secondarysocket; /* for i.e ftp transfers */ |   int secondarysocket; /* for i.e ftp transfers */ | ||||||
|  |  | ||||||
|   long upload_bufsize; /* adjust as you see fit, never bigger than BUFSIZE |  | ||||||
|                           never smaller than UPLOAD_BUFSIZE */ |  | ||||||
|  |  | ||||||
|   long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 |   long maxdownload; /* in bytes, the maximum amount of data to fetch, 0 | ||||||
|                        means unlimited */ |                        means unlimited */ | ||||||
|    |    | ||||||
| @@ -432,6 +423,8 @@ struct PureInfo { | |||||||
|                     the time was unretrievable */ |                     the time was unretrievable */ | ||||||
|   long header_size;  /* size of read header(s) in bytes */ |   long header_size;  /* size of read header(s) in bytes */ | ||||||
|   long request_size; /* the amount of bytes sent in the request(s) */ |   long request_size; /* the amount of bytes sent in the request(s) */ | ||||||
|  |  | ||||||
|  |   char *contenttype; /* the content type of the object */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -5,7 +5,7 @@ | |||||||
|  *                            | (__| |_| |  _ <| |___  |  *                            | (__| |_| |  _ <| |___  | ||||||
|  *                             \___|\___/|_| \_\_____| |  *                             \___|\___/|_| \_\_____| | ||||||
|  * |  * | ||||||
|  * Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al. |  * Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al. | ||||||
|  * |  * | ||||||
|  * In order to be useful for every potential user, curl and libcurl are |  * In order to be useful for every potential user, curl and libcurl are | ||||||
|  * dual-licensed under the MPL and the MIT/X-derivate licenses. |  * dual-licensed under the MPL and the MIT/X-derivate licenses. | ||||||
| @@ -38,20 +38,28 @@ char *curl_version(void) | |||||||
|  |  | ||||||
| #ifdef USE_SSLEAY | #ifdef USE_SSLEAY | ||||||
|  |  | ||||||
| #if (SSLEAY_VERSION_NUMBER >= 0x906000) | #if (SSLEAY_VERSION_NUMBER >= 0x905000) | ||||||
|   { |   { | ||||||
|     char sub[2]; |     char sub[2]; | ||||||
|  |     unsigned long ssleay_value; | ||||||
|     sub[1]='\0'; |     sub[1]='\0'; | ||||||
|     if(SSLEAY_VERSION_NUMBER&0xff0) { |     ssleay_value=SSLeay(); | ||||||
|       sub[0]=((SSLEAY_VERSION_NUMBER>>4)&0xff) + 'a' -1; |     if(ssleay_value < 0x906000) { | ||||||
|  |       ssleay_value=SSLEAY_VERSION_NUMBER; | ||||||
|  |       sub[0]='\0'; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       if(ssleay_value&0xff0) { | ||||||
|  |         sub[0]=((ssleay_value>>4)&0xff) + 'a' -1; | ||||||
|       } |       } | ||||||
|       else |       else | ||||||
|         sub[0]='\0'; |         sub[0]='\0'; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     sprintf(ptr, " (OpenSSL %lx.%lx.%lx%s)", |     sprintf(ptr, " (OpenSSL %lx.%lx.%lx%s)", | ||||||
|             (SSLEAY_VERSION_NUMBER>>28)&0xf, |             (ssleay_value>>28)&0xf, | ||||||
|             (SSLEAY_VERSION_NUMBER>>20)&0xff, |             (ssleay_value>>20)&0xff, | ||||||
|             (SSLEAY_VERSION_NUMBER>>12)&0xff, |             (ssleay_value>>12)&0xff, | ||||||
|             sub); |             sub); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -4,7 +4,7 @@ | |||||||
|  |  | ||||||
| INCLUDES = -I$(top_srcdir)/include | INCLUDES = -I$(top_srcdir)/include | ||||||
|  |  | ||||||
| bin_PROGRAMS = app single double | noinst_PROGRAMS = app single double | ||||||
|  |  | ||||||
| app_SOURCES = app.c | app_SOURCES = app.c | ||||||
| app_LDADD = ../lib/libcurl.la | app_LDADD = ../lib/libcurl.la | ||||||
|   | |||||||
| @@ -13,6 +13,7 @@ bin_PROGRAMS = curl #memtest | |||||||
| noinst_HEADERS = setup.h \ | noinst_HEADERS = setup.h \ | ||||||
| 	config-win32.h \ | 	config-win32.h \ | ||||||
| 	config-mac.h \ | 	config-mac.h \ | ||||||
|  | 	config-vms.h \ | ||||||
| 	urlglob.h \ | 	urlglob.h \ | ||||||
| 	version.h \ | 	version.h \ | ||||||
| 	writeout.h | 	writeout.h | ||||||
|   | |||||||
| @@ -1,10 +1,13 @@ | |||||||
| ######################################################## | ######################################################## | ||||||
| ## Makefile for building curl.exe with MSVC6 | ## Makefile for building curl.exe with MSVC6 | ||||||
| ## Use: nmake -f makefile.vc6 [release | debug] | ## Use: nmake -f makefile.vc6 [release | debug] [CFG=release-ssl] | ||||||
| ##      (default is release) | ##      (default is release) | ||||||
|  | ## "nmake -f makefile.vc6 CFG=release-ssl" statically links OpenSSL | ||||||
|  | ## into curl.exe producing a standalone SSL-enabled executable. | ||||||
| ## | ## | ||||||
| ## Comments to: Troy Engel <tengel@sonic.net> | ## Comments to: Troy Engel <tengel@sonic.net> | ||||||
| ## Updated by: Craig Davison <cd@securityfocus.com> | ## Updated by: Craig Davison <cd@securityfocus.com> | ||||||
|  | ## release-ssl added by Miklos Nemeth <mnemeth@kfkisystems.com> | ||||||
|  |  | ||||||
| PROGRAM_NAME = curl.exe | PROGRAM_NAME = curl.exe | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										21
									
								
								src/config-vms.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/config-vms.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | |||||||
|  | /* src/config.h.  Generated automatically by configure.  */ | ||||||
|  | /* Define cpu-machine-OS */ | ||||||
|  | #define OS "ALPHA-COMPAQ-VMS" | ||||||
|  |  | ||||||
|  | /* Define if you have the <unistd.h> header file.  */ | ||||||
|  | #define HAVE_UNISTD_H 1 | ||||||
|  |  | ||||||
|  | /* Define if you have the <io.h> header file.  */ | ||||||
|  | #undef HAVE_IO_H | ||||||
|  |  | ||||||
|  | /* Define if you have strdup() */ | ||||||
|  | #define HAVE_STRDUP 1 | ||||||
|  |  | ||||||
|  | /* Define if you have utime() */ | ||||||
|  | #undef HAVE_UTIME | ||||||
|  |  | ||||||
|  | /* Define if you have the <utime.h> header file */ | ||||||
|  | #undef HAVE_UTIME_H | ||||||
|  |  | ||||||
|  | /* Define if you have thhe <sys/utime.h> header file */ | ||||||
|  | #undef HAVE_SYS_UTIME_H | ||||||
| @@ -1450,10 +1450,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ | |||||||
|       GetStr(&config->proxy, nextarg); |       GetStr(&config->proxy, nextarg); | ||||||
|       break; |       break; | ||||||
|     case 'X': |     case 'X': | ||||||
|       /* HTTP request */ |       /* set custom request */ | ||||||
|       GetStr(&config->customrequest, nextarg); |       GetStr(&config->customrequest, nextarg); | ||||||
|       if(SetHTTPrequest(HTTPREQ_CUSTOM, &config->httpreq)) |  | ||||||
|         return PARAM_BAD_USE; |  | ||||||
|       break; |       break; | ||||||
|     case 'y': |     case 'y': | ||||||
|       /* low speed time */ |       /* low speed time */ | ||||||
|   | |||||||
| @@ -32,7 +32,11 @@ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
| #ifdef HAVE_CONFIG_H | #ifdef HAVE_CONFIG_H | ||||||
|  | #ifdef VMS | ||||||
|  | #include "config-vms.h" | ||||||
|  | #else | ||||||
| #include "config.h" /* the configure script results */ | #include "config.h" /* the configure script results */ | ||||||
|  | #endif | ||||||
| #else | #else | ||||||
| #ifdef WIN32 | #ifdef WIN32 | ||||||
| /* include the hand-modified win32 adjusted config.h! */ | /* include the hand-modified win32 adjusted config.h! */ | ||||||
|   | |||||||
| @@ -1,3 +1,3 @@ | |||||||
| #define CURL_NAME "curl" | #define CURL_NAME "curl" | ||||||
| #define CURL_VERSION "7.9.3-pre2" | #define CURL_VERSION "7.9.5-pre1" | ||||||
| #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " | #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " | ||||||
|   | |||||||
| @@ -26,7 +26,7 @@ simple HTTP GET | |||||||
|  <command> |  <command> | ||||||
| http://%HOSTIP:%HOSTPORT/1 | http://%HOSTIP:%HOSTPORT/1 | ||||||
| </command> | </command> | ||||||
| </test> | </client> | ||||||
|  |  | ||||||
| # | # | ||||||
| # Verify data after the test has been "shot" | # Verify data after the test has been "shot" | ||||||
|   | |||||||
| @@ -1,15 +1,6 @@ | |||||||
| #!/usr/bin/perl | #!/usr/bin/env perl | ||||||
| use Socket; |  | ||||||
| use Carp; |  | ||||||
| use FileHandle; |  | ||||||
|  |  | ||||||
| #use strict; | use strict; | ||||||
|  |  | ||||||
| require "getpart.pm"; |  | ||||||
|  |  | ||||||
| sub spawn;  # forward declaration |  | ||||||
| sub logmsg { #print "$0 $$: @_ at ", scalar localtime, "\n" |  | ||||||
|  } |  | ||||||
|  |  | ||||||
| my $verbose=0; # set to 1 for debugging | my $verbose=0; # set to 1 for debugging | ||||||
|  |  | ||||||
| @@ -23,204 +14,4 @@ do { | |||||||
|     } |     } | ||||||
| } while(shift @ARGV); | } while(shift @ARGV); | ||||||
|  |  | ||||||
| my $proto = getprotobyname('tcp') || 6; | exec("server/sws $port"); | ||||||
|  |  | ||||||
| socket(Server, PF_INET, SOCK_STREAM, $proto)|| die "socket: $!"; |  | ||||||
| setsockopt(Server, SOL_SOCKET, SO_REUSEADDR, |  | ||||||
|            pack("l", 1)) || die "setsockopt: $!"; |  | ||||||
| bind(Server, sockaddr_in($port, INADDR_ANY))|| die "bind: $!"; |  | ||||||
| listen(Server,SOMAXCONN) || die "listen: $!"; |  | ||||||
|  |  | ||||||
| if($verbose) { |  | ||||||
|     print "HTTP server started on port $port\n"; |  | ||||||
| } |  | ||||||
|  |  | ||||||
| open(PID, ">.http.pid"); |  | ||||||
| print PID $$; |  | ||||||
| close(PID); |  | ||||||
|  |  | ||||||
| my $PID=$$; |  | ||||||
|  |  | ||||||
| my $waitedpid = 0; |  | ||||||
| my $paddr; |  | ||||||
|  |  | ||||||
| sub REAPER { |  | ||||||
|     $waitedpid = wait; |  | ||||||
|     $SIG{CHLD} = \&REAPER;  # loathe sysV |  | ||||||
|     logmsg "reaped $waitedpid" . ($? ? " with exit $?" : ''); |  | ||||||
| } |  | ||||||
|  |  | ||||||
| sub performcmd { |  | ||||||
|     my @cmd = @_; |  | ||||||
|     for(@cmd) { |  | ||||||
|         if($_ =~ /^ *wait *(\d*)/) { |  | ||||||
|             # instructed to sleep! |  | ||||||
|             sleep($1); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  |  | ||||||
| $SIG{CHLD} = \&REAPER; |  | ||||||
|  |  | ||||||
| for ( $waitedpid = 0; |  | ||||||
|       ($paddr = accept(Client,Server)) || $waitedpid; |  | ||||||
|         $waitedpid = 0, close Client) |  | ||||||
| { |  | ||||||
|     next if $waitedpid and not $paddr; |  | ||||||
|     my($port,$iaddr) = sockaddr_in($paddr); |  | ||||||
|     my $name = gethostbyaddr($iaddr,AF_INET); |  | ||||||
|  |  | ||||||
|     logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port"; |  | ||||||
|  |  | ||||||
|     # this code is forked and run |  | ||||||
|     spawn sub { |  | ||||||
|         my ($request, $path, $ver, $left, $cl); |  | ||||||
|  |  | ||||||
|         my @headers; |  | ||||||
|  |  | ||||||
|         while(<STDIN>) { |  | ||||||
|             if($_ =~ /([A-Z]*) (.*) HTTP\/1.(\d)/) { |  | ||||||
|                 $request=$1; |  | ||||||
|                 $path=$2; |  | ||||||
|                 $ver=$3; |  | ||||||
|             } |  | ||||||
|             elsif($_ =~ /^Content-Length: (\d*)/) { |  | ||||||
|                 $cl=$1; |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             if($verbose) { |  | ||||||
|                 print STDERR "IN: $_"; |  | ||||||
|             } |  | ||||||
|              |  | ||||||
|             push @headers, $_; |  | ||||||
|  |  | ||||||
|             if($left > 0) { |  | ||||||
|                 $left -= length($_); |  | ||||||
|                 if($left == 0) { |  | ||||||
|                     $left = -1; # just to force a loop break here |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             # print STDERR "RCV ($left): $_"; |  | ||||||
|  |  | ||||||
|             if(!$left && |  | ||||||
|                ($_ eq "\r\n") or ($_ eq "")) { |  | ||||||
|                 if($request =~ /^(POST|PUT)$/) { |  | ||||||
|                     $left=$cl; |  | ||||||
|                 } |  | ||||||
|                 elsif($request =~ /^CONNECT$/) { |  | ||||||
|                     if($verbose) { |  | ||||||
|                         print STDERR "We're emulating a SSL proxy!\n"; |  | ||||||
|                     } |  | ||||||
|                     $left = -1; |  | ||||||
|                 } |  | ||||||
|                 else { |  | ||||||
|                     $left = -1; # force abort |  | ||||||
|                 } |  | ||||||
|             } |  | ||||||
|             if($left < 0) { |  | ||||||
|                 last; |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         if($request =~ /^CONNECT$/) { |  | ||||||
|             # ssl proxy mode |  | ||||||
|             print "HTTP/1.1 400 WE CANNOT ROOL NOW\r\n", |  | ||||||
|             "Server: bahoooba\r\n\r\n"; |  | ||||||
|             exit; |  | ||||||
|         } |  | ||||||
|         elsif($path =~ /verifiedserver/) { |  | ||||||
|             # this is a hard-coded query-string for the test script |  | ||||||
|             # to verify that this is the server actually running! |  | ||||||
|             print "HTTP/1.1 999 WE ROOLZ: $PID\r\n"; |  | ||||||
|             exit; |  | ||||||
|         } |  | ||||||
|         else { |  | ||||||
|  |  | ||||||
|             # |  | ||||||
|             # we always start the path with a number, this is the |  | ||||||
|             # test number that this server will use to know what |  | ||||||
|             # contents to pass back to the client |  | ||||||
|             # |  | ||||||
|             my $testnum; |  | ||||||
|             if($path =~ /.*\/(\d*)/) { |  | ||||||
|                 $testnum=$1; |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 $testnum=0; |  | ||||||
|             } |  | ||||||
|             open(INPUT, ">>log/server.input"); |  | ||||||
|  |  | ||||||
|             binmode(INPUT,":raw"); # this makes it work better on cygwin |  | ||||||
|  |  | ||||||
|             for(@headers) { |  | ||||||
|                 print INPUT $_; |  | ||||||
|             } |  | ||||||
|             close(INPUT); |  | ||||||
|              |  | ||||||
|             if(0 == $testnum ) { |  | ||||||
|                 print "HTTP/1.1 200 OK\r\n", |  | ||||||
|                 "header: yes\r\n", |  | ||||||
|                 "\r\n", |  | ||||||
|                 "You must enter a test number to get good data back\r\n"; |  | ||||||
|             } |  | ||||||
|             else { |  | ||||||
|                 my $part=""; |  | ||||||
|                 if($testnum > 10000) { |  | ||||||
|                     $part = $testnum % 10000; |  | ||||||
|                     $testnum = sprintf("%d", $testnum/10000); |  | ||||||
|                 } |  | ||||||
|                 if($verbose) { |  | ||||||
|                     print STDERR "OUT: sending reply $testnum (part $part)\n"; |  | ||||||
|                 } |  | ||||||
|  |  | ||||||
|                 loadtest("data/test$testnum"); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|                 my @cmd = getpart("reply", "cmd"); |  | ||||||
|                 performcmd(@cmd); |  | ||||||
|  |  | ||||||
|                 # flush data: |  | ||||||
|                 $| = 1; |  | ||||||
|  |  | ||||||
|                 # send a custom reply to the client |  | ||||||
|                 my @data = getpart("reply", "data$part"); |  | ||||||
|                 for(@data) { |  | ||||||
|                     print $_; |  | ||||||
|                     if($verbose) { |  | ||||||
|                         print STDERR "OUT: $_"; |  | ||||||
|                     } |  | ||||||
|                 } |  | ||||||
|                 my @postcmd = getpart("reply", "postcmd"); |  | ||||||
|                 performcmd(@postcmd); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|      #   print "Hello there, $name, it's now ", scalar localtime, "\r\n"; |  | ||||||
|     }; |  | ||||||
| } |  | ||||||
|  |  | ||||||
|  |  | ||||||
| sub spawn { |  | ||||||
|     my $coderef = shift; |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') { |  | ||||||
|         confess "usage: spawn CODEREF"; |  | ||||||
|     } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     my $pid; |  | ||||||
|     if (!defined($pid = fork)) { |  | ||||||
|         logmsg "cannot fork: $!"; |  | ||||||
|         return; |  | ||||||
|     } elsif ($pid) { |  | ||||||
|         logmsg "begat $pid"; |  | ||||||
|         return; # I'm the parent |  | ||||||
|     } |  | ||||||
|     # else I'm the child -- go spawn |  | ||||||
|  |  | ||||||
|  |  | ||||||
|     open(STDIN,  "<&Client")   || die "can't dup client to stdin"; |  | ||||||
|     open(STDOUT, ">&Client")   || die "can't dup client to stdout"; |  | ||||||
|     ## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr"; |  | ||||||
|     exit &$coderef(); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -22,7 +22,7 @@ my $FTPSPORT=8821;  # this is the FTPS server port | |||||||
| my $CURL="../src/curl"; # what curl executable to run on the tests | my $CURL="../src/curl"; # what curl executable to run on the tests | ||||||
| my $LOGDIR="log"; | my $LOGDIR="log"; | ||||||
| my $TESTDIR="data"; | my $TESTDIR="data"; | ||||||
| my $SERVERIN="$LOGDIR/server.input"; # what curl sent the server | my $SERVERIN="$LOGDIR/http-request.dump"; # what curl sent the server | ||||||
| my $CURLLOG="$LOGDIR/curl.log"; # all command lines run | my $CURLLOG="$LOGDIR/curl.log"; # all command lines run | ||||||
| my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy ftp server instructions here | my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy ftp server instructions here | ||||||
|  |  | ||||||
| @@ -835,6 +835,35 @@ if($testthis[0] ne "") { | |||||||
|     $TESTCASES=join(" ", @testthis); |     $TESTCASES=join(" ", @testthis); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | ############################################################################ | ||||||
|  | # | ||||||
|  | # don't let anyone think this works right now | ||||||
|  |  | ||||||
|  | print <<EOM | ||||||
|  |  *************************************************************************** | ||||||
|  |  | ||||||
|  |     THIS DOES NOT WORK | ||||||
|  |  | ||||||
|  |  *************************************************************************** | ||||||
|  |  | ||||||
|  |  Things in curl-land have changed, but the test suite has not been fixed | ||||||
|  |  accordingly and thus, the test suite is currently more or less useless. | ||||||
|  |  | ||||||
|  |  *PLEASE* help us fixing this. We have to make our new test server written | ||||||
|  |  in C work and get used instead of the perl version previously used. | ||||||
|  |  | ||||||
|  |  The working version of the test server is found in the tests/server | ||||||
|  |  directory in the CVS tree. | ||||||
|  |  | ||||||
|  |  If you run this in the tests/ directory and run the server in there, you | ||||||
|  |  can actually get test-responses if you do like this: | ||||||
|  |  | ||||||
|  |  \$ ./server/sws 8080 & | ||||||
|  |  \$ curl localhost:8080/3 | ||||||
|  |  | ||||||
|  | EOM | ||||||
|  |     ; | ||||||
|  |  | ||||||
|  |  | ||||||
| ####################################################################### | ####################################################################### | ||||||
| # Output curl version and host info being tested | # Output curl version and host info being tested | ||||||
|   | |||||||
							
								
								
									
										16
									
								
								tests/server/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								tests/server/Makefile
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,16 @@ | |||||||
|  | CC	= gcc | ||||||
|  | CFLAGS	= -g -Wall | ||||||
|  |  | ||||||
|  | .PHONY: all clean | ||||||
|  |  | ||||||
|  | TARGET = sws | ||||||
|  | OBJS= sws.o getpart.o | ||||||
|  |  | ||||||
|  | all: $(TARGET) | ||||||
|  |  | ||||||
|  | $(TARGET): $(OBJS) | ||||||
|  | 	$(CC) $(LDFLAGS) -o $@ $^ | ||||||
|  |  | ||||||
|  | clean: | ||||||
|  | 	-rm -f $(OBJS) *~ $(TARGET) core logfile | ||||||
|  |  | ||||||
							
								
								
									
										147
									
								
								tests/server/getpart.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										147
									
								
								tests/server/getpart.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,147 @@ | |||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <ctype.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  |  | ||||||
|  | #define EAT_SPACE(ptr) while( ptr && *ptr && isspace(*ptr) ) ptr++ | ||||||
|  | #define EAT_WORD(ptr) while( ptr && *ptr && !isspace(*ptr) && ('>' != *ptr)) ptr++ | ||||||
|  |  | ||||||
|  | char *appendstring(char *string, /* original string */ | ||||||
|  |                    char *buffer, /* to append */ | ||||||
|  |                    int *stringlen, int *stralloc) | ||||||
|  | { | ||||||
|  |   int len = strlen(buffer); | ||||||
|  |  | ||||||
|  |   if((len + *stringlen) > *stralloc) { | ||||||
|  |     char *newptr= realloc(string, *stralloc*2); | ||||||
|  |     if(newptr) { | ||||||
|  |       string = newptr; | ||||||
|  |       *stralloc *= 2; | ||||||
|  |     } | ||||||
|  |     else | ||||||
|  |       return NULL; | ||||||
|  |   } | ||||||
|  |   strcpy(&string[*stringlen], buffer); | ||||||
|  |   *stringlen += len; | ||||||
|  |  | ||||||
|  |   return string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | char *spitout(FILE *stream, char *main, char *sub, int *size) | ||||||
|  | { | ||||||
|  |   char buffer[8192]; /* big enough for anything */ | ||||||
|  |   char cmain[128]=""; /* current main section */ | ||||||
|  |   char csub[128]="";  /* current sub section */ | ||||||
|  |   char *ptr; | ||||||
|  |   char *end; | ||||||
|  |   char display = 0; | ||||||
|  |  | ||||||
|  |   char *string; | ||||||
|  |   int stringlen=0; | ||||||
|  |   int stralloc=256; | ||||||
|  |   int len; | ||||||
|  |  | ||||||
|  |   enum { | ||||||
|  |     STATE_OUTSIDE, | ||||||
|  |     STATE_INMAIN, | ||||||
|  |     STATE_INSUB, | ||||||
|  |     STATE_ILLEGAL | ||||||
|  |   } state = STATE_OUTSIDE; | ||||||
|  |  | ||||||
|  |   string = (char *)malloc(stralloc); | ||||||
|  |    | ||||||
|  |   while(fgets(buffer, sizeof(buffer), stream)) { | ||||||
|  |  | ||||||
|  |     ptr = buffer; | ||||||
|  |  | ||||||
|  |     /* pass white spaces */ | ||||||
|  |     EAT_SPACE(ptr); | ||||||
|  |  | ||||||
|  |     if('<' != *ptr) { | ||||||
|  |       if(display) { | ||||||
|  |         printf("=> %s", buffer); | ||||||
|  |         string = appendstring(string, buffer, &stringlen, &stralloc); | ||||||
|  |         printf("* %s\n", buffer); | ||||||
|  |       } | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ptr++; | ||||||
|  |     EAT_SPACE(ptr); | ||||||
|  |  | ||||||
|  |     if('/' == *ptr) { | ||||||
|  |       /* end of a section */ | ||||||
|  |       ptr++; | ||||||
|  |       EAT_SPACE(ptr); | ||||||
|  |  | ||||||
|  |       end = ptr; | ||||||
|  |       EAT_WORD(end); | ||||||
|  |       *end = 0; | ||||||
|  |  | ||||||
|  |       if((state == STATE_INSUB) && | ||||||
|  |          !strcmp(csub, ptr)) { | ||||||
|  |         /* this is the end of the currently read sub section */ | ||||||
|  |         state--; | ||||||
|  |         csub[0]=0; /* no sub anymore */ | ||||||
|  |         display=0; | ||||||
|  |       } | ||||||
|  |       else if((state == STATE_INMAIN) && | ||||||
|  |               !strcmp(cmain, ptr)) { | ||||||
|  |         /* this is the end of the currently read main section */ | ||||||
|  |         state--; | ||||||
|  |         cmain[0]=0; /* no main anymore */ | ||||||
|  |         display=0; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     else if(!display) { | ||||||
|  |       /* this is the beginning of a section */ | ||||||
|  |       end = ptr; | ||||||
|  |       EAT_WORD(end); | ||||||
|  |        | ||||||
|  |       *end = 0; | ||||||
|  |       switch(state) { | ||||||
|  |       case STATE_OUTSIDE: | ||||||
|  |         strcpy(cmain, ptr); | ||||||
|  |         state = STATE_INMAIN; | ||||||
|  |         break; | ||||||
|  |       case STATE_INMAIN: | ||||||
|  |         strcpy(csub, ptr); | ||||||
|  |         state = STATE_INSUB; | ||||||
|  |         break; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     if(display) { | ||||||
|  |       string = appendstring(string, buffer, &stringlen, &stralloc); | ||||||
|  |       printf("* %s\n", buffer); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if((STATE_INSUB == state) && | ||||||
|  |        !strcmp(cmain, main) && | ||||||
|  |        !strcmp(csub, sub)) { | ||||||
|  |       printf("* (%d bytes) %s\n", stringlen, buffer); | ||||||
|  |       display = 1; /* start displaying */ | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       printf("%d (%s/%s): %s\n", state, cmain, csub, buffer); | ||||||
|  |       display = 0; /* no display */ | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   *size = stringlen; | ||||||
|  |   return string; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | #ifdef TEST | ||||||
|  | int main(int argc, char **argv) | ||||||
|  | { | ||||||
|  |   if(argc< 3) { | ||||||
|  |     printf("./moo main sub\n"); | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     int size; | ||||||
|  |     char *buffer = spitout(stdin, argv[1], argv[2], &size); | ||||||
|  |   } | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  | #endif | ||||||
							
								
								
									
										343
									
								
								tests/server/sws.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										343
									
								
								tests/server/sws.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,343 @@ | |||||||
|  | /* sws.c: simple (silly?) web server */ | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <signal.h> | ||||||
|  | #include <getopt.h> | ||||||
|  | #include <sys/time.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/wait.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <netdb.h> | ||||||
|  | #include <assert.h> | ||||||
|  |  | ||||||
|  | #define DEFAULT_PORT 8999 | ||||||
|  |  | ||||||
|  | #ifndef DEFAULT_LOGFILE | ||||||
|  | #define DEFAULT_LOGFILE "/dev/null" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define DOCBUFSIZE 4 | ||||||
|  | #define BUFFERSIZE (DOCBUFSIZE * 1024) | ||||||
|  |  | ||||||
|  | #define VERSION "cURL test suite HTTP server/0.1" | ||||||
|  |  | ||||||
|  | #define REQUEST_DUMP "http-request.dump" | ||||||
|  |  | ||||||
|  | #define TEST_DATA_PATH "data/test%d" | ||||||
|  |  | ||||||
|  | static char *docfriends = "WE ROOLZ\r\n"; | ||||||
|  | static char *doc404 = "HTTP/1.1 404 Not Found\n" | ||||||
|  |     "Server: " VERSION "\n" | ||||||
|  |     "Connection: close\n" | ||||||
|  |     "Content-Type: text/html\n" | ||||||
|  |     "\n" | ||||||
|  |     "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n" | ||||||
|  |     "<HTML><HEAD>\n" | ||||||
|  |     "<TITLE>404 Not Found</TITLE>\n" | ||||||
|  |     "</HEAD><BODY>\n" | ||||||
|  |     "<H1>Not Found</H1>\n" | ||||||
|  |     "The requested URL was not found on this server.\n" | ||||||
|  |     "<P><HR><ADDRESS>" VERSION "</ADDRESS>\n" "</BODY></HTML>\n"; | ||||||
|  |  | ||||||
|  | static volatile int sigpipe, sigterm; | ||||||
|  | static FILE *logfp; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void logmsg(const char *msg) | ||||||
|  | { | ||||||
|  |     time_t t = time(NULL); | ||||||
|  |     struct tm *curr_time = localtime(&t); | ||||||
|  |     char loctime[80]; | ||||||
|  |  | ||||||
|  |     strcpy(loctime, asctime(curr_time)); | ||||||
|  |     loctime[strlen(loctime) - 1] = '\0'; | ||||||
|  |     fprintf(logfp, "%s: pid %d: %s\n", loctime, getpid(), msg); | ||||||
|  |     fprintf(stderr, "%s: pid %d: %s\n", loctime, getpid(), msg); | ||||||
|  |     fflush(logfp); | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void sigpipe_handler(int sig) | ||||||
|  | { | ||||||
|  |     sigpipe = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static void sigterm_handler(int sig) | ||||||
|  | { | ||||||
|  |     char logbuf[100]; | ||||||
|  |     snprintf(logbuf, 100, "Got signal %d, terminating", sig); | ||||||
|  |     logmsg(logbuf); | ||||||
|  |     sigterm = 1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int ProcessRequest(char *request) | ||||||
|  | { | ||||||
|  |   char *line=request; | ||||||
|  |   long contentlength=-1; | ||||||
|  |  | ||||||
|  | #define END_OF_HEADERS "\r\n\r\n" | ||||||
|  |  | ||||||
|  |   char *end; | ||||||
|  |   end = strstr(request, END_OF_HEADERS); | ||||||
|  |  | ||||||
|  |   if(!end) | ||||||
|  |     /* we don't have a complete request yet! */ | ||||||
|  |     return 0; | ||||||
|  |  | ||||||
|  |   /* **** Persistancy **** | ||||||
|  |    * | ||||||
|  |    * If the request is a HTTP/1.0 one, we close the connection unconditionally | ||||||
|  |    * when we're done. | ||||||
|  |    * | ||||||
|  |    * If the request is a HTTP/1.1 one, we MUST check for a "Connection:" | ||||||
|  |    * header that might say "close". If it does, we close a connection when | ||||||
|  |    * this request is processed. Otherwise, we keep the connection alive for X | ||||||
|  |    * seconds. | ||||||
|  |    */ | ||||||
|  |  | ||||||
|  |   do { | ||||||
|  |     if(!strncasecmp("Content-Length:", line, 15)) | ||||||
|  |       contentlength = strtol(line+15, &line, 10); | ||||||
|  |  | ||||||
|  |     line = strchr(line, '\n'); | ||||||
|  |     if(line) | ||||||
|  |       line++; | ||||||
|  |   } while(line); | ||||||
|  |  | ||||||
|  |   if(contentlength > -1 ) { | ||||||
|  |     if(contentlength <= strlen(end+strlen(END_OF_HEADERS))) | ||||||
|  |       return 1; /* done */ | ||||||
|  |     else | ||||||
|  |       return 0; /* not complete yet */ | ||||||
|  |   } | ||||||
|  |   return 1; /* done */ | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /* store the entire request in a file */ | ||||||
|  | void storerequest(char *reqbuf) | ||||||
|  | { | ||||||
|  |   FILE *dump; | ||||||
|  |  | ||||||
|  |   dump = fopen(REQUEST_DUMP, "wb"); /* b is for windows-preparing */ | ||||||
|  |   if(dump) { | ||||||
|  |     fwrite(reqbuf, 1, strlen(reqbuf), dump); | ||||||
|  |  | ||||||
|  |     fclose(dump); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define REQBUFSIZ 4096 | ||||||
|  | #define MAXDOCNAMELEN 1024 | ||||||
|  | #define REQUEST_KEYWORD_SIZE 256 | ||||||
|  | static int get_request(int sock) | ||||||
|  | { | ||||||
|  |   char reqbuf[REQBUFSIZ], doc[MAXDOCNAMELEN]; | ||||||
|  |   char request[REQUEST_KEYWORD_SIZE]; | ||||||
|  |   unsigned int offset = 0; | ||||||
|  |   int prot_major, prot_minor; | ||||||
|  |  | ||||||
|  |   while (offset < REQBUFSIZ) { | ||||||
|  |     int got = recv(sock, reqbuf + offset, REQBUFSIZ - offset, 0); | ||||||
|  |     if (got <= 0) { | ||||||
|  |       if (got < 0) { | ||||||
|  |         perror("recv"); | ||||||
|  |         return -1; | ||||||
|  |       } | ||||||
|  |       logmsg("Connection closed by client"); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |     offset += got; | ||||||
|  |  | ||||||
|  |     reqbuf[offset] = 0; | ||||||
|  |  | ||||||
|  |     if(ProcessRequest(reqbuf)) | ||||||
|  |       break; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   if (offset >= REQBUFSIZ) { | ||||||
|  |     logmsg("Request buffer overflow, closing connection"); | ||||||
|  |     return -1; | ||||||
|  |   } | ||||||
|  |   reqbuf[offset]=0; | ||||||
|  |    | ||||||
|  |   logmsg("Received a request"); | ||||||
|  |  | ||||||
|  |   /* dump the request to an external file */ | ||||||
|  |   storerequest(reqbuf); | ||||||
|  |  | ||||||
|  |   if (sscanf(reqbuf, "%s %s HTTP/%d.%d", | ||||||
|  |              request, | ||||||
|  |              doc, | ||||||
|  |              &prot_major, | ||||||
|  |              &prot_minor) == 4) { | ||||||
|  |     char *ptr; | ||||||
|  |     int test_no=0; | ||||||
|  |  | ||||||
|  |     /* find the last slash */ | ||||||
|  |     ptr = strrchr(doc, '/'); | ||||||
|  |  | ||||||
|  |     /* get the number after it */ | ||||||
|  |     if(ptr) { | ||||||
|  |       if(!strcmp("/verifiedserver", ptr)) { | ||||||
|  |         logmsg("Are-we-friendly question received"); | ||||||
|  |         return -2; | ||||||
|  |       } | ||||||
|  |       test_no = strtol(ptr+1, &ptr, 10); | ||||||
|  |  | ||||||
|  |       logmsg("Found test number in PATH"); | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |  | ||||||
|  |       logmsg("Did not find test number in PATH"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return test_no; | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   logmsg("Got illegal request"); | ||||||
|  |   fprintf(stderr, "Got illegal request\n"); | ||||||
|  |   return -1; | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | static int send_doc(int sock, int doc) | ||||||
|  | { | ||||||
|  |   int written; | ||||||
|  |   int count; | ||||||
|  |   char *buffer; | ||||||
|  |   char *ptr; | ||||||
|  |   FILE *stream; | ||||||
|  |  | ||||||
|  |   char filename[256]; | ||||||
|  |  | ||||||
|  |   if(doc < 0) { | ||||||
|  |     if(-2 == doc) | ||||||
|  |       /* we got a "friends?" question, reply back that we sure are */ | ||||||
|  |       buffer = docfriends; | ||||||
|  |     else | ||||||
|  |       buffer = doc404; | ||||||
|  |     ptr = NULL; | ||||||
|  |     stream=NULL; | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     sprintf(filename, TEST_DATA_PATH, doc); | ||||||
|  |  | ||||||
|  |     stream=fopen(filename, "rb"); | ||||||
|  |     if(!stream) { | ||||||
|  |       logmsg("Couldn't open test file"); | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     ptr = buffer = spitout(stream, "reply", "data", &count); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   do { | ||||||
|  |     written = send(sock, buffer, count, 0); | ||||||
|  |     if (written < 0) { | ||||||
|  |       fclose(stream); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |     count -= written; | ||||||
|  |     buffer += written; | ||||||
|  |   } while(count>0); | ||||||
|  |  | ||||||
|  |   if(ptr) | ||||||
|  |     free(ptr); | ||||||
|  |   if(stream) | ||||||
|  |     fclose(stream); | ||||||
|  |  | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | int main(int argc, char *argv[]) | ||||||
|  | { | ||||||
|  |     struct sockaddr_in me; | ||||||
|  |     int sock, msgsock, flag; | ||||||
|  |     unsigned short port = DEFAULT_PORT; | ||||||
|  |     char *logfile = DEFAULT_LOGFILE; | ||||||
|  |      | ||||||
|  |     if(argc>1) | ||||||
|  |       port = atoi(argv[1]); | ||||||
|  |  | ||||||
|  |     logfile = "logfile"; | ||||||
|  |  | ||||||
|  |     /* FIX: write our pid to a file name */ | ||||||
|  |  | ||||||
|  |     logfp = fopen(logfile, "a"); | ||||||
|  |     if (!logfp) { | ||||||
|  | 	perror(logfile); | ||||||
|  | 	exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     signal(SIGPIPE, sigpipe_handler); | ||||||
|  |     signal(SIGINT, sigterm_handler); | ||||||
|  |     signal(SIGTERM, sigterm_handler); | ||||||
|  |  | ||||||
|  |     siginterrupt(SIGPIPE, 1); | ||||||
|  |     siginterrupt(SIGINT, 1); | ||||||
|  |     siginterrupt(SIGTERM, 1); | ||||||
|  |  | ||||||
|  |     sock = socket(AF_INET, SOCK_STREAM, 0); | ||||||
|  |     if (sock < 0) { | ||||||
|  | 	perror("opening stream socket"); | ||||||
|  | 	fprintf(logfp, "Error opening socket -- aborting\n"); | ||||||
|  | 	fclose(logfp); | ||||||
|  | 	exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     flag = 1; | ||||||
|  |     if (setsockopt | ||||||
|  | 	(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag, | ||||||
|  | 	 sizeof(int)) < 0) { | ||||||
|  | 	perror("setsockopt(SO_REUSEADDR)"); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     me.sin_family = AF_INET; | ||||||
|  |     me.sin_addr.s_addr = INADDR_ANY; | ||||||
|  |     me.sin_port = htons(port); | ||||||
|  |     if (bind(sock, (struct sockaddr *) &me, sizeof me) < 0) { | ||||||
|  | 	perror("binding stream socket"); | ||||||
|  | 	fprintf(logfp, "Error binding socket -- aborting\n"); | ||||||
|  | 	fclose(logfp); | ||||||
|  | 	exit(1); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* start accepting connections */ | ||||||
|  |     listen(sock, 5); | ||||||
|  |  | ||||||
|  |     printf("*** %s listening on port %u ***\n", VERSION, port); | ||||||
|  |  | ||||||
|  |     while (!sigterm) { | ||||||
|  |       int doc; | ||||||
|  |  | ||||||
|  |       msgsock = accept(sock, NULL, NULL); | ||||||
|  |        | ||||||
|  |       if (msgsock == -1) { | ||||||
|  |         if (sigterm) { | ||||||
|  |           break; | ||||||
|  |         } | ||||||
|  |         /* perror("accept"); */ | ||||||
|  |         continue; | ||||||
|  |       } | ||||||
|  |        | ||||||
|  |       logmsg("New client connected"); | ||||||
|  |  | ||||||
|  |       doc = get_request(msgsock); | ||||||
|  |       send_doc(msgsock, doc); | ||||||
|  |  | ||||||
|  |       close(msgsock); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     close(sock); | ||||||
|  |     fclose(logfp); | ||||||
|  |  | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user