Compare commits

...

82 Commits

Author SHA1 Message Date
Daniel Stenberg
b40b9677b6 VMS adjustments 2002-02-20 23:24:04 +00:00
Daniel Stenberg
c80ad865db new from Nico! 2002-02-20 13:48:03 +00:00
Daniel Stenberg
758eae49ab four more bugfixes, one VMS adjustment 2002-02-20 13:47:36 +00:00
Daniel Stenberg
721b05e343 Nico Baggus' VMS tweaks 2002-02-20 13:46:53 +00:00
Daniel Stenberg
a333bddeeb Andrs Garca solved bug report #515228 by making sure the progress meter
is updated even if everything is read in one single pass, as the windows
functions apparantly does more often than other systems.
2002-02-20 13:38:34 +00:00
Daniel Stenberg
4c6a52fe90 corrected reference to multi-using examples 2002-02-19 11:02:01 +00:00
Daniel Stenberg
792d73a9cf include winsock.h on window boxen to work smoother there 2002-02-19 11:00:34 +00:00
Daniel Stenberg
9a95a3f8c3 moved the config.h to lib/config.h 2002-02-19 01:06:56 +00:00
Daniel Stenberg
485edb777f a minor step forwards 2002-02-19 01:04:46 +00:00
Daniel Stenberg
a8c3431ae9 use the new HTTP server input file 2002-02-19 01:04:31 +00:00
Daniel Stenberg
6fe4a6fa9a cut off the old perl one, this only runs the C coded version 2002-02-19 01:03:45 +00:00
Daniel Stenberg
6d8c7356d6 fixed the huge text just in case anyone actually reads it 2002-02-19 00:26:44 +00:00
Daniel Stenberg
a782c96e81 no .. in path 2002-02-19 00:26:25 +00:00
Daniel Stenberg
c795123cd5 fixed a long long mistake 2002-02-18 23:32:45 +00:00
Daniel Stenberg
0ec370e6fb auth on multiple hosts with follow-location 2002-02-18 23:17:57 +00:00
Daniel Stenberg
3d5732d4e0 Rick Richardson's getaddrinfo() usage fix to speed up name resolves 2002-02-18 23:12:37 +00:00
Daniel Stenberg
b795929858 INADDR_NONE should be in_addr_t to work with 64bit archs better.
Really, we should only #define this in one file, not both here and in
connect.c!
2002-02-18 22:59:26 +00:00
Daniel Stenberg
535258ffe4 Philip Gladstone's size problem in add_buffer_send() 2002-02-18 22:41:52 +00:00
Daniel Stenberg
cc161b96ac 4 fixes 2002-02-18 10:51:50 +00:00
Daniel Stenberg
5c4b422b18 offer SSL verfication callback,
add 'headers=' in client formpost
2002-02-18 10:51:28 +00:00
Daniel Stenberg
89bad584c3 updated LDAP URL syntax references by Aron Roberts 2002-02-18 10:47:27 +00:00
Daniel Stenberg
e21926f7f0 connection timeout comparison fix by Emil 2002-02-18 10:05:18 +00:00
Daniel Stenberg
e452f467d4 Philip Gladstone's 64-bit issues corrected.
Reminder for the future: when we're using malloc() we MUST include <stdlib.h>
as otherwise 64bit archs go bananas.

