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