Compare commits
	
		
			114 Commits
		
	
	
		
			curl-7_9_3
			...
			curl-7_9_5
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | d9c244278d | ||
|   | b6c4185b27 | ||
|   | 5896d35e72 | ||
|   | b4dfdd8bbc | ||
|   | e6ed3478ea | ||
|   | db08d9c6b9 | ||
|   | 9490278ece | ||
|   | fd8bf5f171 | ||
|   | c9bc14a222 | ||
|   | 63708cbfb0 | ||
|   | d9f307623c | ||
|   | 540f77a627 | ||
|   | 71bb2d0b8b | ||
|   | 87dc44e434 | ||
|   | 29e0fcd091 | ||
|   | 2e9a798f09 | ||
|   | b32a39f44f | ||
|   | d86f9611b3 | ||
|   | 6a62fc4a40 | ||
|   | 7cdd6455d7 | ||
|   | e4fefd088d | ||
|   | 95e601e2b1 | ||
|   | b1ffe7b74a | ||
|   | 417c8fb602 | ||
|   | 85efa64c31 | ||
|   | d8cb026e80 | ||
|   | 41dd5121f0 | ||
|   | 94482d7ca5 | ||
|   | 4d0e51aead | ||
|   | ae8a8c8ba4 | ||
|   | 7d043f46d5 | ||
|   | cbca19d6c2 | ||
|   | 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 | 
							
								
								
									
										179
									
								
								CHANGES
									
									
									
									
									
								
							
							
						
						
									
										179
									
								
								CHANGES
									
									
									
									
									
								
							| @@ -6,6 +6,185 @@ | |||||||