Bug report #517687
2002-02-17 14:55:35 +00:00
Daniel Stenberg
dfda7ba456 corrected the Expect: ignore, made Content-Type: possible to skip 2002-02-17 14:42:44 +00:00
Daniel Stenberg
feb6b6445e Giaslas Georgios's Host: over proxy fix 2002-02-17 11:17:37 +00:00
Daniel Stenberg
0b57fa9c51 http server added to CVS, config*h files moved 2002-02-07 15:13:11 +00:00
Daniel Stenberg
55c6f60c90 ugh. the VMS stuff must've been like that for a reason, I put it back again 2002-02-07 14:47:41 +00:00
Daniel Stenberg
9def011e8e moved the config-* files to lib/Makefile.am 2002-02-07 14:35:14 +00:00
Daniel Stenberg
7cf6e8c9cc moved the config-* files here from the ../Makefile.am 2002-02-07 14:34:34 +00:00
Daniel Stenberg
cdee43aa59 use the config files in this directory now, not ../ 2002-02-07 14:33:36 +00:00
Daniel Stenberg
9c25b58b4c moved the config-*.h files from root to the lib/ dir 2002-02-07 14:32:28 +00:00
Daniel Stenberg
83f35463f5 added note about persistancy in the server 2002-02-07 12:52:04 +00:00
Daniel Stenberg
818cdb879e POSTs seems to work somewhat now 2002-02-07 12:42:59 +00:00
Daniel Stenberg
3eead2d6c4 port number fix, now stores the processed request sent to the server 2002-02-07 12:40:06 +00:00
Daniel Stenberg
5cffe055ad added Cris Bailiff's CAdir option suggestion 2002-02-07 10:43:43 +00:00
Daniel Stenberg
3d4511daf3 the initial C code for the new HTTP test server 2002-02-07 09:39:15 +00:00
Daniel Stenberg
4748b40ad9 changes since 7.9.4 2002-02-07 09:34:43 +00:00
Daniel Stenberg
c40b4f6c39 don't add 2 to the post size, that was a previous mistake because there
was an extra CRLF added to the post data
2002-02-07 09:32:40 +00:00
Daniel Stenberg
d3b96dd394 Miklos Nemeth windows update 2002-02-06 16:04:03 +00:00
Daniel Stenberg
f946df640b Miklos Nemeth added comments 2002-02-06 16:03:28 +00:00
Daniel Stenberg
fef78bd6f1 Miklos Nemeth improved the windows section 2002-02-06 16:01:10 +00:00
Daniel Stenberg
9e6cc86bf7 Miklos Nemeth improved 2002-02-06 16:00:55 +00:00
Daniel Stenberg
b544c5fa5c ARGH the CRLF I removed recently was not only done after the initial
content-type header, it was used for each part and thus without this it
failed MISERABLY. *smacks forhead*
2002-02-06 15:48:53 +00:00
Daniel Stenberg
afa64ee31f a few of the SSL options were added in 7.9.3 and it should be noted
accordingly
2002-02-06 09:49:34 +00:00
Daniel Stenberg
e9bfef0eb1 Brent Beardsley found the content-type bug! 2002-02-06 07:02:13 +00:00
Daniel Stenberg
ddbcccd43d Kevin Roth's discovered SSL download problem 2002-02-05 15:33:00 +00:00
Daniel Stenberg
5370d7a6eb 7.9.4 2002-02-05 11:43:29 +00:00
Daniel Stenberg
685b180ab6 7.9.4-pre2 2002-02-04 09:51:41 +00:00
Daniel Stenberg
9dab850874 Eric Melville fixed spell mistakes on a few places 2002-02-03 15:00:51 +00:00
Daniel Stenberg
0d5bfe883e Andreas Damm made getdate use gmtime_r if available 2002-02-01 11:11:26 +00:00
Daniel Stenberg
cc2f1d4894 Added the recycle handles chapter
Added most of the Customizing Operations chapter
2002-01-31 14:41:01 +00:00
Daniel Stenberg
a8dd13db4c struct HttpHeader died ages ago, corrected comments 2002-01-31 14:24:55 +00:00
Daniel Stenberg
325391aef9 Albert Chin:
Forgot one case. On HP-UX 11.00, gethostbyname_r() is properly defined
if -D_REENTRANT is used. Without it, the compiler still accepts the
function prototype but gives a warning about hostent_data going out of
scope. This is because struct hostent_data is not declared. So, we
force an error by trying to set a variable to the struct.
2002-01-31 07:53:20 +00:00
Daniel Stenberg
3474ec4ecb _num_chars did wrong when called with a number that starts with 1! 2002-01-31 07:51:06 +00:00
Daniel Stenberg
ec1736d488 corrected the docs for CURLINFO_FILETIME 2002-01-31 07:17:32 +00:00
Daniel Stenberg
4522579688 Giaslas Georgios provided docs for CURLINFO_CONTENT_TYPE 2002-01-31 07:10:41 +00:00
Daniel Stenberg
907a6e0eed Georg Horn the previous SSL_read() fix, this was actually the fix I did
on my test machine! :-)
2002-01-30 21:49:29 +00:00
Daniel Stenberg
d20186a7b8 I have too many ideas of what to mention in this docs 2002-01-30 15:35:02 +00:00
Daniel Stenberg
b28051881e Georg Horn found yet another SSL reading problem caused by the non-blocks.
This was a real bummer!
2002-01-30 15:11:47 +00:00
Daniel Stenberg
bdea56cd3f big-time alert that this doesn't work 2002-01-30 10:18:47 +00:00
Daniel Stenberg
8a3ec2c659 the interface is simply called the "C" one these days 2002-01-30 10:07:49 +00:00
Daniel Stenberg
14e9420d2c extended the proxy chapter mucho 2002-01-30 10:04:40 +00:00
Daniel Stenberg
5b58e61f28 now re-seed by force (even if already seeded) if a random file or egd socket
is given
2002-01-30 08:17:23 +00:00
Daniel Stenberg
be2f3071b5 conn->upload_bufsize exists no more 2002-01-29 20:34:30 +00:00
Daniel Stenberg
85dbf82d93 append a CRLF pair after the content-type line 2002-01-29 20:32:10 +00:00
Daniel Stenberg
a9c4963cc0 removed three loust fprintf()s
removed the initial CRLF in the formpost, as they are part of the request
and should be written by the code in http.c!
2002-01-29 20:30:56 +00:00
Daniel Stenberg
a4934387d5 upload progress counter fix, removed the adjustable upload buffer size 2002-01-29 20:28:59 +00:00
Daniel Stenberg
e88a2ec6fc no more adjustable upload buffer size, we use non-blocking sockets now so
this work-around is not needed anymore!
2002-01-29 20:28:26 +00:00
Daniel Stenberg
0666960173 nine items since 7.9.3 2002-01-29 14:12:12 +00:00
Daniel Stenberg
f114caca90 - 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.
2002-01-29 14:11:38 +00:00
Daniel Stenberg
9468c9c796 bad tag 2002-01-29 10:55:57 +00:00
Daniel Stenberg
76c53c690c Giaslas Georgios introduced CURLINFO_CONTENT_TYPE 2002-01-29 10:49:32 +00:00
Daniel Stenberg
c341b11aaf Steve Marx helped us realize that we shouldn't treat customrequest as a
request of its own, it just changes the keyword of a request.
2002-01-28 19:31:26 +00:00
Daniel Stenberg
6212e6990a someone should have me punished, but this bug made curl bug seriously
on IPv4-linux machines
2002-01-28 19:23:18 +00:00
Daniel Stenberg
28049a183c don't count a custom request as a request type of its own, it is merely
a modifier of another type
2002-01-28 19:22:40 +00:00
Daniel Stenberg
5d3dd7911e newly generated 2002-01-28 18:39:55 +00:00
Daniel Stenberg
ae8375516b Andreas Damm made it reentrant safe! 2002-01-28 18:39:40 +00:00
Daniel Stenberg
e3f10eb825 no longer add CRLF _after_ POST data, it should not be needed. Pedro Neves
pointed out this ugliness.
2002-01-27 11:51:11 +00:00
Daniel Stenberg
2b1f683239 set header and request size to 0 before each *_perform() 2002-01-27 11:49:17 +00:00
Daniel Stenberg
a2b19c9a63 postit.c is removed, it used the deprecated curl_formparse() and may
encourage people to use bad functions
2002-01-25 10:07:07 +00:00
Daniel Stenberg
4146ce8267 bug report #508235 identified a non-working Location: following, and this
little fix seems to correct it. another case where we just returned and
didn't shut off the reading. This bug is introduced in 7.9.3 due to the
new internal "order".
2002-01-25 08:35:49 +00:00
Daniel Stenberg
170bd6dafc don't install the example programs! :-O 2002-01-24 07:38:01 +00:00
58 changed files with 1805 additions and 902 deletions

142
CHANGES
View File

@@ -6,6 +6,148 @@
History of Changes History of Changes
Daniel (20 February 2002)
- Andr<64>s Garc<72>a provided a solution to bug report #515228. the total time
counter was not set correctly when -I was used during some conditions (all
headers were read in one single read).
- Nico Baggus provided a huge patch with minor tweaks all over to make curl
compile nicely on VMS.
Daniel (19 February 2002)
- Rick Richardson found out that by replacing PF_UNSPEC with PF_INET in the
getaddrinfo() calls, he could speed up some name resolving calls with an
order of magnitudes on his Redhat Linux 7.2.
- Philip Gladstone found a second INADDR_NONE problem where we used long
intead of in_addr_t which caused 64bit problemos. We really shouldn't define
that on two different places.
Daniel (18 February 2002)
- Philip Gladstone found a problem in how HTTP requests were sent if the
request couldn't be sent all at once.
- Emil found and corrected a bad connection timeout comparison that made curl
use the longest of connect-timeout and timout as a timeout value, instead of
the shortest as it was supposed to!
- Aron Roberts provided updated information about LDAP URL syntax to go into
the manual as a replacement for the old references.
Daniel (17 February 2002)
- Philip Gladstone pointed out two missing include files that made curl core
dump on 64bit architectures. We need to pay more attention on these details.
It is *lethal* to for example forget the malloc() prototype, as 'int' is
32bit and malloc() must return a 64bit pointer on these platforms.
- Giaslas Georgios fixed a problem with Host: headers on repeated requests on
the same handle using a proxy.
Daniel (8 February 2002)
- Hanno L. Kranzhoff accurately found out that disabling the Expect: header
when doing multipart formposts didn't work very well. It disabled other
parts of the request header too, resulting in a broken header. When I fixed
this, I also noticed that the Content-Type wasn't possible to disable. It is
now, even though it probably is really stupid to try to do this (because of
the boundary string that is included in the internally generated header,
used as form part separator.)
Daniel (7 February 2002)
- I moved the config*.h files from the root directory to the lib/ directory.
- I've added the new test suite HTTP server to the CVS repository, It seems to
work pretty good now, but we must make it get used by the test scripts
properly and then we need to make sure that it compiles, builds and runs on
most operating systems.
Version 7.9.5-pre1
Daniel (6 February 2002)
- Miklos Nemeth provided updated windows makefiles and INSTALL docs.
- Mr Larry Fahnoe found a problem with formposts and I managed to track down
and patch this bug. This was actually two bugs, as the posted size was also
said to be two bytes too large.
- Brent Beardsley found out and brought a correction for the
CURLINFO_CONTENT_TYPE parser that was off one byte. This was my fault, I
accidentaly broke Giaslas Georgios' patch.
Daniel (5 February 2002)
- Kevin Roth found yet another SSL download problem.
Version 7.9.4
- no changes since pre-release
Version 7.9.4-pre2
Daniel (3 February 2002)
- Eric Melville provided a few spelling corrections in the curl man page.
Daniel (1 February 2002)
- Andreas Damm corrected the unconditional use of gmtime() in getdate, it now
uses gmtime_r() on all hosts that have it.
Daniel (31 January 2002)
- An anonymous bug report identified a problem in the DNS caching which made it
sometimes allocate one byte too little to store the cache entry in. This
happened when the port number started with 1!
- Albert Chin provided a patch that improves the gethostbyname_r() configure
check on HP-UX 11.00.
Version 7.9.4-pre1
Daniel (30 January 2002)
- Georg Horn found another way the SSL reading failed due to the non-blocking
state of the sockets! I fixed.
Daniel (29 January 2002)
- Multipart formposts now send the full request properly, including the CRLF.
They were previously treated as part of the post data.
- The upload byte counter bugged.
- T. Bharath pointed out that we seed SSL on every connect, which is a time-
consuming operation that should only be needed to do once. We patched
libcurl to now only seed on the first connect when unseeded. The seeded
status is global so it'll now only happen once during a program's life time.
If the random_file or egdsocket is set, the seed will be re-made though.
- Giaslas Georgios introduced CURLINFO_CONTENT_TYPE that lets
curl_easy_getinfo() read the content-type from the previous request.
Daniel (28 January 2002)
- Kjetil Jacobsen found a way to crash curl and after much debugging, it
turned out it was a IPv4-linux only problem introduced in 7.9.3 related to
name resolving.
- Andreas Damm posted a huge patch that made the curl_getdate() function fully
reentrant!
- Steve Marx pointed out that you couldn't mix CURLOPT_CUSTOMREQUEST with
CURLOPT_POSTFIELDS. You can now!
Daniel (25 January 2002)
- Krishnendu Majumdar pointed out that the header length counter was not reset
between multiple requests on the same handle.
- Pedro Neves rightfully questioned why curl always append \r\n to the data
that is sent in HTTP POST requests. Unfortunately, this broke the test suite
as the test HTTP server is lame enough not to deal with this... :-O
- Following Location: headers when the connection didn't close didn't work as
libcurl didn't properly stop reading. This problem was added in 7.9.3 due to
the restructured internals. 'Frank' posted a bug report about this.
Daniel (24 January 2002)
- Kevin Roth very quickly spotted that we wrongly installed the example
programs that were built in the multi directory, when 'make install' was
used. :-/
Version 7.9.3 Version 7.9.3
Daniel (23 January 2002) Daniel (23 January 2002)

View File