|  |  | ||||||
|                                History of Changes |                                History of Changes | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Daniel (25 February 2002) | ||||||
|  | - Fiddled with the automake files to make all source files in the lib | ||||||
|  |   directory not have ../src in the include path, and the src sources shouldn't | ||||||
|  |   have ../lib! | ||||||
|  |  | ||||||
|  | - All 79 test cases ran OK under Linux and Solaris using the new HTTP server | ||||||
|  |   in the test suite. The new HTTP server was first donated by Georg Horn and | ||||||
|  |   subsequently modified to work with the test suite. It is currently still not | ||||||
|  |   portable enough to run on "all over" but this is a start and I can run all | ||||||
|  |   curl tests on my machines. This is an important requirement for the upcoming | ||||||
|  |   public release. | ||||||
|  |  | ||||||
|  | - Using -d and -I on the same command line now reports an error, as it implies | ||||||
|  |   two different HTTP requests that can't be mixed. | ||||||
|  |  | ||||||
|  | - Jeffrey Pohlmeyer provided a patch that made the -w/--write-out option | ||||||
|  |   support %{content_type} to get the content type of the recent download. | ||||||
|  |  | ||||||
|  | - Kevin Roth reported that pre2 and pre3 didn't compile properly on cygwin, | ||||||
|  |   and this was because I used #ifdef HAVE_WINSOCK_H in lib/multi.h to figure | ||||||
|  |   out if we could include winsock.h which turns out not to be a wise choice to | ||||||
|  |   do on cygwin since it has the file but can't include it! | ||||||
|  |  | ||||||
|  | Daniel (22 February 2002) | ||||||
|  | - Added src/config-vms.h to the release archive. | ||||||
|  |  | ||||||
|  | - Fixed the connection timeout value again, the change from February 18 wasn't | ||||||
|  |   complete. | ||||||
|  |  | ||||||
|  | Version 7.9.5-pre3 | ||||||
|  |  | ||||||
|  | Daniel (21 February 2002) | ||||||
|  | - Kevin Roth and Andr<64>s Garc<72>a both found out that lib/config.h.in was missing | ||||||
|  |   in the pre-release archive and thus the configure script failed. | ||||||
|  |  | ||||||
|  | Version 7.9.5-pre2 | ||||||
|  |  | ||||||
|  | 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 | Version 7.9.3 | ||||||
|  |  | ||||||
| Daniel (23 January 2002) | Daniel (23 January 2002) | ||||||
|   | |||||||
| @@ -2,12 +2,11 @@ | |||||||
| # $Id$ | # $Id$ | ||||||
| # | # | ||||||
|  |  | ||||||
| AUTOMAKE_OPTIONS = foreign no-dependencies | AUTOMAKE_OPTIONS = foreign | ||||||
|  |  | ||||||
| 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 | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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. | ||||||
| @@ -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 tests/server/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` | ||||||
| @@ -601,6 +601,7 @@ AC_CONFIG_FILES([Makefile \ | |||||||
|            lib/Makefile \ |            lib/Makefile \ | ||||||
|            tests/Makefile \ |            tests/Makefile \ | ||||||
|            tests/data/Makefile \ |            tests/data/Makefile \ | ||||||
|  |            tests/server/Makefile \ | ||||||
| 	   packages/Makefile \ | 	   packages/Makefile \ | ||||||
| 	   packages/Win32/Makefile \ | 	   packages/Win32/Makefile \ | ||||||
| 	   packages/Win32/cygwin/Makefile \ | 	   packages/Win32/cygwin/Makefile \ | ||||||
|   | |||||||
							
								
								
									
										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: | ||||||
|   | |||||||
							
								
								
									
										35
									
								
								docs/TODO
									
									
									
									
									
								
							
							
						
						
									
										35
									
								
								docs/TODO
									
									
									
									
									
								
							| @@ -49,8 +49,8 @@ TODO | |||||||
|    very long time idle connections. |    very long time idle connections. | ||||||
|  |  | ||||||
|  * Make sure we don't ever loop because of non-blocking sockets return |  * Make sure we don't ever loop because of non-blocking sockets return | ||||||
|    EWOULDBLOCK or similar. This concerns the HTTP request sending, the FTP |    EWOULDBLOCK or similar. This concerns the HTTP request sending (and | ||||||
|    command sending etc. |    especially regular HTTP POST), the FTP command sending etc. | ||||||
|  |  | ||||||
|  * Go through the code and verify that libcurl deals with big files >2GB and |  * 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 |    >4GB all over. Bug reports indicate that it doesn't currently work | ||||||
| @@ -83,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 | ||||||
| @@ -127,6 +133,14 @@ TODO | |||||||
|  |  | ||||||
|  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 | ||||||
| @@ -135,6 +149,11 @@ TODO | |||||||
|    idea might become moot if we enable the 'data sharing' as mentioned in the |    idea might become moot if we enable the 'data sharing' as mentioned in the | ||||||
|    LIBCURL label above. |    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 | ||||||
| @@ -159,6 +178,18 @@ TODO | |||||||
|    make sure that happens. It should of course not make more than one |    make sure that happens. It should of course not make more than one | ||||||
|    connection to the same remote host. |    connection to the same remote host. | ||||||
|  |  | ||||||
|  |  * 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 | ||||||
|  |  | ||||||
|  * Extend the test suite to include more protocols. The telnet could just do |  * Extend the test suite to include more protocols. The telnet could just do | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								docs/curl.1
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								docs/curl.1
									
									
									
									
									
								
							| @@ -2,7 +2,7 @@ | |||||||
| .\" nroff -man curl.1 | .\" nroff -man curl.1 | ||||||
| .\" Written by Daniel Stenberg | .\" Written by Daniel Stenberg | ||||||
| .\" | .\" | ||||||
| .TH curl 1 "30 Nov 2001" "Curl 7.9.2" "Curl Manual" | .TH curl 1 "25 Feb 2002" "Curl 7.9.5" "Curl Manual" | ||||||
| .SH NAME | .SH NAME | ||||||
| curl \- transfer a URL | curl \- transfer a URL | ||||||
| .SH SYNOPSIS | .SH SYNOPSIS | ||||||
| @@ -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: | ||||||
| @@ -594,6 +594,9 @@ The average download speed that curl measured for the complete download. | |||||||
| .TP | .TP | ||||||
| .B speed_upload | .B speed_upload | ||||||
| The average upload speed that curl measured for the complete upload. | The average upload speed that curl measured for the complete upload. | ||||||
|  | .TP | ||||||
|  | .B content_type | ||||||
|  | The Content-Type of the requested document, if there was any. (Added in 7.9.5) | ||||||
| .RE | .RE | ||||||
|  |  | ||||||
| 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. | ||||||
| @@ -788,7 +791,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; |  | ||||||
| } |  | ||||||
| @@ -11,8 +11,8 @@ 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 | ||||||
|  approaches 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. | ||||||
| @@ -114,7 +114,7 @@ Global Preparation | |||||||
|  call initialized. |  call initialized. | ||||||
|  |  | ||||||
|  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 only be called once each. | ||||||
|  |  | ||||||
| Handle the Easy libcurl | Handle the Easy libcurl | ||||||
|  |  | ||||||
| @@ -137,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/"); | ||||||
|  |  | ||||||
| @@ -225,9 +238,9 @@ When It Doesn't Work | |||||||
|  compiler name and version etc. |  compiler name and version etc. | ||||||
|  |  | ||||||
|  Getting some in-depth knowledge about the protocols involved is never wrong, |  Getting some in-depth knowledge about the protocols involved is never wrong, | ||||||
|  and if you're trying to funny things, you might very well understand libcurl |  and if you're trying to do funny things, you might very well understand | ||||||
|  and how to use it better if you study the appropriate RFC documents at least |  libcurl and how to use it better if you study the appropriate RFC documents | ||||||
|  briefly. |  at least briefly. | ||||||
|  |  | ||||||
|  |  | ||||||
| Upload Data to a Remote Site | Upload Data to a Remote Site | ||||||
| @@ -358,12 +371,16 @@ HTTP POSTing | |||||||
|  |  | ||||||
|     curl_easy_perform(easyhandle); /* post away! */ |     curl_easy_perform(easyhandle); /* post away! */ | ||||||
|  |  | ||||||
|  Simple enough, huh? Ok, so what if you want to post binary data that also |  Simple enough, huh? Since you set the POST options with the | ||||||
|  requires you to set the Content-Type: header of the post? Well, binary posts |  CURLOPT_POSTFIELDS, this automaticly switches the handle to use POST in the | ||||||
|  prevents libcurl from being able to do strlen() on the data to figure out the |  upcoming request. | ||||||
|  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 |  Ok, so what if you want to post binary data that also requires you to set the | ||||||
|  our own headers and then passing that list to libcurl. |  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; |     struct curl_slist *headers=NULL; | ||||||
|     headers = curl_slist_append(headers, "Content-Type: text/xml"); |     headers = curl_slist_append(headers, "Content-Type: text/xml"); | ||||||
| @@ -416,14 +433,14 @@ HTTP POSTing | |||||||
|     /* free the post data again */ |     /* free the post data again */ | ||||||
|     curl_formfree(post); |     curl_formfree(post); | ||||||
|  |  | ||||||
|  The multipart formposts are a chain of parts using MIME-style separators and |  Multipart formposts are chains of parts using MIME-style separators and | ||||||
|  headers. That means that each of these separate parts get a few headers set |  headers. It means that each one of these separate parts get a few headers set | ||||||
|  that describes its individual content-type, size etc. Now, to enable your |  that describe the individual content-type, size etc. To enable your | ||||||
|  application to handicraft this formpost even more, libcurl allows you to |  application to handicraft this formpost even more, libcurl allows you to | ||||||
|  supply your own custom headers to an individual form part. You can of course |  supply your own set of custom headers to such an individual form part. You | ||||||
|  supply headers to as many parts you like, but this little example will show |  can of course supply headers to as many parts you like, but this little | ||||||
|  how you have set headers to one specific part when you add that to post |  example will show how you set headers to one specific part when you add that | ||||||
|  handle: |  to the post handle: | ||||||
|  |  | ||||||
|     struct curl_slist *headers=NULL; |     struct curl_slist *headers=NULL; | ||||||
|     headers = curl_slist_append(headers, "Content-Type: text/xml"); |     headers = curl_slist_append(headers, "Content-Type: text/xml"); | ||||||
| @@ -439,9 +456,22 @@ HTTP POSTing | |||||||
|     curl_formfree(post); /* free post */ |     curl_formfree(post); /* free post */ | ||||||
|     curl_slist_free_all(post); /* free custom header list */ |     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 | Showing Progress | ||||||
|  |  | ||||||
|  |  [ built-in progress meter, progress callback ] | ||||||
|  |  | ||||||
|  |  | ||||||
| libcurl with C++ | libcurl with C++ | ||||||
|  |  | ||||||
| @@ -488,16 +518,342 @@ Proxies | |||||||
|  proxy is using the HTTP protocol. For example, you can't invoke your own |  proxy is using the HTTP protocol. For example, you can't invoke your own | ||||||
|  custom FTP commands or even proper FTP directory listings. |  custom FTP commands or even proper FTP directory listings. | ||||||
|  |  | ||||||
|  |   Proxy Options | ||||||
|  |  | ||||||
|     To tell libcurl to use a proxy at a given port number: |     To tell libcurl to use a proxy at a given port number: | ||||||
|  |  | ||||||
|        curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080"); |        curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080"); | ||||||
|  |  | ||||||
|  Some proxies require user authentication before allowing a request, and you |     Some proxies require user authentication before allowing a request, and | ||||||
|  pass that information similar to this: |     you pass that information similar to this: | ||||||
|  |  | ||||||
|        curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password"); |        curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password"); | ||||||
|  |  | ||||||
|  [ environment variables, SSL, tunneling, automatic proxy config (.pac) ] |     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. | ||||||
|  |  | ||||||
|  |  There's only one aspect left in the HTTP requests that we haven't yet | ||||||
|  |  mentioned how to modify: the version field. All HTTP requests includes the | ||||||
|  |  version number to tell the server which version we support. libcurl speak | ||||||
|  |  HTTP 1.1 by default. Some very old servers don't like getting 1.1-requests | ||||||
|  |  and when dealing with stubborn old things like that, you can tell libcurl to | ||||||
|  |  use 1.0 instead by doing something like this: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_HTTP_VERSION, CURLHTTP_VERSION_1_0); | ||||||
|  |  | ||||||
|  |  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 added to 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 (CURLE_FTP_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE to | ||||||
|  |  send commands before a transfer, no transfer will actually take place when a | ||||||
|  |  quote command has failed. | ||||||
|  |  | ||||||
|  |  If you set the CURLOPT_HEADER to true, you will tell libcurl to get | ||||||
|  |  information about the target file and output "headers" about it. The headers | ||||||
|  |  will be in "HTTP-style", looking like they do in HTTP. | ||||||
|  |  | ||||||
|  |  The option to enable headers or to run custom FTP commands may be useful to | ||||||
|  |  combine with CURLOPT_NOBODY. If this option is set, no actual file content | ||||||
|  |  transfer will be performed. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Cookies Without Chocolate Chips | ||||||
|  |  | ||||||
|  |  In the HTTP sense, a cookie is a name with an associated value. A server | ||||||
|  |  sends the name and value to the client, and expects it to get sent back on | ||||||
|  |  every subsequent request to the server that matches the particular conditions | ||||||
|  |  set. The conditions include that the domain name and path match and that the | ||||||
|  |  cookie hasn't become too old. | ||||||
|  |  | ||||||
|  |  In real-world cases, servers send new cookies to replace existing one to | ||||||
|  |  update them. Server use cookies to "track" users and to keep "sessions". | ||||||
|  |  | ||||||
|  |  Cookies are sent from server to clients with the header Set-Cookie: and | ||||||
|  |  they're sent from clients to servers with the Cookie: header. | ||||||
|  |  | ||||||
|  |  To just send whatever cookie you want to a server, you can use CURLOPT_COOKIE | ||||||
|  |  to set a cookie string like this: | ||||||
|  |  | ||||||
|  |     curl_easy_setopt(easyhandle, CURLOPT_COOKIE, "name1=var1; name2=var2;"); | ||||||
|  |  | ||||||
|  |  In many cases, that is not enough. You might want to dynamicly save whatever | ||||||
|  |  cookies the remote server passes to you, and make sure those cookies are then | ||||||
|  |  use accordingly on later requests. | ||||||
|  |  | ||||||
|  |  One way to do this, is to save all headers you receive in a plain file and | ||||||
|  |  when you make a request, you tell libcurl to read the previous headers to | ||||||
|  |  figure out which cookies to use. Set header file to read cookies from with | ||||||
|  |  CURLOPT_COOKIEFILE. | ||||||
|  |  | ||||||
|  |  The CURLOPT_COOKIEFILE option also automaticly enables the cookie parser in | ||||||
|  |  libcurl. Until the cookie parser is enabled, libcurl will not parse or | ||||||
|  |  understand incoming cookies and they will just be ignored. However, when the | ||||||
|  |  parser is enabled the cookies will be understood and the cookies will be kept | ||||||
|  |  in memory and used properly in subsequent requests when the same handle is | ||||||
|  |  used. Many times this is enough, and you may not have to save the cookies to | ||||||
|  |  disk at all. Note that the file you specify to CURLOPT_COOKIEFILE doesn't | ||||||
|  |  have to exist to enable the parser, so a common way to just enable the parser | ||||||
|  |  and not read able might be to use a file name you know doesn't exist. | ||||||
|  |  | ||||||
|  |  If you rather use existing cookies that you've previously received with your | ||||||
|  |  Netscape or Mozilla browsers, you can make libcurl use that cookie file as | ||||||
|  |  input. The CURLOPT_COOKIEFILE is used for that too, as libcurl will | ||||||
|  |  automaticly find out what kind of file it is and act accordingly. | ||||||
|  |  | ||||||
|  |  The perhaps most advanced cookie operation libcurl offers, is saving the | ||||||
|  |  entire internal cookie state back into a Netscape/Mozilla formatted cookie | ||||||
|  |  file. We call that the cookie-jar. When you set a file name with | ||||||
|  |  CURLOPT_COOKIEJAR, that file name will be created and all received cookies | ||||||
|  |  will be stored in it when curl_easy_cleanup() is called. This enabled cookies | ||||||
|  |  to get passed on properly between multiple handles without any information | ||||||
|  |  getting lost. | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Headers Equal Fun | ||||||
|  |  | ||||||
|  |  [ use the header callback for HTTP, FTP etc ] | ||||||
|  |  | ||||||
|  |  | ||||||
|  | Post Transfer Information | ||||||
|  |  | ||||||
|  |  [ curl_easy_getinfo ] | ||||||
|  |  | ||||||
|  |  | ||||||
| Security Considerations | Security Considerations | ||||||
| @@ -505,11 +861,14 @@ Security Considerations | |||||||
|  [ ps output, netrc plain text, plain text protocols / base64 ] |  [ ps output, netrc plain text, plain text protocols / base64 ] | ||||||
|  |  | ||||||
|  |  | ||||||
| Certificates and Other SSL Tricks | SSL, Certificates and Other Tricks | ||||||
|  |  | ||||||
|  |  [ seeding, passwords, keys, certificates, ENGINE, ca certs ] | ||||||
|  |  | ||||||
|  |  | ||||||
| Future | Future | ||||||
|  |  | ||||||
|  |  [ multi interface, sharing between handles, mutexes, pipelining ] | ||||||
|  |  | ||||||
|  |  | ||||||
| ----- | ----- | ||||||
|   | |||||||
| @@ -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. | ||||||
| @@ -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" | #define LIBCURL_VERSION "7.9.5-pre4" | ||||||
| #define LIBCURL_VERSION_NUM 0x070903 | #define LIBCURL_VERSION_NUM 0x070905 | ||||||
|  |  | ||||||
| /* 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 | ||||||
|   | |||||||
| @@ -2,17 +2,18 @@ | |||||||
| # $Id$ | # $Id$ | ||||||
| # | # | ||||||
|  |  | ||||||
| AUTOMAKE_OPTIONS = foreign no-dependencies | AUTOMAKE_OPTIONS = foreign nostdinc | ||||||
|  |  | ||||||
| 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 \ | ||||||
|  |        config.h.in | ||||||
|  |  | ||||||
| lib_LTLIBRARIES = libcurl.la | lib_LTLIBRARIES = libcurl.la | ||||||
|  |  | ||||||
| INCLUDES = -I$(top_srcdir)/include | INCLUDES = -I$(top_srcdir)/include | ||||||
|  |  | ||||||
|  |  | ||||||
| libcurl_la_LDFLAGS = -no-undefined -version-info 2:2:0 | libcurl_la_LDFLAGS = -no-undefined -version-info 2:2:0 | ||||||
| # This flag accepts an argument of the form current[:revision[:age]]. So, | # This flag accepts an argument of the form current[:revision[:age]]. So, | ||||||
| # passing -version-info 3:12:1 sets current to 3, revision to 12, and age to | # passing -version-info 3:12:1 sets current to 3, revision to 12, and age to | ||||||
|   | |||||||
| @@ -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> | ||||||
| @@ -360,8 +364,13 @@ CURLcode Curl_connecthost(struct connectdata *conn,  /* context */ | |||||||
| #endif | #endif | ||||||
|  |  | ||||||
|     /* 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.connecttimeout) { | ||||||
|        (data->set.timeout>data->set.connecttimeout)) |       if (data->set.timeout < data->set.connecttimeout) | ||||||
|  |         timeout_ms = data->set.timeout*1000; | ||||||
|  |       else  | ||||||
|  |         timeout_ms = data->set.connecttimeout*1000; | ||||||
|  |     } | ||||||
|  |     else if(data->set.timeout) | ||||||
|       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; | ||||||
|   | |||||||
| @@ -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); | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -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", | ||||||
|   | |||||||
							
								
								
									
										512
									
								
								lib/getdate.c
									
									
									
									
									
								
							
							
						
						
									
										512
									
								
								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,7 +41,6 @@ | |||||||
| # ifdef HAVE_TIME_H | # ifdef HAVE_TIME_H | ||||||
| #  include <time.h> | #  include <time.h> | ||||||
| # endif | # endif | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef YYDEBUG | #ifndef YYDEBUG | ||||||
|   /* to satisfy gcc -Wundef, we set this to 0 */ |   /* to satisfy gcc -Wundef, we set this to 0 */ | ||||||
| @@ -197,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 211 "getdate.y" |  | ||||||
| typedef union { | typedef union { | ||||||
|     int			Number; |     int			Number; | ||||||
|     enum _MERIDIAN	Meridian; |     enum _MERIDIAN	Meridian; | ||||||
| @@ -311,11 +310,11 @@ static const short yyrhs[] = {    -1, | |||||||
|  |  | ||||||
| #if YYDEBUG != 0 | #if YYDEBUG != 0 | ||||||
| static const short yyrline[] = { 0, | static const short yyrline[] = { 0, | ||||||
|    227,   228,   231,   234,   237,   240,   243,   246,   249,   255, |    231,   232,   235,   238,   241,   244,   247,   250,   253,   259, | ||||||
|    261,   270,   276,   288,   291,   294,   300,   304,   308,   314, |    265,   274,   280,   292,   295,   298,   304,   308,   312,   318, | ||||||
|    318,   336,   342,   348,   352,   357,   361,   368,   376,   379, |    322,   340,   346,   352,   356,   361,   365,   372,   380,   383, | ||||||
|    382,   385,   388,   391,   394,   397,   400,   403,   406,   409, |    386,   389,   392,   395,   398,   401,   404,   407,   410,   413, | ||||||
|    412,   415,   418,   421,   424,   427,   430,   435,   468,   472 |    416,   419,   422,   425,   428,   431,   434,   439,   473,   477 | ||||||
| }; | }; | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| @@ -395,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.  */ | ||||||
| @@ -939,135 +940,135 @@ yyreduce: | |||||||
|   switch (yyn) { |   switch (yyn) { | ||||||
|  |  | ||||||
| case 3: | case 3: | ||||||
| #line 231 "getdate.y" | #line 235 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveTime++; | 	    context->yyHaveTime++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 4: | case 4: | ||||||
| #line 234 "getdate.y" | #line 238 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveZone++; | 	    context->yyHaveZone++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 5: | case 5: | ||||||
| #line 237 "getdate.y" | #line 241 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveDate++; | 	    context->yyHaveDate++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 6: | case 6: | ||||||
| #line 240 "getdate.y" | #line 244 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveDay++; | 	    context->yyHaveDay++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 7: | case 7: | ||||||
| #line 243 "getdate.y" | #line 247 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyHaveRel++; | 	    context->yyHaveRel++; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 9: | case 9: | ||||||
| #line 249 "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 255 "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 261 "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 270 "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 276 "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 288 "getdate.y" | #line 292 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[0].Number; | 	    context->yyTimezone = yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 15: | case 15: | ||||||
| #line 291 "getdate.y" | #line 295 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[0].Number - 60; | 	    context->yyTimezone = yyvsp[0].Number - 60; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 16: | case 16: | ||||||
| #line 295 "getdate.y" | #line 299 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyTimezone = yyvsp[-1].Number - 60; | 	    context->yyTimezone = yyvsp[-1].Number - 60; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 17: | case 17: | ||||||
| #line 300 "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 304 "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 308 "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 314 "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 318 "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 | ||||||
| @@ -1075,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 336 "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 342 "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 348 "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 352 "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 357 "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 361 "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 368 "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 379 "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 382 "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 385 "getdate.y" | #line 389 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelYear += yyvsp[0].Number; | 	    context->yyRelYear += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 33: | case 33: | ||||||
| #line 388 "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 391 "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 394 "getdate.y" | #line 398 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMonth += yyvsp[0].Number; | 	    context->yyRelMonth += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 36: | case 36: | ||||||
| #line 397 "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 400 "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 403 "getdate.y" | #line 407 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelDay += yyvsp[0].Number; | 	    context->yyRelDay += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 39: | case 39: | ||||||
| #line 406 "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 409 "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 412 "getdate.y" | #line 416 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelHour += yyvsp[0].Number; | 	    context->yyRelHour += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 42: | case 42: | ||||||
| #line 415 "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 418 "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 421 "getdate.y" | #line 425 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelMinutes += yyvsp[0].Number; | 	    context->yyRelMinutes += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 45: | case 45: | ||||||
| #line 424 "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 427 "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 430 "getdate.y" | #line 434 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyRelSeconds += yyvsp[0].Number; | 	    context->yyRelSeconds += yyvsp[0].Number; | ||||||
| 	; | 	; | ||||||
|     break;} |     break;} | ||||||
| case 48: | case 48: | ||||||
| #line 436 "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 469 "getdate.y" | #line 474 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyval.Meridian = MER24; | 	    yyval.Meridian = MER24; | ||||||
| 	  ; | 	  ; | ||||||
|     break;} |     break;} | ||||||
| case 50: | case 50: | ||||||
| #line 473 "getdate.y" | #line 478 "getdate.y" | ||||||
| { | { | ||||||
| 	    yyval.Meridian = yyvsp[0].Meridian; | 	    yyval.Meridian = yyvsp[0].Meridian; | ||||||
| 	  ; | 	  ; | ||||||
| @@ -1521,7 +1523,7 @@ yyerrhandle: | |||||||
|     } |     } | ||||||
|   return 1; |   return 1; | ||||||
| } | } | ||||||
| #line 478 "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 | ||||||
| @@ -1777,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; | ||||||
| @@ -1793,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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -1819,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; | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| @@ -1833,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1843,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1855,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. */ | ||||||
| @@ -1864,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -1874,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; | ||||||
| 	  } | 	  } | ||||||
|     } |     } | ||||||
| @@ -1890,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; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -1898,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; | ||||||
| @@ -1908,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 == '(') | ||||||
| @@ -1983,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); | ||||||
| @@ -1995,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; | ||||||
| @@ -2058,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); | ||||||
| 	} | 	} | ||||||
| @@ -2078,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; | ||||||
|   | |||||||
| @@ -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__) | ||||||
|   | |||||||
							
								
								
									
										409
									
								
								lib/getdate.y
									
									
									
									
									
								
							
							
						
						
									
										409
									
								
								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,7 +17,6 @@ | |||||||
| # ifdef HAVE_TIME_H | # ifdef HAVE_TIME_H | ||||||
| #  include <time.h> | #  include <time.h> | ||||||
| # endif | # endif | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #ifndef YYDEBUG | #ifndef YYDEBUG | ||||||
|   /* to satisfy gcc -Wundef, we set this to 0 */ |   /* to satisfy gcc -Wundef, we set this to 0 */ | ||||||
| @@ -173,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; | ||||||
| @@ -229,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. | ||||||
| @@ -322,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; | ||||||
| 		  } | 		  } | ||||||
| 	      } | 	      } | ||||||
| 	  } | 	  } | ||||||
| @@ -730,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; | ||||||
| @@ -746,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; | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -772,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; | ||||||
| 	} | 	} | ||||||
|     } |     } | ||||||
| @@ -786,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -796,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -808,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. */ | ||||||
| @@ -817,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; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| @@ -827,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; | ||||||
| 	  } | 	  } | ||||||
|     } |     } | ||||||
| @@ -843,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; | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| @@ -851,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; | ||||||
| @@ -861,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 == '(') | ||||||
| @@ -936,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); | ||||||
| @@ -948,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; | ||||||
| @@ -1011,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); | ||||||
| 	} | 	} | ||||||
| @@ -1031,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" | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										11
									
								
								lib/hostip.c
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								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 | ||||||
| @@ -117,7 +118,7 @@ static int _num_chars(int i) | |||||||
|     chars++; |     chars++; | ||||||
|  |  | ||||||
|     i = (int) i / 10; |     i = (int) i / 10; | ||||||
|   } while (i > 1); |   } while (i >= 1); | ||||||
|  |  | ||||||
|   return chars; |   return chars; | ||||||
| } | } | ||||||
| @@ -292,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); | ||||||
| @@ -409,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, | ||||||
| @@ -467,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)) | ||||||
| @@ -510,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" | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 */ | ||||||
|  |  | ||||||
| /* | /* | ||||||
|   | |||||||
| @@ -699,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 | ||||||
|   | |||||||
| @@ -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 | ||||||
|  | #if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__) | ||||||
|  | #include <winsock.h> | ||||||
|  | #endif | ||||||
|  |  | ||||||
| #include <curl/curl.h> | #include <curl/curl.h> | ||||||
|  |  | ||||||
| typedef void CURLM; | typedef void CURLM; | ||||||
|   | |||||||
| @@ -310,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; | ||||||
|  |  | ||||||
| @@ -326,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 */ | ||||||
|   } |   } | ||||||
|   | |||||||
							
								
								
									
										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 | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										27
									
								
								lib/ssluse.c
									
									
									
									
									
								
							
							
						
						
									
										27
									
								
								lib/ssluse.c
									
									
									
									
									
								
							| @@ -80,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 */ | ||||||
|  |  | ||||||
| @@ -99,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 */ | ||||||
| @@ -119,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; | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -138,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; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @@ -170,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; | ||||||
| } | } | ||||||
|  |  | ||||||
| @@ -363,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 */ | ||||||
| @@ -677,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; | ||||||
| @@ -380,6 +380,8 @@ CURLcode Curl_readwrite(struct connectdata *conn, | |||||||
|                 /* we make sure that this socket isn't read more now */ |                 /* we make sure that this socket isn't read more now */ | ||||||
|                 k->keepon &= ~KEEP_READ; |                 k->keepon &= ~KEEP_READ; | ||||||
|                 FD_ZERO(&k->rkeepfd); |                 FD_ZERO(&k->rkeepfd); | ||||||
|  |                 /* for a progress meter/info update before going away */ | ||||||
|  |                 Curl_pgrsUpdate(conn); | ||||||
|                 return CURLE_OK; |                 return CURLE_OK; | ||||||
|               } |               } | ||||||
|  |  | ||||||
| @@ -466,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")) { | ||||||
| @@ -610,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 && | ||||||
| @@ -722,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 */ | ||||||
| @@ -755,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 */ | ||||||
| @@ -784,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); | ||||||
|  |  | ||||||
|     } |     } | ||||||
| @@ -819,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", | ||||||
| @@ -997,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 */ | ||||||
| }; | }; | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -2,25 +2,26 @@ | |||||||
| # $Id$ | # $Id$ | ||||||
| # | # | ||||||
|  |  | ||||||
| # Some flags needed when trying to cause warnings ;-) | AUTOMAKE_OPTIONS = foreign nostdinc | ||||||
| # CFLAGS = -g -DMALLOCDEBUG # -Wall -pedantic |  | ||||||
| #CPPFLAGS = -DGLOBURL -DCURL_SEPARATORS |  | ||||||
|  |  | ||||||
| INCLUDES = -I$(top_srcdir)/include | INCLUDES = -I$(top_srcdir)/include | ||||||
|  |  | ||||||
| bin_PROGRAMS = curl #memtest | bin_PROGRAMS = curl #memtest | ||||||
|  |  | ||||||
| noinst_HEADERS = setup.h \ |  | ||||||
| 	config-win32.h \ |  | ||||||
| 	config-mac.h \ |  | ||||||
| 	urlglob.h \ |  | ||||||
| 	version.h \ |  | ||||||
| 	writeout.h |  | ||||||
|  |  | ||||||
| #memtest_SOURCES = memtest.c | #memtest_SOURCES = memtest.c | ||||||
| #memtest_LDADD = $(top_srcdir)/lib/libcurl.la | #memtest_LDADD = $(top_srcdir)/lib/libcurl.la | ||||||
|  |  | ||||||
| curl_SOURCES = main.c hugehelp.c urlglob.c writeout.c | curl_SOURCES = main.c hugehelp.c urlglob.c writeout.c setup.h \ | ||||||
|  | 	config-win32.h \ | ||||||
|  | 	config-mac.h \ | ||||||
|  | 	config-vms.h \ | ||||||
|  | 	urlglob.h \ | ||||||
|  | 	version.h \ | ||||||
|  | 	writeout.h \ | ||||||
|  | 	config-win32.h \ | ||||||
|  | 	config-mac.h \ | ||||||
|  | 	config-vms.h	 | ||||||
|  |  | ||||||
| curl_LDADD = ../lib/libcurl.la | curl_LDADD = ../lib/libcurl.la | ||||||
| curl_DEPENDENCIES = ../lib/libcurl.la | curl_DEPENDENCIES = ../lib/libcurl.la | ||||||
| BUILT_SOURCES = hugehelp.c | BUILT_SOURCES = hugehelp.c | ||||||
| @@ -34,8 +35,6 @@ EXTRA_DIST = mkhelp.pl curlmsg.msg \ | |||||||
| 	macos/src/curl_GUSIConfig.cpp \ | 	macos/src/curl_GUSIConfig.cpp \ | ||||||
| 	macos/src/macos_main.cpp | 	macos/src/macos_main.cpp | ||||||
|  |  | ||||||
| AUTOMAKE_OPTIONS = foreign no-dependencies |  | ||||||
|  |  | ||||||
| MANPAGE=$(top_srcdir)/docs/curl.1 | MANPAGE=$(top_srcdir)/docs/curl.1 | ||||||
| README=$(top_srcdir)/docs/MANUAL | README=$(top_srcdir)/docs/MANUAL | ||||||
| MKHELP=$(top_srcdir)/src/mkhelp.pl | MKHELP=$(top_srcdir)/src/mkhelp.pl | ||||||
|   | |||||||
| @@ -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 | ||||||
| @@ -1176,8 +1176,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */ | |||||||
|           config->postfields=postdata; |           config->postfields=postdata; | ||||||
|       } |       } | ||||||
|  |  | ||||||
| /*      if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) |       if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq)) | ||||||
|         return PARAM_BAD_USE;*/ |         return PARAM_BAD_USE; | ||||||
|       break; |       break; | ||||||
|     case 'D': |     case 'D': | ||||||
|       /* dump-header to given file name */ |       /* dump-header to given file name */ | ||||||
| @@ -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" | #define CURL_VERSION "7.9.5-pre4" | ||||||
| #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " | #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " | ||||||
|   | |||||||
| @@ -46,6 +46,7 @@ typedef enum { | |||||||
|   VAR_HEADER_SIZE, |   VAR_HEADER_SIZE, | ||||||
|   VAR_REQUEST_SIZE, |   VAR_REQUEST_SIZE, | ||||||
|   VAR_EFFECTIVE_URL, |   VAR_EFFECTIVE_URL, | ||||||
|  |   VAR_CONTENT_TYPE, | ||||||
|   VAR_NUM_OF_VARS /* must be the last */ |   VAR_NUM_OF_VARS /* must be the last */ | ||||||
| } replaceid; | } replaceid; | ||||||
|  |  | ||||||
| @@ -69,6 +70,7 @@ static struct variable replacements[]={ | |||||||
|   {"size_upload", VAR_SIZE_UPLOAD}, |   {"size_upload", VAR_SIZE_UPLOAD}, | ||||||
|   {"speed_download", VAR_SPEED_DOWNLOAD}, |   {"speed_download", VAR_SPEED_DOWNLOAD}, | ||||||
|   {"speed_upload", VAR_SPEED_UPLOAD}, |   {"speed_upload", VAR_SPEED_UPLOAD}, | ||||||
|  |   {"content_type", VAR_CONTENT_TYPE}, | ||||||
|   {NULL, 0} |   {NULL, 0} | ||||||
| }; | }; | ||||||
|  |  | ||||||
| @@ -165,6 +167,11 @@ void ourWriteOut(CURL *curl, char *writeinfo) | |||||||
|                    curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo)) |                    curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo)) | ||||||
|                   fprintf(stream, "%.3f", doubleinfo); |                   fprintf(stream, "%.3f", doubleinfo); | ||||||
|                 break; |                 break; | ||||||
|  |               case VAR_CONTENT_TYPE: | ||||||
|  |                 if(CURLE_OK == | ||||||
|  |                    curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp)) | ||||||
|  |                    fputs(stringp, stream); | ||||||
|  |                break; | ||||||
|               default: |               default: | ||||||
|                 break; |                 break; | ||||||
|               } |               } | ||||||
|   | |||||||
| @@ -62,8 +62,10 @@ One regex per line that is removed from the protocol dumps before the | |||||||
| comparison is made. This is very useful to remove dependencies on dynamicly | comparison is made. This is very useful to remove dependencies on dynamicly | ||||||
| changing protocol data such as port numbers or user-agent strings. | changing protocol data such as port numbers or user-agent strings. | ||||||
| </strip> | </strip> | ||||||
| <protocol> | <protocol [nonewline=yes]> | ||||||
| the protocol dump curl should transmit | the protocol dump curl should transmit, if 'nonewline' is set, we will cut | ||||||
|  | off the trailing newline of this given data before comparing with the one | ||||||
|  | actually sent by the client | ||||||
| </protocol> | </protocol> | ||||||
| <stdout> | <stdout> | ||||||
| This verfies that this data was passed to stdout. | This verfies that this data was passed to stdout. | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ EXTRA_DIST = ftpserver.pl httpserver.pl httpsserver.pl runtests.pl \ | |||||||
| 	     ftpsserver.pl stunnel.pm getpart.pm FILEFORMAT README \ | 	     ftpsserver.pl stunnel.pm getpart.pm FILEFORMAT README \ | ||||||
| 	     stunnel.pem | 	     stunnel.pem | ||||||
|  |  | ||||||
| SUBDIRS = data | SUBDIRS = data server | ||||||
|  |  | ||||||
| PERLFLAGS = -I$(srcdir) | PERLFLAGS = -I$(srcdir) | ||||||
|  |  | ||||||
| @@ -12,11 +12,11 @@ install: | |||||||
| curl: | curl: | ||||||
| 	@(cd ..; make) | 	@(cd ..; make) | ||||||
|  |  | ||||||
| test: | test: server/sws | ||||||
| 	@cd data && exec $(MAKE) test | 	@cd data && exec $(MAKE) test | ||||||
| 	srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl | 	srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl | ||||||
|  |  | ||||||
| quiet-test: | quiet-test: server/sws | ||||||
| 	@cd data && exec $(MAKE) test | 	@cd data && exec $(MAKE) test | ||||||
| 	srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -s -a | 	srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -s -a | ||||||
|  |  | ||||||
| @@ -24,3 +24,5 @@ clean: | |||||||
| 	rm -rf log | 	rm -rf log | ||||||
| 	find . -name "*~" | xargs rm -f | 	find . -name "*~" | xargs rm -f | ||||||
|  |  | ||||||
|  | server/sws: | ||||||
|  | 	cd server; make sws | ||||||
|   | |||||||
| @@ -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" | ||||||
|   | |||||||
| @@ -10,7 +10,7 @@ | |||||||
| use curl with multiple request methods | use curl with multiple request methods | ||||||
|  </name> |  </name> | ||||||
|  <command> |  <command> | ||||||
| -I -X FOOO localhost | -I -d FOOO localhost | ||||||
| </command> | </command> | ||||||
| </test> | </test> | ||||||
|  |  | ||||||
|   | |||||||
| @@ -28,7 +28,7 @@ HTTP POST with user and password | |||||||
| <strip> | <strip> | ||||||
| ^User-Agent:.* | ^User-Agent:.* | ||||||
| </strip> | </strip> | ||||||
| <protocol> | <protocol nonewline=yes> | ||||||
| POST /3 HTTP/1.1 | POST /3 HTTP/1.1 | ||||||
| Authorization: Basic ZmFrZTotdXNlcg== | Authorization: Basic ZmFrZTotdXNlcg== | ||||||
| Host: 127.0.0.1:8999 | Host: 127.0.0.1:8999 | ||||||
|   | |||||||
| @@ -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(); |  | ||||||
| } |  | ||||||
|   | |||||||
| @@ -1,4 +1,4 @@ | |||||||
| #!/usr/bin/perl | #!/usr/bin/env perl | ||||||
| # $Id$ | # $Id$ | ||||||
| # | # | ||||||
| # Main curl test script, in perl to run on more platforms | # Main curl test script, in perl to run on more platforms | ||||||
| @@ -140,16 +140,27 @@ sub runhttpserver { | |||||||
|     my $RUNNING; |     my $RUNNING; | ||||||
|     my $pid; |     my $pid; | ||||||
|  |  | ||||||
|  |     $pid = checkserver ($HTTPPIDFILE); | ||||||
|  |  | ||||||
|     # verify if our/any server is running on this port |     # verify if our/any server is running on this port | ||||||
|     my $data=`$CURL --silent -i $HOSTIP:$HOSTPORT/verifiedserver`; |     my $data=`$CURL --silent -i $HOSTIP:$HOSTPORT/verifiedserver`; | ||||||
|  |  | ||||||
|     if ( $data =~ /WE ROOLZ(: |)(\d*)/ ) { |     if ( $data =~ /WE ROOLZ(: |)(\d*)/ ) { | ||||||
|  |         if($2) { | ||||||
|             $pid = 0+$2; |             $pid = 0+$2; | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if(!$pid) { | ||||||
|  |             print "Test server already running with unknown pid! Use it...\n"; | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  |  | ||||||
|         if($verbose) { |         if($verbose) { | ||||||
|             print "Test server already running with pid $pid, killing it...\n"; |             print "Test server already running with pid $pid, killing it...\n"; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     elsif($data ne "") { |     elsif($data ne "") { | ||||||
|  |         print "GOT: $data\n"; | ||||||
|         print "An alien HTTP server is running on port $HOSTPORT\n", |         print "An alien HTTP server is running on port $HOSTPORT\n", | ||||||
|         "Edit runtests.pl to use another port and rerun the test script\n"; |         "Edit runtests.pl to use another port and rerun the test script\n"; | ||||||
|         exit; |         exit; | ||||||
| @@ -602,6 +613,15 @@ sub singletest { | |||||||
|  |  | ||||||
|         my @protstrip=@protocol; |         my @protstrip=@protocol; | ||||||
|  |  | ||||||
|  |         # check if there's any attributes on the verify/protocol section | ||||||
|  |         my %hash = getpartattr("verify", "protocol"); | ||||||
|  |  | ||||||
|  |         if($hash{'nonewline'}) { | ||||||
|  |             # Yes, we must cut off the final newline from the final line | ||||||
|  |             # of the protocol data | ||||||
|  |             chomp($protstrip[$#protstrip]); | ||||||
|  |         } | ||||||
|  |  | ||||||
|         for(@strip) { |         for(@strip) { | ||||||
|             # strip all patterns from both arrays |             # strip all patterns from both arrays | ||||||
|             @out = striparray( $_, \@out); |             @out = striparray( $_, \@out); | ||||||
| @@ -835,7 +855,6 @@ if($testthis[0] ne "") { | |||||||
|     $TESTCASES=join(" ", @testthis); |     $TESTCASES=join(" ", @testthis); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| ####################################################################### | ####################################################################### | ||||||
| # Output curl version and host info being tested | # Output curl version and host info being tested | ||||||
| # | # | ||||||
|   | |||||||
							
								
								
									
										12
									
								
								tests/server/Makefile.am
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								tests/server/Makefile.am
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | |||||||
|  | # sws is the Silly Web Server | ||||||
|  | # | ||||||
|  | # Original http server code contributed by Georg Horn. Heavily modified since. | ||||||
|  | # | ||||||
|  |  | ||||||
|  | AUTOMAKE_OPTIONS = foreign | ||||||
|  |  | ||||||
|  | noinst_PROGRAMS = sws | ||||||
|  |  | ||||||
|  | sws_SOURCES= sws.c getpart.c | ||||||
|  |  | ||||||
|  | extra_DIST = config.h.in | ||||||
							
								
								
									
										2
									
								
								tests/server/config.h.in
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								tests/server/config.h.in
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,2 @@ | |||||||
|  |  | ||||||
|  | #undef HAVE_SIGNAL | ||||||
							
								
								
									
										153
									
								
								tests/server/getpart.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										153
									
								
								tests/server/getpart.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,153 @@ | |||||||
|  |  | ||||||
|  | #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++ | ||||||
|  |  | ||||||
|  | #ifdef DEBUG | ||||||
|  | #define show(x) printf x | ||||||
|  | #else | ||||||
|  | #define show(x) | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | static | ||||||
|  | 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; | ||||||
|  |  | ||||||
|  |   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) { | ||||||
|  |         show(("=> %s", buffer)); | ||||||
|  |         string = appendstring(string, buffer, &stringlen, &stralloc); | ||||||
|  |         show(("* %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); | ||||||
|  |       show(("* %s\n", buffer)); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     if((STATE_INSUB == state) && | ||||||
|  |        !strcmp(cmain, main) && | ||||||
|  |        !strcmp(csub, sub)) { | ||||||
|  |       show(("* (%d bytes) %s\n", stringlen, buffer)); | ||||||
|  |       display = 1; /* start displaying */ | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       show(("%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 | ||||||
							
								
								
									
										425
									
								
								tests/server/sws.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										425
									
								
								tests/server/sws.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,425 @@ | |||||||
|  | /* sws.c: simple (silly?) web server */ | ||||||
|  |  | ||||||
|  | #include <stdio.h> | ||||||
|  | #include <stdlib.h> | ||||||
|  | #include <string.h> | ||||||
|  | #include <unistd.h> | ||||||
|  | #include <signal.h> | ||||||
|  | #include <sys/time.h> | ||||||
|  | #include <sys/types.h> | ||||||
|  | #include <sys/wait.h> | ||||||
|  | #include <sys/socket.h> | ||||||
|  | #include <netinet/in.h> | ||||||
|  | #include <netdb.h> | ||||||
|  |  | ||||||
|  | char *spitout(FILE *stream, char *main, char *sub, int *size); | ||||||
|  |  | ||||||
|  | #define DEFAULT_PORT 8999 | ||||||
|  |  | ||||||
|  | #ifndef DEFAULT_LOGFILE | ||||||
|  | #define DEFAULT_LOGFILE "log/sws.log" | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  | #define DOCBUFSIZE 4 | ||||||
|  | #define BUFFERSIZE (DOCBUFSIZE * 1024) | ||||||
|  |  | ||||||
|  | #define VERSION "cURL test suite HTTP server/0.1" | ||||||
|  |  | ||||||
|  | #define REQUEST_DUMP "log/server.input" | ||||||
|  |  | ||||||
|  | #define TEST_DATA_PATH "data/test%d" | ||||||
|  |  | ||||||
|  | static char *docfriends = "HTTP/1.1 200 Mighty fine indeed\r\n\r\nWE 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); | ||||||
|  | #ifdef DEBUG | ||||||
|  |     fprintf(stderr, "%s: pid %d: %s\n", loctime, getpid(), msg); | ||||||
|  | #endif | ||||||
|  |     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; | ||||||
|  |   unsigned long contentlength=0; | ||||||
|  |  | ||||||
|  | #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 > 0 ) { | ||||||
|  |     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, "ab"); /* b is for windows-preparing */ | ||||||
|  |   if(dump) { | ||||||
|  |     fwrite(reqbuf, 1, strlen(reqbuf), dump); | ||||||
|  |  | ||||||
|  |     fclose(dump); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | #define REQBUFSIZ 50000 | ||||||
|  | #define REQBUFSIZ_TXT "49999" | ||||||
|  |  | ||||||
|  | /* very-big-path support */ | ||||||
|  | #define MAXDOCNAMELEN 40000 | ||||||
|  | #define MAXDOCNAMELEN_TXT "39999" | ||||||
|  |  | ||||||
|  | #define REQUEST_KEYWORD_SIZE 256 | ||||||
|  | static int get_request(int sock, int *part) | ||||||
|  | { | ||||||
|  |   static char reqbuf[REQBUFSIZ], doc[MAXDOCNAMELEN]; | ||||||
|  |   static char request[REQUEST_KEYWORD_SIZE]; | ||||||
|  |   unsigned int offset = 0; | ||||||
|  |   int prot_major, prot_minor; | ||||||
|  |   char logbuf[256]; | ||||||
|  |  | ||||||
|  |   *part = 0; /* part zero equals none */ | ||||||
|  |  | ||||||
|  |   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, "%" REQBUFSIZ_TXT"s %" MAXDOCNAMELEN_TXT "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((strlen(doc) + strlen(request)) < 200) | ||||||
|  |         sprintf(logbuf, "Got request: %s %s HTTP/%d.%d", | ||||||
|  |                 request, doc, prot_major, prot_minor); | ||||||
|  |       else | ||||||
|  |         sprintf(logbuf, "Got a *HUGE* request HTTP/%d.%d", | ||||||
|  |                 prot_major, prot_minor); | ||||||
|  |       logmsg(logbuf); | ||||||
|  |        | ||||||
|  |       if(!strncmp("/verifiedserver", ptr, 15)) { | ||||||
|  |         logmsg("Are-we-friendly question received"); | ||||||
|  |         return -2; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       ptr++; /* skip the slash */ | ||||||
|  |  | ||||||
|  |       test_no = strtol(ptr, &ptr, 10); | ||||||
|  |  | ||||||
|  |       if(test_no > 10000) { | ||||||
|  |         *part = test_no % 10000; | ||||||
|  |         test_no /= 10000; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       sprintf(logbuf, "Found test number %d in path", test_no); | ||||||
|  |       logmsg(logbuf); | ||||||
|  |     } | ||||||
|  |     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 part_no) | ||||||
|  | { | ||||||
|  |   int written; | ||||||
|  |   int count; | ||||||
|  |   char *buffer; | ||||||
|  |   char *ptr; | ||||||
|  |   FILE *stream; | ||||||
|  |   char *cmd=NULL; | ||||||
|  |   int cmdsize; | ||||||
|  |  | ||||||
|  |   char filename[256]; | ||||||
|  |   char partbuf[80]="data"; | ||||||
|  |  | ||||||
|  |   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; | ||||||
|  |  | ||||||
|  |     count = strlen(buffer); | ||||||
|  |   } | ||||||
|  |   else { | ||||||
|  |     if(0 != part_no) { | ||||||
|  |       sprintf(partbuf, "data%d", part_no); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |     sprintf(filename, TEST_DATA_PATH, doc); | ||||||
|  |  | ||||||
|  |     stream=fopen(filename, "rb"); | ||||||
|  |     if(!stream) { | ||||||
|  |       logmsg("Couldn't open test file"); | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     else { | ||||||
|  |       ptr = buffer = spitout(stream, "reply", partbuf, &count); | ||||||
|  |       fclose(stream); | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     /* re-open the same file again */ | ||||||
|  |     stream=fopen(filename, "rb"); | ||||||
|  |     if(!stream) { | ||||||
|  |       logmsg("Couldn't open test file"); | ||||||
|  |       return 0; | ||||||
|  |     } | ||||||
|  |     else {     | ||||||
|  |       /* get the custom server control "commands" */ | ||||||
|  |       cmd = spitout(stream, "reply", "postcmd", &cmdsize); | ||||||
|  |       fclose(stream); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   do { | ||||||
|  |     written = send(sock, buffer, count, 0); | ||||||
|  |     if (written < 0) { | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |     count -= written; | ||||||
|  |     buffer += written; | ||||||
|  |   } while(count>0); | ||||||
|  |  | ||||||
|  |   if(ptr) | ||||||
|  |     free(ptr); | ||||||
|  |  | ||||||
|  |   if(cmdsize > 0 ) { | ||||||
|  |     char command[32]; | ||||||
|  |     int num; | ||||||
|  |     char *ptr=cmd; | ||||||
|  |     do { | ||||||
|  |       if(2 == sscanf(ptr, "%31s %d", command, &num)) { | ||||||
|  |         if(!strcmp("wait", command)) | ||||||
|  |           sleep(num); /* wait this many seconds */ | ||||||
|  |         else { | ||||||
|  |           logmsg("Unknown command in reply command section"); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |       ptr = strchr(ptr, '\n'); | ||||||
|  |       if(ptr) | ||||||
|  |         ptr++; | ||||||
|  |       else | ||||||
|  |         ptr = NULL; | ||||||
|  |     } while(ptr && *ptr); | ||||||
|  |   } | ||||||
|  |   if(cmd) | ||||||
|  |     free(cmd); | ||||||
|  |  | ||||||
|  |   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; | ||||||
|  |   int part_no; | ||||||
|  |   FILE *pidfile; | ||||||
|  |    | ||||||
|  |   if(argc>1) | ||||||
|  |     port = atoi(argv[1]); | ||||||
|  |  | ||||||
|  |   /* FIX: write our pid to a file name */ | ||||||
|  |  | ||||||
|  |   logfp = fopen(logfile, "a"); | ||||||
|  |   if (!logfp) { | ||||||
|  |     perror(logfile); | ||||||
|  |     exit(1); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  | #ifdef HAVE_SIGNAL | ||||||
|  |   /* FIX: make a more portable signal handler */ | ||||||
|  |   signal(SIGPIPE, sigpipe_handler); | ||||||
|  |   signal(SIGINT, sigterm_handler); | ||||||
|  |   signal(SIGTERM, sigterm_handler); | ||||||
|  |  | ||||||
|  |   siginterrupt(SIGPIPE, 1); | ||||||
|  |   siginterrupt(SIGINT, 1); | ||||||
|  |   siginterrupt(SIGTERM, 1); | ||||||
|  | #endif | ||||||
|  |  | ||||||
|  |   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); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   pidfile = fopen(".http.pid", "w"); | ||||||
|  |   if(pidfile) { | ||||||
|  |     fprintf(pidfile, "%d\n", (int)getpid()); | ||||||
|  |     fclose(pidfile); | ||||||
|  |   } | ||||||
|  |   else | ||||||
|  |     fprintf(stderr, "Couldn't write pid file\n"); | ||||||
|  |  | ||||||
|  |   /* start accepting connections */ | ||||||
|  |   listen(sock, 5); | ||||||
|  |  | ||||||
|  |   fprintf(stderr, "*** %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, &part_no); | ||||||
|  |     send_doc(msgsock, doc, part_no); | ||||||
|  |  | ||||||
|  |     close(msgsock); | ||||||
|  |   } | ||||||
|  |    | ||||||
|  |   close(sock); | ||||||
|  |   fclose(logfp); | ||||||
|  |    | ||||||
|  |   return 0; | ||||||
|  | } | ||||||
|  |  | ||||||
		Reference in New Issue
	
	Block a user