@@ -6,8 +6,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = \ EXTRA_DIST = \
CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt \ CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt \
reconf Makefile.dist curl-config.in build_vms.com curl-mode.el \ reconf Makefile.dist curl-config.in build_vms.com curl-mode.el
config-vms.h config-win32.h config-riscos.h config-mac.h
bin_SCRIPTS = curl-config bin_SCRIPTS = curl-config

View File

@@ -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:

View File

@@ -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)

View File

@@ -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

View File

@@ -8,7 +8,7 @@ AC_PREREQ(2.50)
dnl First some basic init macros dnl First some basic init macros
AC_INIT AC_INIT
AC_CONFIG_SRCDIR([lib/urldata.h]) AC_CONFIG_SRCDIR([lib/urldata.h])
AM_CONFIG_HEADER(config.h src/config.h) AM_CONFIG_HEADER(lib/config.h src/config.h)
dnl figure out the libcurl version dnl figure out the libcurl version
VERSION=`sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curl.h` VERSION=`sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curl.h`

View File

@@ -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
------------------------- -------------------------

View File

@@ -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:

View File

@@ -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

View File

@@ -510,7 +510,7 @@ password is specified, curl will ask for it interactively.
If this option is used several times, the last one will be used. If this option is used several times, the last one will be used.
.IP "--url <URL>" .IP "--url <URL>"
Specify a URL to fetch. This option is mostly handy when you wanna specify Specify a URL to fetch. This option is mostly handy when you want to specify
URL(s) in a config file. URL(s) in a config file.
This option may be used any number of times. To control where this URL is written, use the This option may be used any number of times. To control where this URL is written, use the
@@ -538,7 +538,7 @@ write "@-".
The variables present in the output format will be substituted by the value or The variables present in the output format will be substituted by the value or
text that curl thinks fit, as described below. All variables are specified text that curl thinks fit, as described below. All variables are specified
like %{variable_name} and to output a normal % you just write them like like %{variable_name} and to output a normal % you just write them like
%%. You can output a newline by using \\n, a carrige return with \\r and a tab %%. You can output a newline by using \\n, a carriage return with \\r and a tab
space with \\t. space with \\t.
.B NOTE: .B NOTE:
@@ -788,7 +788,7 @@ Internal error. A function was called in a bad order.
.IP 45 .IP 45
Interface error. A specified outgoing interface could not be used. Interface error. A specified outgoing interface could not be used.
.IP 46 .IP 46
Bad password entered. An error was signalled when the password was entered. Bad password entered. An error was signaled when the password was entered.
.IP 47 .IP 47
Too many redirects. When following redirects, curl hit the maximum amount. Too many redirects. When following redirects, curl hit the maximum amount.
.IP 48 .IP 48

View File

@@ -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

View File

@@ -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.

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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.
@@ -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,278 @@ 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.
To tell libcurl to use a proxy at a given port number: Proxy Options
curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080"); To tell libcurl to use a proxy at a given port number:
Some proxies require user authentication before allowing a request, and you curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080");
pass that information similar to this:
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password"); Some proxies require user authentication before allowing a request, and
you pass that information similar to this:
[ environment variables, SSL, tunneling, automatic proxy config (.pac) ] curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password");
If you want to, you can specify the host name only in the CURLOPT_PROXY
option, and set the port number separately with CURLOPT_PROXYPORT.
Environment Variables
libcurl automaticly checks and uses a set of environment variables to know
what proxies to use for certain protocols. The names of the variables are
following an ancient de facto standard and are built up as
"[protocol]_proxy" (note the lower casing). Which makes the variable
'http_proxy' checked for a name of a proxy to use when the input URL is
HTTP. Following the same rule, the variable named 'ftp_proxy' is checked
for FTP URLs. Again, the proxies are always HTTP proxies, the different
names of the variables simply allows different HTTP proxies to be used.
The proxy environment variable contents should be in the format
"[protocol://]machine[:port]". Where the protocol:// part is simply
ignored if present (so http://proxy and bluerk://proxy will do the same)
and the optional port number specifies on which port the proxy operates on
the host. If not specified, the internal default port number will be used
and that is most likely *not* the one you would like it to be.
There are two special environment variables. 'all_proxy' is what sets
proxy for any URL in case the protocol specific variable wasn't set, and
'no_proxy' defines a list of hosts that should not use a proxy even though
a variable may say so. If 'no_proxy' is a plain asterisk ("*") it matches
all hosts.
SSL and Proxies
SSL is for secure point-to-point connections. This involves strong
encryption and similar things, which effectivly makes it impossible for a
proxy to operate as a "man in between" which the proxy's task is, as
previously discussed. Instead, the only way to have SSL work over a HTTP
proxy is to ask the proxy to tunnel trough everything without being able
to check or fiddle with the traffic.
Opening an SSL connection over a HTTP proxy is therefor a matter of asking
the proxy for a straight connection to the target host on a specified
port. This is made with the HTTP request CONNECT. ("please mr proxy,
connect me to that remote host").
Because of the nature of this operation, where the proxy has no idea what
kind of data that is passed in and out through this tunnel, this breaks
some of the very few advantages that come from using a proxy, such as
caching. Many organizations prevent this kind of tunneling to other
destination port numbers than 443 (which is the default HTTPS port
number).
Tunneling Through Proxy
As explained above, tunneling is required for SSL to work and often even
restricted to the operation intended for SSL; HTTPS.
This is however not the only time proxy-tunneling might offer benefits to
you or your application.
As tunneling opens a direct connection from your application to the remote
machine, it suddenly also re-introduces the ability to do non-HTTP
operations over a HTTP proxy. You can in fact use things such as FTP
upload or FTP custom commands this way.
Again, this is often prevented by the adminstrators of proxies and is
rarely allowed.
Tell libcurl to use proxy tunneling like this:
curl_easy_setopt(easyhandle, CURLOPT_HTTPPROXYTUNNEL, TRUE);
In fact, there might even be times when you want to do plain HTTP
operations using a tunnel like this, as it then enables you to operate on
the remote server instead of asking the proxy to do so. libcurl will not
stand in the way for such innovative actions either!
Proxy Auto-Config
Netscape first came up with this. It is basicly a web page (usually using
a .pac extension) with a javascript that when executed by the browser with
the requested URL as input, returns information to the browser on how to
connect to the URL. The returned information might be "DIRECT" (which
means no proxy should be used), "PROXY host:port" (to tell the browser
where the proxy for this particular URL is) or "SOCKS host:port" (to
direct the brower to a SOCKS proxy).
libcurl has no means to interpret or evaluate javascript and thus it
doesn't support this. If you get yourself in a position where you face
this nasty invention, the following advice have been mentioned and used in
the past:
- Depending on the javascript complexity, write up a script that
translates it to another language and execute that.
- Read the javascript code and rewrite the same logic in another language.
- Implement a javascript interpreted, people have successfully used the
Mozilla javascript engine in the past.
- Ask your admins to stop this, for a static proxy setup or similar.
Persistancy Is The Way to Happiness
Re-cycling the same easy handle several times when doing multiple requests is
the way to go.
After each single curl_easy_perform() operation, libcurl will keep the
connection alive and open. A subsequent request using the same easy handle to
the same host might just be able to use the already open connection! This
reduces network impact a lot.
Even if the connection is dropped, all connections involving SSL to the same
host again, will benefit from libcurl's session ID cache that drasticly
reduces re-connection time.
FTP connections that are kept alive saves a lot of time, as the command-
response roundtrips are skipped, and also you don't risk getting blocked
without permission to login again like on many FTP servers only allowing N
persons to be logged in at the same time.
libcurl caches DNS name resolving results, to make lookups of a previously
looked up name a lot faster.
Other interesting details that improve performance for subsequent requests
may also be added in the future.
Each easy handle will attempt to keep the last few connections alive for a
while in case they are to be used again. You can set the size of this "cache"
with the CURLOPT_MAXCONNECTS option. Default is 5. It is very seldom any
point in changing this value, and if you think of changing this it is often
just a matter of thinking again.
When the connection cache gets filled, libcurl must close an existing
connection in order to get room for the new one. To know which connection to
close, libcurl uses a "close policy" that you can affect with the
CURLOPT_CLOSEPOLICY option. There's only two polices implemented as of this
writing (libcurl 7.9.4) and they are:
CURLCLOSEPOLICY_LEAST_RECENTLY_USED simply close the one that hasn't been
used for the longest time. This is the default behavior.
CURLCLOSEPOLICY_OLDEST closes the oldest connection, the one that was
createst the longest time ago.
There are, or at least were, plans to support a close policy that would call
a user-specified callback to let the user be able to decide which connection
to dump when this is necessary and therefor is the CURLOPT_CLOSEFUNCTION an
existing option still today. Nothing ever uses this though and this will not
be used within the forseeable future either.
To force your upcoming request to not use an already existing connection (it
will even close one first if there happens to be one alive to the same host
you're about to operate on), you can do that by setting CURLOPT_FRESH_CONNECT
to TRUE. In a similar spirit, you can also forbid the upcoming request to be
"lying" around and possibly get re-used after the request by setting
CURLOPT_FORBID_REUSE to TRUE.
Customizing Operations
There is an ongoing development today where more and more protocols are built
upon HTTP for transport. This has obvious benefits as HTTP is a tested and
reliable protocol that is widely deployed and have excellent proxy-support.
When you use one of these protocols, and even when doing other kinds of
programming you may need to change the traditional HTTP (or FTP or...)
manners. You may need to change words, headers or various data.
libcurl is your friend here too.
If just changing the actual HTTP request keyword is what you want, like when
GET, HEAD or POST is not good enough for you, CURLOPT_CUSTOMREQUEST is there
for you. It is very simple to use:
curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "MYOWNRUQUEST");
When using the custom request, you change the request keyword of the actual
request you are performing. Thus, by default you make GET request but you can
also make a POST operation (as described before) and then replace the POST
keyword if you want to. You're the boss.
HTTP-like protocols pass a series of headers to the server when doing the
request, and you're free to pass any amount of extra headers that you think
fit. Adding headers are this easy:
struct curl_slist *headers;
headers = curl_slist_append(headers, "Hey-server-hey: how are you?");
headers = curl_slist_append(headers, "X-silly-content: yes");
/* pass our list of custom made headers */
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(easyhandle); /* transfer http */
curl_slist_free_all(headers); /* free the header list */
... and if you think some of the internally generated headers, such as
User-Agent:, Accept: or Host: don't contain the data you want them to
contain, you can replace them by simply setting them too:
headers = curl_slist_append(headers, "User-Agent: 007");
headers = curl_slist_append(headers, "Host: munged.host.line");
If you replace an existing header with one with no contents, you will prevent
the header from being sent. Like if you want to completely prevent the
"Accept:" header to be sent, you can disable it with code similar to this:
headers = curl_slist_append(headers, "Accept:");
Both replacing and cancelling internal headers should be done with careful
consideration and you should be aware that you may violate the HTTP protocol
when doing so.
Not all protocols are HTTP-like, and thus the above may not help you when you
want to make for example your FTP transfers to behave differently.
Sending custom commands to a FTP server means that you need to send the
comands exactly as the FTP server expects them (RFC959 is a good guide here),
and you can only use commands that work on the control-connection alone. All
kinds of commands that requires data interchange and thus needs a
data-connection must be left to libcurl's own judgement. Also be aware that
libcurl will do its very best to change directory to the target directory
before doing any transfer, so if you change directory (with CWD or similar)
you might confuse libcurl and then it might not attempt to transfer the file
in the correct remote directory.
A little example that deletes a given file before an operation:
headers = curl_slist_append(headers, "DELE file-to-remove");
/* pass the list of custom commands to the handle */
curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers);
curl_easy_perform(easyhandle); /* transfer ftp data! */
curl_slist_free_all(headers); /* free the header list */
If you would instead want this operation (or chain of operations) to happen
_after_ the data transfer took place the option to curl_easy_setopt() would
instead be called CURLOPT_POSTQUOTE and used the exact same way.
The custom FTP command will be issued to the server in the same order they
are built in the list, and if a command gets an error code returned back from
the server no more commands will be issued and libcurl will bail out with an
error code. Note that if you use CURLOPT_QUOTE to send commands before a
transfer, no transfer will actually take place then.
[ custom FTP commands without transfer, FTP "header-only", HTTP 1.0 ]
Cookies Without Chocolate Chips
[ set cookies, read cookies from file, cookie-jar ]
Headers Equal Fun
[ use the header callback for HTTP, FTP etc ]
Post Transfer Information
[ curl_easy_getinfo ]
Security Considerations Security Considerations
@@ -505,11 +797,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 ]
----- -----

View File

@@ -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

View File

@@ -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.4"
#define LIBCURL_VERSION_NUM 0x070903 #define LIBCURL_VERSION_NUM 0x070904
/* linked-list structure for the CURLOPT_QUOTE option (and other) */ /* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist { struct curl_slist {
@@ -666,7 +666,11 @@ typedef enum {
CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17, CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
CURLINFO_LASTONE = 18 CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
/* Fill in new entries here! */
CURLINFO_LASTONE = 19
} CURLINFO; } CURLINFO;
/* unfortunately, the easy.h include file needs the options and info stuff /* unfortunately, the easy.h include file needs the options and info stuff

View File

@@ -6,7 +6,8 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = getdate.y \ EXTRA_DIST = getdate.y \
Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \ Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \
libcurl.def dllinit.c curllib.dsp curllib.dsw libcurl.def dllinit.c curllib.dsp curllib.dsw \
config-vms.h config-win32.h config-riscos.h config-mac.h
lib_LTLIBRARIES = libcurl.la lib_LTLIBRARIES = libcurl.la

View File

@@ -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

View File

@@ -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

View File

@@ -48,6 +48,10 @@
#include <stdlib.h> /* required for free() prototype, without it, this crashes #include <stdlib.h> /* required for free() prototype, without it, this crashes
on macos 68K */ on macos 68K */
#endif #endif
#ifdef VMS
#include <in.h>
#include <inet.h>
#endif
#endif #endif
#include <stdio.h> #include <stdio.h>
@@ -361,7 +365,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* get the most strict timeout of the ones converted to milliseconds */ /* get the most strict timeout of the ones converted to milliseconds */
if(data->set.timeout && if(data->set.timeout &&
(data->set.timeout>data->set.connecttimeout)) (data->set.timeout < data->set.connecttimeout))
timeout_ms = data->set.timeout*1000; timeout_ms = data->set.timeout*1000;
else else
timeout_ms = data->set.connecttimeout*1000; timeout_ms = data->set.connecttimeout*1000;

View File

@@ -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 */

View File

@@ -81,6 +81,10 @@ DllMain (
} }
return TRUE; return TRUE;
} }
#else
#ifdef VMS
int VOID_VAR_DLLINIT;
#endif
#endif #endif
/* /*

View File

@@ -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);

View File

@@ -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",

View File

@@ -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;

View File

@@ -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__)

View File

@@ -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;

View File

@@ -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;
} }

View File

@@ -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"

View File

@@ -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);

View File

@@ -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 );
} }
} }

View File

@@ -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"

View File

@@ -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 */
/* /*

View File

@@ -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

View File

@@ -44,12 +44,16 @@
o Enable the application to select() on its own file descriptors and curl's o Enable the application to select() on its own file descriptors and curl's
file descriptors simultaneous easily. file descriptors simultaneous easily.
Example source using this interface: http://curl.haxx.se/dev/multi-app.c Example sources using this interface is here: ../multi/
*/ */
#ifdef HAVE_SYS_SOCKET_H #ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h> #include <sys/socket.h>
#endif #endif
#ifdef HAVE_WINSOCK_H
#include <winsock.h>
#endif
#include <curl/curl.h> #include <curl/curl.h>
typedef void CURLM; typedef void CURLM;

View File

@@ -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 */
} }

View File

@@ -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

View File

@@ -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;
/* Make funny stuff to get random input */ if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
random_the_seed(conn); /* Make funny stuff to get random input */
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) {

View File

@@ -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;

View File

@@ -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)
data->set.httpreq = HTTPREQ_CUSTOM; /* we don't set
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 */

View File

@@ -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 */
}; };

View File

@@ -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

View File

@@ -13,6 +13,7 @@ bin_PROGRAMS = curl #memtest
noinst_HEADERS = setup.h \ noinst_HEADERS = setup.h \
config-win32.h \ config-win32.h \
config-mac.h \ config-mac.h \
config-vms.h \
urlglob.h \ urlglob.h \
version.h \ version.h \
writeout.h writeout.h

View File

@@ -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
View 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

View File

@@ -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 */

View File

@@ -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! */

View File

@@ -1,3 +1,3 @@
#define CURL_NAME "curl" #define CURL_NAME "curl"
#define CURL_VERSION "7.9.3" #define CURL_VERSION "7.9.5-pre1"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

View File

@@ -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"

View File

@@ -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();
}

View File

@@ -22,7 +22,7 @@ my $FTPSPORT=8821; # this is the FTPS server port
my $CURL="../src/curl"; # what curl executable to run on the tests my $CURL="../src/curl"; # what curl executable to run on the tests
my $LOGDIR="log"; my $LOGDIR="log";
my $TESTDIR="data"; my $TESTDIR="data";
my $SERVERIN="$LOGDIR/server.input"; # what curl sent the server my $SERVERIN="$LOGDIR/http-request.dump"; # what curl sent the server
my $CURLLOG="$LOGDIR/curl.log"; # all command lines run my $CURLLOG="$LOGDIR/curl.log"; # all command lines run
my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy ftp server instructions here my $FTPDCMD="$LOGDIR/ftpserver.cmd"; # copy ftp server instructions here
@@ -835,6 +835,35 @@ if($testthis[0] ne "") {
$TESTCASES=join(" ", @testthis); $TESTCASES=join(" ", @testthis);
} }
############################################################################
#
# don't let anyone think this works right now
print <<EOM
***************************************************************************
THIS DOES NOT WORK
***************************************************************************
Things in curl-land have changed, but the test suite has not been fixed
accordingly and thus, the test suite is currently more or less useless.
*PLEASE* help us fixing this. We have to make our new test server written
in C work and get used instead of the perl version previously used.
The working version of the test server is found in the tests/server
directory in the CVS tree.
If you run this in the tests/ directory and run the server in there, you
can actually get test-responses if you do like this:
\$ ./server/sws 8080 &
\$ curl localhost:8080/3
EOM
;
####################################################################### #######################################################################
# Output curl version and host info being tested # Output curl version and host info being tested

16
tests/server/Makefile Normal file
View File

@@ -0,0 +1,16 @@
CC = gcc
CFLAGS = -g -Wall
.PHONY: all clean
TARGET = sws
OBJS= sws.o getpart.o
all: $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LDFLAGS) -o $@ $^
clean:
-rm -f $(OBJS) *~ $(TARGET) core logfile

147
tests/server/getpart.c Normal file
View File

@@ -0,0 +1,147 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define EAT_SPACE(ptr) while( ptr && *ptr && isspace(*ptr) ) ptr++
#define EAT_WORD(ptr) while( ptr && *ptr && !isspace(*ptr) && ('>' != *ptr)) ptr++
char *appendstring(char *string, /* original string */
char *buffer, /* to append */
int *stringlen, int *stralloc)
{
int len = strlen(buffer);
if((len + *stringlen) > *stralloc) {
char *newptr= realloc(string, *stralloc*2);
if(newptr) {
string = newptr;
*stralloc *= 2;
}
else
return NULL;
}
strcpy(&string[*stringlen], buffer);
*stringlen += len;
return string;
}
char *spitout(FILE *stream, char *main, char *sub, int *size)
{
char buffer[8192]; /* big enough for anything */
char cmain[128]=""; /* current main section */
char csub[128]=""; /* current sub section */
char *ptr;
char *end;
char display = 0;
char *string;
int stringlen=0;
int stralloc=256;
int len;
enum {
STATE_OUTSIDE,
STATE_INMAIN,
STATE_INSUB,
STATE_ILLEGAL
} state = STATE_OUTSIDE;
string = (char *)malloc(stralloc);
while(fgets(buffer, sizeof(buffer), stream)) {
ptr = buffer;
/* pass white spaces */
EAT_SPACE(ptr);
if('<' != *ptr) {
if(display) {
printf("=> %s", buffer);
string = appendstring(string, buffer, &stringlen, &stralloc);
printf("* %s\n", buffer);
}
continue;
}
ptr++;
EAT_SPACE(ptr);
if('/' == *ptr) {
/* end of a section */
ptr++;
EAT_SPACE(ptr);
end = ptr;
EAT_WORD(end);
*end = 0;
if((state == STATE_INSUB) &&
!strcmp(csub, ptr)) {
/* this is the end of the currently read sub section */
state--;
csub[0]=0; /* no sub anymore */
display=0;
}
else if((state == STATE_INMAIN) &&
!strcmp(cmain, ptr)) {
/* this is the end of the currently read main section */
state--;
cmain[0]=0; /* no main anymore */
display=0;
}
}
else if(!display) {
/* this is the beginning of a section */
end = ptr;
EAT_WORD(end);
*end = 0;
switch(state) {
case STATE_OUTSIDE:
strcpy(cmain, ptr);
state = STATE_INMAIN;
break;
case STATE_INMAIN:
strcpy(csub, ptr);
state = STATE_INSUB;
break;
}
}
if(display) {
string = appendstring(string, buffer, &stringlen, &stralloc);
printf("* %s\n", buffer);
}
if((STATE_INSUB == state) &&
!strcmp(cmain, main) &&
!strcmp(csub, sub)) {
printf("* (%d bytes) %s\n", stringlen, buffer);
display = 1; /* start displaying */
}
else {
printf("%d (%s/%s): %s\n", state, cmain, csub, buffer);
display = 0; /* no display */
}
}
*size = stringlen;
return string;
}
#ifdef TEST
int main(int argc, char **argv)
{
if(argc< 3) {
printf("./moo main sub\n");
}
else {
int size;
char *buffer = spitout(stdin, argv[1], argv[2], &size);
}
return 0;
}
#endif

343
tests/server/sws.c Normal file
View File

@@ -0,0 +1,343 @@
/* sws.c: simple (silly?) web server */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <assert.h>
#define DEFAULT_PORT 8999
#ifndef DEFAULT_LOGFILE
#define DEFAULT_LOGFILE "/dev/null"
#endif
#define DOCBUFSIZE 4
#define BUFFERSIZE (DOCBUFSIZE * 1024)
#define VERSION "cURL test suite HTTP server/0.1"
#define REQUEST_DUMP "http-request.dump"
#define TEST_DATA_PATH "data/test%d"
static char *docfriends = "WE ROOLZ\r\n";
static char *doc404 = "HTTP/1.1 404 Not Found\n"
"Server: " VERSION "\n"
"Connection: close\n"
"Content-Type: text/html\n"
"\n"
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
"<HTML><HEAD>\n"
"<TITLE>404 Not Found</TITLE>\n"
"</HEAD><BODY>\n"
"<H1>Not Found</H1>\n"
"The requested URL was not found on this server.\n"
"<P><HR><ADDRESS>" VERSION "</ADDRESS>\n" "</BODY></HTML>\n";
static volatile int sigpipe, sigterm;
static FILE *logfp;
static void logmsg(const char *msg)
{
time_t t = time(NULL);
struct tm *curr_time = localtime(&t);
char loctime[80];
strcpy(loctime, asctime(curr_time));
loctime[strlen(loctime) - 1] = '\0';
fprintf(logfp, "%s: pid %d: %s\n", loctime, getpid(), msg);
fprintf(stderr, "%s: pid %d: %s\n", loctime, getpid(), msg);
fflush(logfp);
}
static void sigpipe_handler(int sig)
{
sigpipe = 1;
}
static void sigterm_handler(int sig)
{
char logbuf[100];
snprintf(logbuf, 100, "Got signal %d, terminating", sig);
logmsg(logbuf);
sigterm = 1;
}
int ProcessRequest(char *request)
{
char *line=request;
long contentlength=-1;
#define END_OF_HEADERS "\r\n\r\n"
char *end;
end = strstr(request, END_OF_HEADERS);
if(!end)
/* we don't have a complete request yet! */
return 0;
/* **** Persistancy ****
*
* If the request is a HTTP/1.0 one, we close the connection unconditionally
* when we're done.
*
* If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
* header that might say "close". If it does, we close a connection when
* this request is processed. Otherwise, we keep the connection alive for X
* seconds.
*/
do {
if(!strncasecmp("Content-Length:", line, 15))
contentlength = strtol(line+15, &line, 10);
line = strchr(line, '\n');
if(line)
line++;
} while(line);
if(contentlength > -1 ) {
if(contentlength <= strlen(end+strlen(END_OF_HEADERS)))
return 1; /* done */
else
return 0; /* not complete yet */
}
return 1; /* done */
}
/* store the entire request in a file */
void storerequest(char *reqbuf)
{
FILE *dump;
dump = fopen(REQUEST_DUMP, "wb"); /* b is for windows-preparing */
if(dump) {
fwrite(reqbuf, 1, strlen(reqbuf), dump);
fclose(dump);
}
}
#define REQBUFSIZ 4096
#define MAXDOCNAMELEN 1024
#define REQUEST_KEYWORD_SIZE 256
static int get_request(int sock)
{
char reqbuf[REQBUFSIZ], doc[MAXDOCNAMELEN];
char request[REQUEST_KEYWORD_SIZE];
unsigned int offset = 0;
int prot_major, prot_minor;
while (offset < REQBUFSIZ) {
int got = recv(sock, reqbuf + offset, REQBUFSIZ - offset, 0);
if (got <= 0) {
if (got < 0) {
perror("recv");
return -1;
}
logmsg("Connection closed by client");
return -1;
}
offset += got;
reqbuf[offset] = 0;
if(ProcessRequest(reqbuf))
break;
}
if (offset >= REQBUFSIZ) {
logmsg("Request buffer overflow, closing connection");
return -1;
}
reqbuf[offset]=0;
logmsg("Received a request");
/* dump the request to an external file */
storerequest(reqbuf);
if (sscanf(reqbuf, "%s %s HTTP/%d.%d",
request,
doc,
&prot_major,
&prot_minor) == 4) {
char *ptr;
int test_no=0;
/* find the last slash */
ptr = strrchr(doc, '/');
/* get the number after it */
if(ptr) {
if(!strcmp("/verifiedserver", ptr)) {
logmsg("Are-we-friendly question received");
return -2;
}
test_no = strtol(ptr+1, &ptr, 10);
logmsg("Found test number in PATH");
}
else {
logmsg("Did not find test number in PATH");
}
return test_no;
}
logmsg("Got illegal request");
fprintf(stderr, "Got illegal request\n");
return -1;
}
static int send_doc(int sock, int doc)
{
int written;
int count;
char *buffer;
char *ptr;
FILE *stream;
char filename[256];
if(doc < 0) {
if(-2 == doc)
/* we got a "friends?" question, reply back that we sure are */
buffer = docfriends;
else
buffer = doc404;
ptr = NULL;
stream=NULL;
}
else {
sprintf(filename, TEST_DATA_PATH, doc);
stream=fopen(filename, "rb");
if(!stream) {
logmsg("Couldn't open test file");
return 0;
}
ptr = buffer = spitout(stream, "reply", "data", &count);
}
do {
written = send(sock, buffer, count, 0);
if (written < 0) {
fclose(stream);
return -1;
}
count -= written;
buffer += written;
} while(count>0);
if(ptr)
free(ptr);
if(stream)
fclose(stream);
return 0;
}
int main(int argc, char *argv[])
{
struct sockaddr_in me;
int sock, msgsock, flag;
unsigned short port = DEFAULT_PORT;
char *logfile = DEFAULT_LOGFILE;
if(argc>1)
port = atoi(argv[1]);
logfile = "logfile";
/* FIX: write our pid to a file name */
logfp = fopen(logfile, "a");
if (!logfp) {
perror(logfile);
exit(1);
}
signal(SIGPIPE, sigpipe_handler);
signal(SIGINT, sigterm_handler);
signal(SIGTERM, sigterm_handler);
siginterrupt(SIGPIPE, 1);
siginterrupt(SIGINT, 1);
siginterrupt(SIGTERM, 1);
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
fprintf(logfp, "Error opening socket -- aborting\n");
fclose(logfp);
exit(1);
}
flag = 1;
if (setsockopt
(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag,
sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEADDR)");
}
me.sin_family = AF_INET;
me.sin_addr.s_addr = INADDR_ANY;
me.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &me, sizeof me) < 0) {
perror("binding stream socket");
fprintf(logfp, "Error binding socket -- aborting\n");
fclose(logfp);
exit(1);
}
/* start accepting connections */
listen(sock, 5);
printf("*** %s listening on port %u ***\n", VERSION, port);
while (!sigterm) {
int doc;
msgsock = accept(sock, NULL, NULL);
if (msgsock == -1) {
if (sigterm) {
break;
}
/* perror("accept"); */
continue;
}
logmsg("New client connected");
doc = get_request(msgsock);
send_doc(msgsock, doc);
close(msgsock);
}
close(sock);
fclose(logfp);
return 0;
}