Compare commits
271 Commits
pre-host-c
...
curl-7_9_5
Author | SHA1 | Date | |
---|---|---|---|
![]() |
c2d4fd876c | ||
![]() |
58cad04bbb | ||
![]() |
9bb64d6827 | ||
![]() |
4441df90c1 | ||
![]() |
f51f2417c5 | ||
![]() |
aad617647d | ||
![]() |
49c0d62dda | ||
![]() |
f752098ba5 | ||
![]() |
a4477b9e4b | ||
![]() |
ad3cef0fc8 | ||
![]() |
d89dbe5bd6 | ||
![]() |
b0475dbdbc | ||
![]() |
60b2e74fa3 | ||
![]() |
cda16297d1 | ||
![]() |
d6c9a72e15 | ||
![]() |
4d7b1512c1 | ||
![]() |
d8a35d745e | ||
![]() |
e22657ea13 | ||
![]() |
d06d6b5534 | ||
![]() |
cec8ab1fde | ||
![]() |
9fc62a8dd0 | ||
![]() |
61540b98c2 | ||
![]() |
465ae39e86 | ||
![]() |
01f04b9a41 | ||
![]() |
34f9ab1046 | ||
![]() |
699876778b | ||
![]() |
8fc5a0d19e | ||
![]() |
62b5926d58 | ||
![]() |
4d1037f385 | ||
![]() |
e4addb3975 | ||
![]() |
2aef351980 | ||
![]() |
d88c153c7d | ||
![]() |
9e9883082e | ||
![]() |
71440df4c7 | ||
![]() |
80b004a57d | ||
![]() |
ea8476a2dc | ||
![]() |
cb85ca18ab | ||
![]() |
f1103b95cf | ||
![]() |
aa5ff53bcf | ||
![]() |
907dabed5d | ||
![]() |
0cacbc892c | ||
![]() |
6753c3c715 | ||
![]() |
36e1363e3d | ||
![]() |
d1a711eb6a | ||
![]() |
d8dea4dcc7 | ||
![]() |
ca161737bc | ||
![]() |
3612c3774e | ||
![]() |
e6a65bb3ef | ||
![]() |
ff291eee48 | ||
![]() |
66b8f48a88 | ||
![]() |
634760cbdc | ||
![]() |
a23a897ad2 | ||
![]() |
d9c244278d | ||
![]() |
b6c4185b27 | ||
![]() |
5896d35e72 | ||
![]() |
b4dfdd8bbc | ||
![]() |
e6ed3478ea | ||
![]() |
db08d9c6b9 | ||
![]() |
9490278ece | ||
![]() |
fd8bf5f171 | ||
![]() |
c9bc14a222 | ||
![]() |
63708cbfb0 | ||
![]() |
d9f307623c | ||
![]() |
540f77a627 | ||
![]() |
71bb2d0b8b | ||
![]() |
87dc44e434 | ||
![]() |
29e0fcd091 | ||
![]() |
2e9a798f09 | ||
![]() |
b32a39f44f | ||
![]() |
d86f9611b3 | ||
![]() |
6a62fc4a40 | ||
![]() |
7cdd6455d7 | ||
![]() |
e4fefd088d | ||
![]() |
95e601e2b1 | ||
![]() |
b1ffe7b74a | ||
![]() |
417c8fb602 | ||
![]() |
85efa64c31 | ||
![]() |
d8cb026e80 | ||
![]() |
41dd5121f0 | ||
![]() |
94482d7ca5 | ||
![]() |
4d0e51aead | ||
![]() |
ae8a8c8ba4 | ||
![]() |
7d043f46d5 | ||
![]() |
cbca19d6c2 | ||
![]() |
b40b9677b6 | ||
![]() |
c80ad865db | ||
![]() |
758eae49ab | ||
![]() |
721b05e343 | ||
![]() |
a333bddeeb | ||
![]() |
4c6a52fe90 | ||
![]() |
792d73a9cf | ||
![]() |
9a95a3f8c3 | ||
![]() |
485edb777f | ||
![]() |
a8c3431ae9 | ||
![]() |
6fe4a6fa9a | ||
![]() |
6d8c7356d6 | ||
![]() |
a782c96e81 | ||
![]() |
c795123cd5 | ||
![]() |
0ec370e6fb | ||
![]() |
3d5732d4e0 | ||
![]() |
b795929858 | ||
![]() |
535258ffe4 | ||
![]() |
cc161b96ac | ||
![]() |
5c4b422b18 | ||
![]() |
89bad584c3 | ||
![]() |
e21926f7f0 | ||
![]() |
e452f467d4 | ||
![]() |
dfda7ba456 | ||
![]() |
feb6b6445e | ||
![]() |
0b57fa9c51 | ||
![]() |
55c6f60c90 | ||
![]() |
9def011e8e | ||
![]() |
7cf6e8c9cc | ||
![]() |
cdee43aa59 | ||
![]() |
9c25b58b4c | ||
![]() |
83f35463f5 | ||
![]() |
818cdb879e | ||
![]() |
3eead2d6c4 | ||
![]() |
5cffe055ad | ||
![]() |
3d4511daf3 | ||
![]() |
4748b40ad9 | ||
![]() |
c40b4f6c39 | ||
![]() |
d3b96dd394 | ||
![]() |
f946df640b | ||
![]() |
fef78bd6f1 | ||
![]() |
9e6cc86bf7 | ||
![]() |
b544c5fa5c | ||
![]() |
afa64ee31f | ||
![]() |
e9bfef0eb1 | ||
![]() |
ddbcccd43d | ||
![]() |
5370d7a6eb | ||
![]() |
685b180ab6 | ||
![]() |
9dab850874 | ||
![]() |
0d5bfe883e | ||
![]() |
cc2f1d4894 | ||
![]() |
a8dd13db4c | ||
![]() |
325391aef9 | ||
![]() |
3474ec4ecb | ||
![]() |
ec1736d488 | ||
![]() |
4522579688 | ||
![]() |
907a6e0eed | ||
![]() |
d20186a7b8 | ||
![]() |
b28051881e | ||
![]() |
bdea56cd3f | ||
![]() |
8a3ec2c659 | ||
![]() |
14e9420d2c | ||
![]() |
5b58e61f28 | ||
![]() |
be2f3071b5 | ||
![]() |
85dbf82d93 | ||
![]() |
a9c4963cc0 | ||
![]() |
a4934387d5 | ||
![]() |
e88a2ec6fc | ||
![]() |
0666960173 | ||
![]() |
f114caca90 | ||
![]() |
9468c9c796 | ||
![]() |
76c53c690c | ||
![]() |
c341b11aaf | ||
![]() |
6212e6990a | ||
![]() |
28049a183c | ||
![]() |
5d3dd7911e | ||
![]() |
ae8375516b | ||
![]() |
e3f10eb825 | ||
![]() |
2b1f683239 | ||
![]() |
a2b19c9a63 | ||
![]() |
4146ce8267 | ||
![]() |
170bd6dafc | ||
![]() |
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 | ||
![]() |
fbe2907599 | ||
![]() |
343da8d4b3 | ||
![]() |
8d97792dbc | ||
![]() |
8d07c87be7 | ||
![]() |
ed21701df3 | ||
![]() |
df01507582 | ||
![]() |
f2bda5fd5b | ||
![]() |
cba9838e8f | ||
![]() |
b6dba9f5dd | ||
![]() |
6e9d1617c6 | ||
![]() |
ea811fee52 | ||
![]() |
7391fd8f6a | ||
![]() |
6c00c58f2a | ||
![]() |
4931fbce49 | ||
![]() |
fefc7ea600 | ||
![]() |
d220389647 | ||
![]() |
a1f910c159 | ||
![]() |
e4866563de | ||
![]() |
47f45aa229 | ||
![]() |
affe334675 | ||
![]() |
ee7e184e26 | ||
![]() |
bec0ebacf1 | ||
![]() |
5bd6d631c6 | ||
![]() |
fd1799f3bb | ||
![]() |
d84a0c51e0 | ||
![]() |
d9a7c7de51 | ||
![]() |
d57e09889a | ||
![]() |
eecb86bfb0 | ||
![]() |
0b1197936c | ||
![]() |
b545ac6391 | ||
![]() |
a922132e4a | ||
![]() |
9474e8d6d2 | ||
![]() |
6328428568 | ||
![]() |
ea9a88a9b8 | ||
![]() |
aec7358ca4 | ||
![]() |
3c334b2bb6 | ||
![]() |
75bba0da92 | ||
![]() |
c0bfe7be15 | ||
![]() |
22ac08e06d | ||
![]() |
87037136ef | ||
![]() |
2182e37433 | ||
![]() |
1de82b220d | ||
![]() |
bd878756fc | ||
![]() |
8d7f402efb | ||
![]() |
d3299beec7 | ||
![]() |
f9192db358 | ||
![]() |
c69c0c0446 | ||
![]() |
deb2911c0e | ||
![]() |
e31a306a38 | ||
![]() |
d9a7773011 | ||
![]() |
2b14916813 | ||
![]() |
1d1530e14c | ||
![]() |
b4fdc025a8 | ||
![]() |
f1c14fe0b4 | ||
![]() |
38306cda54 | ||
![]() |
5a0f0023cf | ||
![]() |
6dcdb8b821 | ||
![]() |
781f52a287 | ||
![]() |
f75ff58b4b | ||
![]() |
ae9bf16dee | ||
![]() |
17a8bf212f | ||
![]() |
4fc76afef4 | ||
![]() |
a31155a72a | ||
![]() |
75601f7924 | ||
![]() |
8b6314ccfb | ||
![]() |
6de7dc5879 |
1957
CHANGES.2001
Normal file
1957
CHANGES.2001
Normal file
File diff suppressed because it is too large
Load Diff
@@ -2,12 +2,11 @@
|
||||
# $Id$
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
AUTOMAKE_OPTIONS = foreign
|
||||
|
||||
EXTRA_DIST = \
|
||||
CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt \
|
||||
reconf Makefile.dist curl-config.in build_vms.com curl-mode.el \
|
||||
config-vms.h config-win32.h config-riscos.h config-mac.h
|
||||
reconf Makefile.dist curl-config.in build_vms.com curl-mode.el
|
||||
|
||||
bin_SCRIPTS = curl-config
|
||||
|
||||
|
@@ -5,7 +5,7 @@
|
||||
# | (__| |_| | _ <| |___
|
||||
# \___|\___/|_| \_\_____|
|
||||
#
|
||||
# Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
# Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
#
|
||||
# In order to be useful for every potential user, curl and libcurl are
|
||||
# dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@@ -51,6 +51,12 @@ vc-ssl:
|
||||
cd lib
|
||||
nmake -f Makefile.vc6 cfg=release-ssl
|
||||
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
|
||||
|
||||
cygwin:
|
||||
|
@@ -176,7 +176,7 @@ AC_DEFUN([TYPE_IN_ADDR_T],
|
||||
AC_DEFINE_UNQUOTED(in_addr_t, $curl_cv_in_addr_t_equiv,
|
||||
[type to use in place of in_addr_t if not defined])],
|
||||
[#include <sys/types.h>
|
||||
#include <sys/socket.h>,
|
||||
#include <sys/socket.h>
|
||||
#include <arpa/inet.h>])
|
||||
])
|
||||
|
||||
@@ -377,6 +377,7 @@ AC_DEFUN(CURL_CHECK_GETHOSTBYNAME_R,
|
||||
|
||||
int
|
||||
gethostbyname_r(const char *, struct hostent *, struct hostent_data *);],[
|
||||
struct hostent_data data;
|
||||
gethostbyname_r(NULL, NULL, NULL);],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GETHOSTBYNAME_R_3)
|
||||
@@ -394,6 +395,7 @@ gethostbyname_r(NULL, NULL, NULL);],[
|
||||
|
||||
int
|
||||
gethostbyname_r(const char *,struct hostent *, struct hostent_data *);],[
|
||||
struct hostent_data data;
|
||||
gethostbyname_r(NULL, NULL, NULL);],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_GETHOSTBYNAME_R_3)
|
||||
|
@@ -6,14 +6,16 @@ $ loc = f$environment("PROCEDURE")
|
||||
$ def = f$parse("X.X;1",loc) - "X.X;1"
|
||||
$
|
||||
$ 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. "DEBUG" then cc_qual = cc_qual + "/LIST/MACHINE/DEBUG"
|
||||
$ msg_qual = ""
|
||||
$ call build "[.lib]" "*.c"
|
||||
$ call build "[.src]" "*.c"
|
||||
$ 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
|
||||
|
12
configure.in
12
configure.in
@@ -8,7 +8,7 @@ AC_PREREQ(2.50)
|
||||
dnl First some basic init macros
|
||||
AC_INIT
|
||||
AC_CONFIG_SRCDIR([lib/urldata.h])
|
||||
AM_CONFIG_HEADER(config.h src/config.h)
|
||||
AM_CONFIG_HEADER(lib/config.h src/config.h tests/server/config.h)
|
||||
|
||||
dnl figure out the libcurl version
|
||||
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)
|
||||
|
||||
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 ],
|
||||
AC_MSG_RESULT(no)
|
||||
@@ -524,9 +524,9 @@ AC_HEADER_TIME
|
||||
# mprintf() checks:
|
||||
|
||||
# check for 'long double'
|
||||
AC_CHECK_SIZEOF(long double, 8)
|
||||
# AC_CHECK_SIZEOF(long double, 8)
|
||||
# check for 'long long'
|
||||
AC_CHECK_SIZEOF(long long, 4)
|
||||
# AC_CHECK_SIZEOF(long long, 4)
|
||||
|
||||
# check for ssize_t
|
||||
AC_CHECK_TYPE(ssize_t, int)
|
||||
@@ -594,12 +594,14 @@ dnl AC_SUBST(RANLIB)
|
||||
AC_CONFIG_FILES([Makefile \
|
||||
docs/Makefile \
|
||||
docs/examples/Makefile \
|
||||
docs/libcurl/Makefile \
|
||||
include/Makefile \
|
||||
include/curl/Makefile \
|
||||
src/Makefile \
|
||||
lib/Makefile \
|
||||
tests/Makefile \
|
||||
tests/data/Makefile \
|
||||
tests/server/Makefile \
|
||||
packages/Makefile \
|
||||
packages/Win32/Makefile \
|
||||
packages/Win32/cygwin/Makefile \
|
||||
@@ -608,6 +610,8 @@ AC_CONFIG_FILES([Makefile \
|
||||
packages/Linux/RPM/curl.spec \
|
||||
packages/Linux/RPM/curl-ssl.spec \
|
||||
packages/Solaris/Makefile \
|
||||
packages/EPM/curl.list \
|
||||
packages/EPM/Makefile \
|
||||
curl-config
|
||||
])
|
||||
AC_OUTPUT
|
||||
|
@@ -16,6 +16,7 @@ Usage: curl-config [OPTION]
|
||||
|
||||
Available values for OPTION include:
|
||||
|
||||
--cc compiler
|
||||
--cflags pre-processor and compiler flags
|
||||
--feature newline separated list of enabled features
|
||||
--help display this help and exit
|
||||
@@ -42,6 +43,10 @@ while test $# -gt 0; do
|
||||
esac
|
||||
|
||||
case "$1" in
|
||||
--cc)
|
||||
echo @CC@
|
||||
;;
|
||||
|
||||
--prefix)
|
||||
echo $prefix
|
||||
;;
|
||||
|
10
docs/BUGS
10
docs/BUGS
@@ -23,11 +23,16 @@ BUGS
|
||||
|
||||
When reporting a bug, you should include information that will help us
|
||||
understand what's wrong, what you expected to happen and how to repeat the
|
||||
bad behaviour. You therefore need to supply your operating system's name and
|
||||
bad behavior. You therefore need to supply your operating system's name and
|
||||
version number (uname -a under a unix is fine), what version of curl you're
|
||||
using (curl -V is fine), what URL you were working with and anything else
|
||||
you think matters.
|
||||
|
||||
Since curl deals with networks, it often helps us a lot if you include a
|
||||
protocol debug dump with your bug report. The output you get by using the -v
|
||||
flag. Usually, you also get more info by using -i so that is likely to be
|
||||
useful when reporting bugs as well.
|
||||
|
||||
If curl crashed, causing a core dump (in unix), there is hardly any use to
|
||||
send that huge file to anyone of us. Unless we have an exact same system
|
||||
setup as you, we can't do much with it. What we instead ask of you is to get
|
||||
@@ -36,8 +41,7 @@ BUGS
|
||||
The address and how to subscribe to the mailing list is detailed in the
|
||||
MANUAL file.
|
||||
|
||||
How To Get A Stack Trace
|
||||
========================
|
||||
HOW TO GET A STACK TRACE
|
||||
|
||||
First, you must make sure that you compile all sources with -g and that you
|
||||
don't 'strip' the final executable. Try to avoid optimizing the code as
|
||||
|
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?
|
||||
|
||||
Project cURL is entirely free and open, without any commercial interests or
|
||||
money involved. No person gets paid in any way for developing curl. We all
|
||||
do this voluntarily on our spare time.
|
||||
Project cURL is entirely free and open. No person gets paid in any way for
|
||||
developing curl. We all do this voluntarily on our spare time.
|
||||
|
||||
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
|
||||
|
48
docs/INSTALL
48
docs/INSTALL
@@ -179,8 +179,8 @@ Win32
|
||||
to use out-of-the-box.
|
||||
|
||||
Microsoft note: add /Zm200 to the compiler options to increase the
|
||||
compiler's memory allocation limit, as the hugehelp.c won't compile
|
||||
due to "too long puts string".
|
||||
compiler's memory allocation limit, as the hugehelp.c won't compile
|
||||
due to "too long puts string".
|
||||
|
||||
|
||||
With SSL:
|
||||
@@ -203,15 +203,32 @@ Win32
|
||||
----------------------------
|
||||
Please read the OpenSSL documentation on how to compile and install
|
||||
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
|
||||
set. Edit the makefile.vc6 in the lib directory and define
|
||||
OPENSSL_PATH. Set the location of the OpenSSL library and run 'nmake
|
||||
vc-ssl' in the root directory.
|
||||
set. The vcvars32.bat file is part of the Microsoft development
|
||||
environment and you may find it in 'C:\Program Files\Microsoft Visual
|
||||
Studio\vc98\bin' if you installed Visual C/C++ 6 in the default
|
||||
directory.
|
||||
|
||||
The vcvars32.bat file is part of the Microsoft development
|
||||
environment.
|
||||
Before running nmake define the OPENSSL_PATH environment variable with
|
||||
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
|
||||
-------------------------
|
||||
@@ -322,6 +339,20 @@ VMS
|
||||
13-jul-2001
|
||||
N. Baggus
|
||||
|
||||
QNX
|
||||
===
|
||||
(This section was graciously brought to us by David Bentham)
|
||||
|
||||
As QNX is targetted for resource constrained environments, the QNX headers
|
||||
set conservative limits. This includes the FD_SETSIZE macro, set by default
|
||||
to 32. Socket descriptors returned within the CURL library may exceed this,
|
||||
resulting in memory faults/SIGSEGV crashes when passed into select(..)
|
||||
calls using fd_set macros.
|
||||
|
||||
A good all-round solution to this is to override the default when building
|
||||
libcurl, by overriding CFLAGS during configure, example
|
||||
# configure CFLAGS='-DFD_SETSIZE=64 -g -O2'
|
||||
|
||||
CROSS COMPILE
|
||||
=============
|
||||
|
||||
@@ -377,6 +408,7 @@ PORTS
|
||||
- HP-PA Linux
|
||||
- MIPS IRIX 6.2, 6.5
|
||||
- MIPS Linux
|
||||
- Pocket PC/Win CE 3.0
|
||||
- Power AIX 4.2, 4.3.1, 4.3.2
|
||||
- PowerPC Darwin 1.0
|
||||
- PowerPC Linux
|
||||
|
@@ -54,7 +54,7 @@ Windows vs Unix
|
||||
Inside the source code, We make an effort to avoid '#ifdef [Your OS]'. All
|
||||
conditionals that deal with features *should* instead be in the format
|
||||
'#ifdef HAVE_THAT_WEIRD_FUNCTION'. Since Windows can't run configure scripts,
|
||||
we maintain two config-win32.h files (one in / and one in src/) that are
|
||||
we maintain two config-win32.h files (one in lib/ and one in src/) that are
|
||||
supposed to look exactly as a config.h file would have looked like on a
|
||||
Windows machine!
|
||||
|
||||
@@ -69,10 +69,10 @@ Library
|
||||
rather small and easy-to-follow. All the ones prefixed with 'curl_easy' are
|
||||
put in the lib/easy.c file.
|
||||
|
||||
Starting with libcurl 7.8, curl_global_init_() and curl_global_cleanup() were
|
||||
introduced. They should be called by the application to initialize and clean
|
||||
up global stuff in the library. As of today, they just do the global SSL
|
||||
initing if SSL is enabled. libcurl itself has no "global" scope.
|
||||
curl_global_init_() and curl_global_cleanup() should be called by the
|
||||
application to initialize and clean up global stuff in the library. As of
|
||||
today, it can handle the global SSL initing if SSL is enabled and it can init
|
||||
the socket layer on windows machines. libcurl itself has no "global" scope.
|
||||
|
||||
All printf()-style functions use the supplied clones in lib/mprintf.c. This
|
||||
makes sure we stay absolutely platform independent.
|
||||
|
14
docs/KNOWN_BUGS
Normal file
14
docs/KNOWN_BUGS
Normal file
@@ -0,0 +1,14 @@
|
||||
These are problems known to exist at the time of this release. Feel free to
|
||||
join in and help us correct one or more of these! Also be sure to check the
|
||||
changelog of the current development status, as one or more of these problems
|
||||
may have been fixed since this was written!
|
||||
|
||||
* curl_formadd() fails on OSF1. Why? Fix! Need help from OSF1 dudes.
|
||||
https://sourceforge.net/tracker/index.php?func=detail&aid=524433&group_id=976&atid=100976
|
||||
|
||||
* Running 'make test' on Mac OS X gives 4 errors. This seems to be related
|
||||
to some kind of libtool problem:
|
||||
http://curl.haxx.se/mail/archive-2002-03/0029.html and
|
||||
http://curl.haxx.se/mail/archive-2002-03/0033.html
|
||||
|
||||
* libcurl does not deal nicely with files larger than 2GB
|
34
docs/MANUAL
34
docs/MANUAL
@@ -246,25 +246,25 @@ POST (HTTP)
|
||||
-F accepts parameters like -F "name=contents". If you want the contents to
|
||||
be read from a file, use <@filename> as contents. When specifying a file,
|
||||
you can also specify the file content type by appending ';type=<mime type>'
|
||||
to the file name. You can also post the contents of several files in one field.
|
||||
For example, the field name 'coolfiles' is used to send three files, with
|
||||
different content types using the following syntax:
|
||||
to the file name. You can also post the contents of several files in one
|
||||
field. For example, the field name 'coolfiles' is used to send three files,
|
||||
with different content types using the following syntax:
|
||||
|
||||
curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html" \
|
||||
http://www.post.com/postit.cgi
|
||||
|
||||
If the content-type is not specified, curl will try to guess from the file
|
||||
extension (it only knows a few), or use the previously specified type
|
||||
(from an earlier file if several files are specified in a list) or else it
|
||||
will using the default type 'text/plain'.
|
||||
extension (it only knows a few), or use the previously specified type (from
|
||||
an earlier file if several files are specified in a list) or else it will
|
||||
using the default type 'text/plain'.
|
||||
|
||||
Emulate a fill-in form with -F. Let's say you fill in three fields in a
|
||||
form. One field is a file name which to post, one field is your name and one
|
||||
field is a file description. We want to post the file we have written named
|
||||
"cooltext.txt". To let curl do the posting of this data instead of your
|
||||
favourite browser, you have to read the HTML source of the form page and find
|
||||
the names of the input fields. In our example, the input field names are
|
||||
'file', 'yourname' and 'filedescription'.
|
||||
favourite browser, you have to read the HTML source of the form page and
|
||||
find the names of the input fields. In our example, the input field names
|
||||
are 'file', 'yourname' and 'filedescription'.
|
||||
|
||||
curl -F "file=@cooltext.txt" -F "yourname=Daniel" \
|
||||
-F "filedescription=Cool text file with cool text inside" \
|
||||
@@ -601,15 +601,15 @@ RESUMING FILE TRANSFERS
|
||||
|
||||
Continue downloading a document:
|
||||
|
||||
curl -c -o file ftp://ftp.server.com/path/file
|
||||
curl -C - -o file ftp://ftp.server.com/path/file
|
||||
|
||||
Continue uploading a document(*1):
|
||||
|
||||
curl -c -T file ftp://ftp.server.com/path/file
|
||||
curl -C - -T file ftp://ftp.server.com/path/file
|
||||
|
||||
Continue downloading a document from a web server(*2):
|
||||
|
||||
curl -c -o file http://www.server.com/
|
||||
curl -C - -o file http://www.server.com/
|
||||
|
||||
(*1) = This requires that the ftp server supports the non-standard command
|
||||
SIZE. If it doesn't, curl will say so.
|
||||
@@ -668,8 +668,14 @@ LDAP
|
||||
and offer ldap:// support.
|
||||
|
||||
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
|
||||
no other place is better.
|
||||
advice you to dig up the syntax description for that elsewhere. Two places
|
||||
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
|
||||
server that has a certain sub-domain in their email address:
|
||||
|
@@ -6,69 +6,24 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
|
||||
man_MANS = \
|
||||
curl.1 \
|
||||
curl-config.1 \
|
||||
curl_easy_cleanup.3 \
|
||||
curl_easy_getinfo.3 \
|
||||
curl_easy_init.3 \
|
||||
curl_easy_perform.3 \
|
||||
curl_easy_setopt.3 \
|
||||
curl_easy_duphandle.3 \
|
||||
curl_formparse.3 \
|
||||
curl_formadd.3 \
|
||||
curl_formfree.3 \
|
||||
curl_getdate.3 \
|
||||
curl_getenv.3 \
|
||||
curl_slist_append.3 \
|
||||
curl_slist_free_all.3 \
|
||||
curl_version.3 \
|
||||
curl_escape.3 \
|
||||
curl_unescape.3 \
|
||||
curl_strequal.3 \
|
||||
curl_strnequal.3 \
|
||||
curl_mprintf.3 \
|
||||
curl_global_init.3 \
|
||||
curl_global_cleanup.3 \
|
||||
libcurl.3
|
||||
|
||||
SUBDIRS = examples
|
||||
curl-config.1
|
||||
|
||||
HTMLPAGES = \
|
||||
curl.html \
|
||||
curl-config.html \
|
||||
curl_easy_cleanup.html \
|
||||
curl_easy_getinfo.html \
|
||||
curl_easy_init.html \
|
||||
curl_easy_perform.html \
|
||||
curl_easy_setopt.html \
|
||||
curl_easy_duphandle.html \
|
||||
curl_formadd.html \
|
||||
curl_formparse.html \
|
||||
curl_formfree.html \
|
||||
curl_getdate.html \
|
||||
curl_getenv.html \
|
||||
curl_slist_append.html \
|
||||
curl_slist_free_all.html \
|
||||
curl_version.html \
|
||||
curl_escape.html \
|
||||
curl_unescape.html \
|
||||
curl_strequal.html \
|
||||
curl_strnequal.html \
|
||||
curl_mprintf.html \
|
||||
curl_global_init.html \
|
||||
curl_global_cleanup.html \
|
||||
libcurl.html \
|
||||
index.html
|
||||
curl-config.html
|
||||
|
||||
EXTRA_DIST = $(man_MANS) \
|
||||
MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS \
|
||||
README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS \
|
||||
VERSIONS $(HTMLPAGES)
|
||||
SUBDIRS = examples libcurl
|
||||
|
||||
EXTRA_DIST = MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS \
|
||||
README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS \
|
||||
VERSIONS KNOWN_BUGS $(man_MANS) $(HTMLPAGES)
|
||||
|
||||
MAN2HTML= gnroff -man $< | man2html >$@
|
||||
|
||||
SUFFIXES = .1 .3 .html
|
||||
|
||||
html: $(HTMLPAGES)
|
||||
cd libcurl; make html
|
||||
|
||||
.3.html:
|
||||
$(MAN2HTML)
|
||||
|
122
docs/TODO
122
docs/TODO
@@ -19,10 +19,7 @@ TODO
|
||||
|
||||
* The new 'multi' interface is being designed. Work out the details, start
|
||||
implementing and write test applications!
|
||||
[http://curl.haxx.se/dev/multi.h]
|
||||
|
||||
* Add a name resolve cache to libcurl to make repeated fetches to the same
|
||||
host name (when persitancy isn't available) faster.
|
||||
[http://curl.haxx.se/lxr/source/lib/multi.h]
|
||||
|
||||
* Introduce another callback interface for upload/download that makes one
|
||||
less copy of data and thus a faster operation.
|
||||
@@ -33,13 +30,36 @@ TODO
|
||||
telnet, ldap, dict or file.
|
||||
|
||||
* 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
|
||||
|
||||
* 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
|
||||
|
||||
@@ -54,19 +74,24 @@ TODO
|
||||
already working http dito works. It of course requires that 'MDTM' works,
|
||||
and it isn't a standard FTP command.
|
||||
|
||||
* Suggested on the mailing list: CURLOPT_FTP_MKDIR...!
|
||||
|
||||
* 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!
|
||||
* Add FTPS support with SSL for the data connection too.
|
||||
|
||||
HTTP
|
||||
|
||||
* Make it possible to supply normal POST data through the ordinary read data
|
||||
callback.
|
||||
|
||||
* HTTP PUT for files passed on stdin *OR* when the --crlf option is
|
||||
used. Requires libcurl to send the file with chunked content
|
||||
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.
|
||||
|
||||
* 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
|
||||
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
|
||||
@@ -83,34 +108,66 @@ TODO
|
||||
http://www.innovation.ch/java/ntlm.html that contains detailed reverse-
|
||||
engineered info.
|
||||
|
||||
* RFC2617 compliance, "Digest Access Authentication"
|
||||
A valid test page seem to exist at:
|
||||
http://hopf.math.nwu.edu/testpage/digest/
|
||||
And some friendly person's server source code is available at
|
||||
http://hopf.math.nwu.edu/digestauth/index.html
|
||||
Then there's the Apache mod_digest source code too of course. It seems as
|
||||
if Netscape doesn't support this, and not many servers do. Although this is
|
||||
a lot better authentication method than the more common "Basic". Basic
|
||||
sends the password in cleartext over the network, this "Digest" method uses
|
||||
a challange-response protocol which increases security quite a lot.
|
||||
* RFC2617 compliance, "Digest Access Authentication" A valid test page seem
|
||||
to exist at: http://hopf.math.nwu.edu/testpage/digest/ And some friendly
|
||||
person's server source code is available at
|
||||
http://hopf.math.nwu.edu/digestauth/index.html Then there's the Apache
|
||||
mod_digest source code too of course. It seems as if Netscape doesn't
|
||||
support this, and not many servers do. Although this is a lot better
|
||||
authentication method than the more common "Basic". Basic sends the
|
||||
password in cleartext over the network, this "Digest" method uses 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
|
||||
|
||||
* 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
|
||||
|
||||
* 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
|
||||
exported/imported. Cris Bailiff said: "OpenSSL has functions which can
|
||||
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
|
||||
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.
|
||||
Such as the Mozilla Security Services
|
||||
(http://www.mozilla.org/projects/security/pki/nss/) and GNUTLS
|
||||
(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
|
||||
|
||||
* "curl ftp://site.com/*.txt"
|
||||
@@ -119,11 +176,22 @@ TODO
|
||||
the same syntax to specify several files to get uploaded (using the same
|
||||
persistant connection), using -T.
|
||||
|
||||
* Say you have a list of FTP addresses to download in a file named
|
||||
ftp-list.txt: "cat ftp-list.txt | xargs curl -O -O -O [...]". curl _needs_
|
||||
an "-Oalways" flag -- all addresses on the command line use the base
|
||||
filename to store locally. Else a script must precount the # of URLs,
|
||||
construct the proper number of "-O"s...
|
||||
* When the multi interface has been implemented and proved to work, the
|
||||
client could be told to use maximum N simultaneous transfers and then just
|
||||
make sure that happens. It should of course not make more than one
|
||||
connection to the same remote host.
|
||||
|
||||
* Extending the capabilities of the multipart formposting. How about leaving
|
||||
the ';type=foo' syntax as it is and adding an extra tag (headers) which
|
||||
works like this: curl -F "coolfiles=@fil1.txt;headers=@fil1.hdr" where
|
||||
fil1.hdr contains extra headers like
|
||||
|
||||
Content-Type: text/plain; charset=KOI8-R"
|
||||
Content-Transfer-Encoding: base64
|
||||
X-User-Comment: Please don't use browser specific HTML code
|
||||
|
||||
which should overwrite the program reasonable defaults (plain/text,
|
||||
8bit...) (Idea brough to us by kromJx)
|
||||
|
||||
TEST SUITE
|
||||
|
||||
|
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man curl-config.1
|
||||
.\" 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
|
||||
curl-config \- Get information about a libcurl installation
|
||||
.SH SYNOPSIS
|
||||
@@ -11,6 +11,8 @@ curl-config \- Get information about a libcurl installation
|
||||
.B curl-config
|
||||
displays information about a previous curl and libcurl installation.
|
||||
.SH OPTIONS
|
||||
.IP "--cc"
|
||||
Displays the compiler used to build libcurl.
|
||||
.IP "--cflags"
|
||||
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.
|
||||
@@ -38,18 +40,23 @@ major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl
|
||||
.SH "EXAMPLES"
|
||||
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?
|
||||
|
||||
curl-config --cflags
|
||||
$ curl-config --cflags
|
||||
|
||||
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?
|
||||
|
||||
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"
|
||||
.BR curl (1)
|
||||
|
11
docs/curl.1
11
docs/curl.1
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man curl.1
|
||||
.\" Written by Daniel Stenberg
|
||||
.\"
|
||||
.TH curl 1 "30 Nov 2001" "Curl 7.9.2" "Curl Manual"
|
||||
.TH curl 1 "25 Feb 2002" "Curl 7.9.5" "Curl Manual"
|
||||
.SH NAME
|
||||
curl \- transfer a URL
|
||||
.SH SYNOPSIS
|
||||
@@ -510,7 +510,7 @@ password is specified, curl will ask for it interactively.
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
.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.
|
||||
|
||||
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
|
||||
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
|
||||
%%. 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.
|
||||
|
||||
.B NOTE:
|
||||
@@ -594,6 +594,9 @@ The average download speed that curl measured for the complete download.
|
||||
.TP
|
||||
.B speed_upload
|
||||
The average upload speed that curl measured for the complete upload.
|
||||
.TP
|
||||
.B content_type
|
||||
The Content-Type of the requested document, if there was any. (Added in 7.9.5)
|
||||
.RE
|
||||
|
||||
If this option is used several times, the last one will be used.
|
||||
@@ -788,7 +791,7 @@ Internal error. A function was called in a bad order.
|
||||
.IP 45
|
||||
Interface error. A specified outgoing interface could not be used.
|
||||
.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
|
||||
Too many redirects. When following redirects, curl hit the maximum amount.
|
||||
.IP 48
|
||||
|
@@ -1,29 +0,0 @@
|
||||
.\" You can view this file with:
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_cleanup 3 "5 March 2001" "libcurl 7.7" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_cleanup - End a libcurl session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "void curl_easy_cleanup(CURL *" handle ");"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function must be the last function to call for a curl session. It is the
|
||||
opposite of the
|
||||
.I curl_easy_init
|
||||
function and must be called with the same
|
||||
.I handle
|
||||
as input as the curl_easy_init call returned.
|
||||
|
||||
This will effectively close all connections libcurl has been used and possibly
|
||||
has kept open until now. Don't call this function if you intend to transfer
|
||||
more files (libcurl 7.7 or later).
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_easy_init "(3), "
|
||||
.SH BUGS
|
||||
Surely there are some, you tell me!
|
@@ -1,34 +0,0 @@
|
||||
.\" You can view this file with:
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_init 3 "14 August 2001" "libcurl 7.8.1" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_init - Start a libcurl session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "CURL *curl_easy_init( );"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function must be the first function to call, and it returns a CURL handle
|
||||
that you shall use as input to the other easy-functions. The init calls
|
||||
intializes curl and this call MUST have a corresponding call to
|
||||
.I curl_easy_cleanup
|
||||
when the operation is complete.
|
||||
|
||||
On win32 systems, if you want to init the winsock stuff manually, libcurl will
|
||||
not do that for you. WSAStartup() and WSACleanup() should then be called
|
||||
accordingly. If you want libcurl to handle this, use the CURL_GLOBAL_WIN32
|
||||
flag in the initial curl_global_init() call.
|
||||
|
||||
Using libcurl 7.7 and later, you should perform all your sequential file
|
||||
transfers using the same curl handle. This enables libcurl to use persistant
|
||||
connections where possible.
|
||||
.SH RETURN VALUE
|
||||
If this function returns NULL, something went wrong and you cannot use the
|
||||
other curl functions.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_easy_cleanup "(3), " curl_global_init "(3)
|
||||
.SH BUGS
|
||||
Surely there are some, you tell me!
|
@@ -4,10 +4,10 @@
|
||||
|
||||
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 \
|
||||
multithread.c getinmemory.c ftpupload.c httpput.c \
|
||||
simplessl.c
|
||||
simplessl.c ftpgetresp.c http-post.c
|
||||
|
||||
all:
|
||||
@echo "done"
|
||||
|
@@ -10,6 +10,10 @@ them for submission in future packages and on the web site.
|
||||
The Makefile.example is an example makefile that could be used to build these
|
||||
examples. Just edit the file according to your system and requirements first.
|
||||
|
||||
Most examples should build fine using a command line like this:
|
||||
|
||||
$ gcc `curl-config --cflags` `curl-config --libs` -o example example.c
|
||||
|
||||
Try the php/examples/ directory for PHP programming snippets!
|
||||
|
||||
*PLEASE* do not use the curl.haxx.se site as a test target for your libcurl
|
||||
|
@@ -14,31 +14,70 @@
|
||||
#include <curl/types.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
/* to make this work under windows, use the win32-functions from the
|
||||
win32socket.c file as well */
|
||||
/*
|
||||
* This is an example showing how to get a single file from an FTP server.
|
||||
* It delays the actual destination file creation until the first write
|
||||
* callback so that it won't create an empty file in case the remote file
|
||||
* doesn't exist or something else fails.
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
struct FtpFile {
|
||||
char *filename;
|
||||
FILE *stream;
|
||||
};
|
||||
|
||||
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
|
||||
{
|
||||
struct FtpFile *out=(struct FtpFile *)stream;
|
||||
if(out && !out->stream) {
|
||||
/* open file for writing */
|
||||
out->stream=fopen(out->filename, "wb");
|
||||
if(!out->stream)
|
||||
return -1; /* failure, can't open file to write */
|
||||
}
|
||||
return fwrite(buffer, size, nmemb, out->stream);
|
||||
}
|
||||
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
FILE *ftpfile;
|
||||
struct FtpFile ftpfile={
|
||||
"curl.tar.gz", /* name to store the file as if succesful */
|
||||
NULL
|
||||
};
|
||||
|
||||
/* local file name to store the file as */
|
||||
ftpfile = fopen("curl.tar.gz", "wb"); /* b is binary for win */
|
||||
curl_global_init(CURL_GLOBAL_DEFAULT);
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
/* Get curl 7.7 from sunet.se's FTP site: */
|
||||
/* Get curl 7.9.2 from sunet.se's FTP site: */
|
||||
curl_easy_setopt(curl, CURLOPT_URL,
|
||||
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.7.tar.gz");
|
||||
curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
|
||||
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.9.2.tar.gz");
|
||||
/* Define our callback to get called when there's data to be written */
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
|
||||
/* Set a pointer to our struct to pass to the callback */
|
||||
curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile);
|
||||
|
||||
/* Switch on full protocol/debug output */
|
||||
curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
|
||||
if(CURLE_OK != res) {
|
||||
/* we failed */
|
||||
fprintf(stderr, "curl told us %d\n", res);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(ftpfile); /* close the local file */
|
||||
if(ftpfile.stream)
|
||||
fclose(ftpfile.stream); /* close the local file */
|
||||
|
||||
curl_global_cleanup();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
61
docs/examples/ftpgetresp.c
Normal file
61
docs/examples/ftpgetresp.c
Normal file
@@ -0,0 +1,61 @@
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/types.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
/*
|
||||
* Similar to ftpget.c but this also stores the received response-lines
|
||||
* in a separate file using our own callback!
|
||||
*
|
||||
* This functionality was introduced in libcurl 7.9.3.
|
||||
*/
|
||||
|
||||
size_t
|
||||
write_response(void *ptr, size_t size, size_t nmemb, void *data)
|
||||
{
|
||||
FILE *writehere = (FILE *)data;
|
||||
return fwrite(ptr, size, nmemb, writehere);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
FILE *ftpfile;
|
||||
FILE *respfile;
|
||||
|
||||
/* local file name to store the file as */
|
||||
ftpfile = fopen("ftp-list", "wb"); /* b is binary, needed on win32 */
|
||||
|
||||
/* local file name to store the FTP server's response lines in */
|
||||
respfile = fopen("ftp-responses", "wb"); /* b is binary, needed on win32 */
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
/* Get a file listing from sunet */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.sunet.se/");
|
||||
curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
|
||||
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response);
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, respfile);
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
|
||||
fclose(ftpfile); /* close the local file */
|
||||
fclose(respfile); /* close the response file */
|
||||
|
||||
return 0;
|
||||
}
|
35
docs/examples/http-post.c
Normal file
35
docs/examples/http-post.c
Normal file
@@ -0,0 +1,35 @@
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* $Id$
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
/* First set the URL that is about to receive our POST. This URL can
|
||||
just as well be a https:// URL if that is what should receive the
|
||||
data. */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
|
||||
/* Now specify the POST data */
|
||||
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
|
||||
|
||||
/* Perform the request, res will get the return code */
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
/* always cleanup */
|
||||
curl_easy_cleanup(curl);
|
||||
}
|
||||
return 0;
|
||||
}
|
92
docs/examples/multi-app.c
Normal file
92
docs/examples/multi-app.c
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* This is an example application source code using the multi interface.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* somewhat unix-specific */
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
||||
/* To start with, we include the header from the lib directory. This should
|
||||
later of course be moved to the proper include dir. */
|
||||
#include "../lib/multi.h"
|
||||
|
||||
/*
|
||||
* Download a HTTP file and upload an FTP file simultaneously.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CURL *http_handle;
|
||||
CURL *ftp_handle;
|
||||
CURLM *multi_handle;
|
||||
|
||||
int still_running; /* keep number of running handles */
|
||||
|
||||
http_handle = curl_easy_init();
|
||||
ftp_handle = curl_easy_init();
|
||||
|
||||
/* set the options (I left out a few, you'll get the point anyway) */
|
||||
curl_easy_setopt(http_handle, CURLOPT_URL, "http://website.com");
|
||||
|
||||
curl_easy_setopt(ftp_handle, CURLOPT_URL, "ftp://ftpsite.com");
|
||||
curl_easy_setopt(ftp_handle, CURLOPT_UPLOAD, TRUE);
|
||||
|
||||
/* init a multi stack */
|
||||
multi_handle = curl_multi_init();
|
||||
|
||||
/* add the individual transfers */
|
||||
curl_multi_add_handle(multi_handle, http_handle);
|
||||
curl_multi_add_handle(multi_handle, ftp_handle);
|
||||
|
||||
/* we start some action by calling perform right away */
|
||||
while(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(multi_handle, &still_running));
|
||||
|
||||
while(still_running) {
|
||||
struct timeval timeout;
|
||||
int rc; /* select() return code */
|
||||
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
|
||||
/* set a suitable timeout to play around with */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* get file descriptors from the transfers */
|
||||
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
|
||||
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||
|
||||
switch(rc) {
|
||||
case -1:
|
||||
/* select error */
|
||||
break;
|
||||
case 0:
|
||||
/* timeout, do something else */
|
||||
break;
|
||||
default:
|
||||
/* one or more of curl's file descriptors say there's data to read
|
||||
or write */
|
||||
curl_multi_perform(multi_handle, &still_running);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
curl_multi_cleanup(multi_handle);
|
||||
|
||||
curl_easy_cleanup(http_handle);
|
||||
curl_easy_cleanup(ftp_handle);
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
87
docs/examples/multi-double.c
Normal file
87
docs/examples/multi-double.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This is a simple example using the multi interface.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* somewhat unix-specific */
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* To start with, we include the header from the lib directory. This should
|
||||
later of course be moved to the proper include dir. */
|
||||
#include "../lib/multi.h"
|
||||
|
||||
/*
|
||||
* Simply download two HTTP files!
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CURL *http_handle;
|
||||
CURL *http_handle2;
|
||||
CURLM *multi_handle;
|
||||
|
||||
int still_running; /* keep number of running handles */
|
||||
|
||||
http_handle = curl_easy_init();
|
||||
http_handle2 = curl_easy_init();
|
||||
|
||||
/* set options */
|
||||
curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.haxx.se/");
|
||||
|
||||
/* set options */
|
||||
curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/");
|
||||
|
||||
/* init a multi stack */
|
||||
multi_handle = curl_multi_init();
|
||||
|
||||
/* add the individual transfers */
|
||||
curl_multi_add_handle(multi_handle, http_handle);
|
||||
curl_multi_add_handle(multi_handle, http_handle2);
|
||||
|
||||
/* we start some action by calling perform right away */
|
||||
while(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(multi_handle, &still_running));
|
||||
|
||||
while(still_running) {
|
||||
struct timeval timeout;
|
||||
int rc; /* select() return code */
|
||||
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
|
||||
/* set a suitable timeout to play around with */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* get file descriptors from the transfers */
|
||||
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
|
||||
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||
|
||||
switch(rc) {
|
||||
case -1:
|
||||
/* select error */
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
/* timeout or readable/writable sockets */
|
||||
curl_multi_perform(multi_handle, &still_running);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
curl_multi_cleanup(multi_handle);
|
||||
|
||||
curl_easy_cleanup(http_handle);
|
||||
curl_easy_cleanup(http_handle2);
|
||||
|
||||
return 0;
|
||||
}
|
80
docs/examples/multi-single.c
Normal file
80
docs/examples/multi-single.c
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* This is a very simple example using the multi interface.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/* somewhat unix-specific */
|
||||
#include <sys/time.h>
|
||||
#include <unistd.h>
|
||||
|
||||
/* To start with, we include the header from the lib directory. This should
|
||||
later of course be moved to the proper include dir. */
|
||||
#include "../lib/multi.h"
|
||||
|
||||
/*
|
||||
* Simply download a HTTP file.
|
||||
*/
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
CURL *http_handle;
|
||||
CURLM *multi_handle;
|
||||
|
||||
int still_running; /* keep number of running handles */
|
||||
|
||||
http_handle = curl_easy_init();
|
||||
|
||||
/* set the options (I left out a few, you'll get the point anyway) */
|
||||
curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.haxx.se/");
|
||||
|
||||
/* init a multi stack */
|
||||
multi_handle = curl_multi_init();
|
||||
|
||||
/* add the individual transfers */
|
||||
curl_multi_add_handle(multi_handle, http_handle);
|
||||
|
||||
/* we start some action by calling perform right away */
|
||||
while(CURLM_CALL_MULTI_PERFORM ==
|
||||
curl_multi_perform(multi_handle, &still_running));
|
||||
|
||||
while(still_running) {
|
||||
struct timeval timeout;
|
||||
int rc; /* select() return code */
|
||||
|
||||
fd_set fdread;
|
||||
fd_set fdwrite;
|
||||
fd_set fdexcep;
|
||||
int maxfd;
|
||||
|
||||
FD_ZERO(&fdread);
|
||||
FD_ZERO(&fdwrite);
|
||||
FD_ZERO(&fdexcep);
|
||||
|
||||
/* set a suitable timeout to play around with */
|
||||
timeout.tv_sec = 1;
|
||||
timeout.tv_usec = 0;
|
||||
|
||||
/* get file descriptors from the transfers */
|
||||
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
|
||||
|
||||
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
|
||||
|
||||
switch(rc) {
|
||||
case -1:
|
||||
/* select error */
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
/* timeout or readable/writable sockets */
|
||||
curl_multi_perform(multi_handle, &still_running);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
curl_multi_cleanup(multi_handle);
|
||||
|
||||
curl_easy_cleanup(http_handle);
|
||||
|
||||
return 0;
|
||||
}
|
@@ -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;
|
||||
}
|
@@ -9,27 +9,16 @@
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <curl/curl.h>
|
||||
#include <curl/types.h>
|
||||
#include <curl/easy.h>
|
||||
|
||||
/* to make this work under windows, use the win32-functions from the
|
||||
win32socket.c file as well */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
int main(void)
|
||||
{
|
||||
CURL *curl;
|
||||
CURLcode res;
|
||||
FILE *headerfile;
|
||||
|
||||
headerfile = fopen("dumpit", "w");
|
||||
|
||||
curl = curl_easy_init();
|
||||
if(curl) {
|
||||
/* what call to write: */
|
||||
curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
|
||||
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, headerfile);
|
||||
res = curl_easy_perform(curl);
|
||||
|
||||
/* always cleanup */
|
||||
|
@@ -28,6 +28,9 @@
|
||||
4.2. if the format of the key file is DER, set pKeyType to "DER"
|
||||
|
||||
!! 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)
|
||||
@@ -37,6 +40,7 @@ int main(int argc, char **argv)
|
||||
FILE *headerfile;
|
||||
|
||||
const char *pCertFile = "testcert.pem";
|
||||
const char *pCACertFile="cacert.pem"
|
||||
|
||||
const char *pKeyName;
|
||||
const char *pKeyType;
|
||||
@@ -96,6 +100,10 @@ int main(int argc, char **argv)
|
||||
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE,pKeyType);
|
||||
/* set the private key (file or ID in engine) */
|
||||
curl_easy_setopt(curl,CURLOPT_SSLKEY,pKeyName);
|
||||
/* set the file with the certs vaildating the server */
|
||||
curl_easy_setopt(curl,CURLOPT_CAINFO,pCACertFile);
|
||||
/* disconnect if we can't validate server's cert */
|
||||
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,1);
|
||||
|
||||
res = curl_easy_perform(curl);
|
||||
break; /* we are done... */
|
||||
|
911
docs/libcurl-the-guide
Normal file
911
docs/libcurl-the-guide
Normal file
@@ -0,0 +1,911 @@
|
||||
$Id$
|
||||
_ _ ____ _
|
||||
___| | | | _ \| |
|
||||
/ __| | | | |_) | |
|
||||
| (__| |_| | _ <| |___
|
||||
\___|\___/|_| \_\_____|
|
||||
|
||||
PROGRAMMING WITH LIBCURL
|
||||
|
||||
About this Document
|
||||
|
||||
This document will attempt to describe the general principle and some basic
|
||||
approaches to consider when programming with libcurl. The text will focus
|
||||
mainly on the C interface but might apply fairly well on other interfaces as
|
||||
well as they usually follow the C one pretty closely.
|
||||
|
||||
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.
|
||||
What will be generally refered to as 'the program' will be the collected
|
||||
source code that you write that is using libcurl for transfers. 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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
The program must initialize some of the libcurl functionality globally. That
|
||||
means it should be done exactly once, no matter how many times you intend to
|
||||
use the library. Once for your program's entire life time. This is done using
|
||||
|
||||
curl_global_init()
|
||||
|
||||
and it takes one parameter which is a bit pattern that tells libcurl what to
|
||||
intialize. Using CURL_GLOBAL_ALL will make it initialize all known internal
|
||||
sub modules, and might be a good default option. The current two bits that
|
||||
are specified are:
|
||||
|
||||
CURL_GLOBAL_WIN32 which only does anything on Windows machines. When used on
|
||||
a Windows machine, it'll make libcurl intialize the win32 socket
|
||||
stuff. Without having that initialized properly, your program cannot use
|
||||
sockets properly. You should only do this once for each application, so if
|
||||
your program already does this or of another library in use does it, you
|
||||
should not tell libcurl to do this as well.
|
||||
|
||||
CURL_GLOBAL_SSL which only does anything on libcurls compiled and built
|
||||
SSL-enabled. On these systems, this will make libcurl init OpenSSL properly
|
||||
for this application. This is only needed to do once for each application so
|
||||
if your program or another library already does this, this bit should not be
|
||||
needed.
|
||||
|
||||
libcurl has a default protection mechanism that detects if curl_global_init()
|
||||
hasn't been called by the time curl_easy_perform() is called and if that is
|
||||
the case, libcurl runs the function itself with a guessed bit pattern. Please
|
||||
note that depending solely on this is not considered nice nor very good.
|
||||
|
||||
When the program no longer uses libcurl, it should call
|
||||
curl_global_cleanup(), which is the opposite of the init call. It will then
|
||||
do the reversed operations to cleanup the resources the curl_global_init()
|
||||
call initialized.
|
||||
|
||||
Repeated calls to curl_global_init() and curl_global_cleanup() should be
|
||||
avoided. They should only be called once each.
|
||||
|
||||
Handle the Easy libcurl
|
||||
|
||||
libcurl version 7 is oriented around the so called easy interface. All
|
||||
operations in the easy interface are prefixed with 'curl_easy'.
|
||||
|
||||
Future libcurls will also offer the multi interface. More about that
|
||||
interface, what it is targeted for and how to use it is still only debated on
|
||||
the libcurl mailing list and developer web pages. Join up to discuss and
|
||||
figure out!
|
||||
|
||||
To use the easy interface, you must first create yourself an easy handle. You
|
||||
need one handle for each easy session you want to perform. Basicly, you
|
||||
should use one handle for every thread you plan to use for transferring. You
|
||||
must never share the same handle in multiple threads.
|
||||
|
||||
Get an easy handle with
|
||||
|
||||
easyhandle = curl_easy_init();
|
||||
|
||||
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
|
||||
transfer or series of transfers.
|
||||
|
||||
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/");
|
||||
|
||||
Let's assume for a while that you want to receive data as the URL indentifies
|
||||
a remote resource you want to get here. Since you write a sort of application
|
||||
that needs this transfer, I assume that you would like to get the data passed
|
||||
to you directly instead of simply getting it passed to stdout. So, you write
|
||||
your own function that matches this prototype:
|
||||
|
||||
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
|
||||
|
||||
You tell libcurl to pass all data to this function by issuing a function
|
||||
similar to this:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data);
|
||||
|
||||
You can control what data your function get in the forth argument by setting
|
||||
another property:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_FILE, &internal_struct);
|
||||
|
||||
Using that property, you can easily pass local data between your application
|
||||
and the function that gets invoked by libcurl. libcurl itself won't touch the
|
||||
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
|
||||
few of them later. Let's instead continue to the actual transfer:
|
||||
|
||||
success = curl_easy_perform(easyhandle);
|
||||
|
||||
The curl_easy_perform() will connect to the remote site, do the necessary
|
||||
commands and receive the transfer. Whenever it receives data, it calls the
|
||||
callback function we previously set. The function may get one byte at a time,
|
||||
or it may get many kilobytes at once. libcurl delivers as much as possible as
|
||||
often as possible. Your callback function should return the number of bytes
|
||||
it "took care of". If that is not the exact same amount of bytes that was
|
||||
passed to it, libcurl will abort the operation and return with an error code.
|
||||
|
||||
When the transfer is complete, the function returns a return code that
|
||||
informs you if it succeeded in its mission or not. If a return code isn't
|
||||
enough for you, you can use the CURLOPT_ERRORBUFFER to point libcurl to a
|
||||
buffer of yours where it'll store a human readable error message as well.
|
||||
|
||||
If you then want to transfer another file, the handle is ready to be used
|
||||
again. Mind you, it is even preferred that you re-use an existing handle if
|
||||
you intend to make another transfer. libcurl will then attempt to re-use the
|
||||
previous
|
||||
|
||||
|
||||
When It Doesn't Work
|
||||
|
||||
There will always be times when the transfer fails for some reason. You might
|
||||
have set the wrong libcurl option or misunderstood what the libcurl option
|
||||
actually does, or the remote server might return non-standard replies that
|
||||
confuse the library which then confuses your program.
|
||||
|
||||
There's one golden rule when these things occur: set the CURLOPT_VERBOSE
|
||||
option to TRUE. It'll cause the library to spew out the entire protocol
|
||||
details it sends, some internal info and some received protcol data as well
|
||||
(especially when using FTP). If you're using HTTP, adding the headers in the
|
||||
received output to study is also a clever way to get a better understanding
|
||||
wht the server behaves the way it does. Include headers in the normal body
|
||||
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
|
||||
|
||||
libcurl tries to keep a protocol independent approach to most transfers, thus
|
||||
uploading to a remote FTP site is very similar to uploading data to a HTTP
|
||||
server with a PUT request.
|
||||
|
||||
Of course, first you either create an easy handle or you re-use one existing
|
||||
one. Then you set the URL to operate on just like before. This is the remote
|
||||
URL, that we now will upload.
|
||||
|
||||
Since we write an application, we most likely want libcurl to get the upload
|
||||
data by asking us for it. To make it do that, we set the read callback and
|
||||
the custom pointer libcurl will pass to our read callback. The read callback
|
||||
should have a prototype similar to:
|
||||
|
||||
size_t function(char *bufptr, size_t size, size_t nitems, void *userp);
|
||||
|
||||
Where bufptr is the pointer to a buffer we fill in with data to upload and
|
||||
size*nitems is the size of the buffer and therefore also the maximum amount
|
||||
of data we can return to libcurl in this call. The 'userp' pointer is the
|
||||
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_INFILE, &filedata);
|
||||
|
||||
Tell libcurl that we want to upload:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, TRUE);
|
||||
|
||||
A few protocols won't behave properly when uploads are done without any prior
|
||||
knowledge of the expected file size. HTTP PUT is one example [1]. So, set the
|
||||
upload file size using the CURLOPT_INFILESIZE like this:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, file_size);
|
||||
|
||||
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
|
||||
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
|
||||
fast as possible. The callback should return the number of bytes it wrote in
|
||||
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
|
||||
|
||||
For historical and traditional reasons, libcurl has a built-in progress meter
|
||||
that can be switched on and then makes it presents a progress meter in your
|
||||
terminal.
|
||||
|
||||
Switch on the progress meter by, oddly enough, set CURLOPT_NOPROGRESS to
|
||||
FALSE. This option is set to TRUE by default.
|
||||
|
||||
For most applications however, the built-in progress meter is useless and
|
||||
what instead is interesting is the ability to specify a progress
|
||||
callback. The function pointer you pass to libcurl will then be called on
|
||||
irregular intervals with information about the current transfer.
|
||||
|
||||
Set the progress callback by using CURLOPT_PROGRESSFUNCTION. And pass a
|
||||
pointer to a function that matches this prototype:
|
||||
|
||||
int progress_callback(void *clientp,
|
||||
double dltotal,
|
||||
double dlnow,
|
||||
double ultotal,
|
||||
double ulnow);
|
||||
|
||||
If any of the input arguments is unknown, a 0 will be passed. The first
|
||||
argument, the 'clientp' is the pointer you pass to libcurl with
|
||||
CURLOPT_PROGRESSDATA. libcurl won't touch it.
|
||||
|
||||
|
||||
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.
|
||||
|
||||
There's only one aspect left in the HTTP requests that we haven't yet
|
||||
mentioned how to modify: the version field. All HTTP requests includes the
|
||||
version number to tell the server which version we support. libcurl speak
|
||||
HTTP 1.1 by default. Some very old servers don't like getting 1.1-requests
|
||||
and when dealing with stubborn old things like that, you can tell libcurl to
|
||||
use 1.0 instead by doing something like this:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_HTTP_VERSION, CURLHTTP_VERSION_1_0);
|
||||
|
||||
Not all protocols are HTTP-like, and thus the above may not help you when you
|
||||
want to make for example your FTP transfers to behave differently.
|
||||
|
||||
Sending custom commands to a FTP server means that you need to send the
|
||||
comands exactly as the FTP server expects them (RFC959 is a good guide here),
|
||||
and you can only use commands that work on the control-connection alone. All
|
||||
kinds of commands that requires data interchange and thus needs a
|
||||
data-connection must be left to libcurl's own judgement. Also be aware that
|
||||
libcurl will do its very best to change directory to the target directory
|
||||
before doing any transfer, so if you change directory (with CWD or similar)
|
||||
you might confuse libcurl and then it might not attempt to transfer the file
|
||||
in the correct remote directory.
|
||||
|
||||
A little example that deletes a given file before an operation:
|
||||
|
||||
headers = curl_slist_append(headers, "DELE file-to-remove");
|
||||
|
||||
/* pass the list of custom commands to the handle */
|
||||
curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers);
|
||||
|
||||
curl_easy_perform(easyhandle); /* transfer ftp data! */
|
||||
|
||||
curl_slist_free_all(headers); /* free the header list */
|
||||
|
||||
If you would instead want this operation (or chain of operations) to happen
|
||||
_after_ the data transfer took place the option to curl_easy_setopt() would
|
||||
instead be called CURLOPT_POSTQUOTE and used the exact same way.
|
||||
|
||||
The custom FTP command will be issued to the server in the same order they
|
||||
are added to the list, and if a command gets an error code returned back from
|
||||
the server, no more commands will be issued and libcurl will bail out with an
|
||||
error code (CURLE_FTP_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE to
|
||||
send commands before a transfer, no transfer will actually take place when a
|
||||
quote command has failed.
|
||||
|
||||
If you set the CURLOPT_HEADER to true, you will tell libcurl to get
|
||||
information about the target file and output "headers" about it. The headers
|
||||
will be in "HTTP-style", looking like they do in HTTP.
|
||||
|
||||
The option to enable headers or to run custom FTP commands may be useful to
|
||||
combine with CURLOPT_NOBODY. If this option is set, no actual file content
|
||||
transfer will be performed.
|
||||
|
||||
|
||||
Cookies Without Chocolate Chips
|
||||
|
||||
In the HTTP sense, a cookie is a name with an associated value. A server
|
||||
sends the name and value to the client, and expects it to get sent back on
|
||||
every subsequent request to the server that matches the particular conditions
|
||||
set. The conditions include that the domain name and path match and that the
|
||||
cookie hasn't become too old.
|
||||
|
||||
In real-world cases, servers send new cookies to replace existing one to
|
||||
update them. Server use cookies to "track" users and to keep "sessions".
|
||||
|
||||
Cookies are sent from server to clients with the header Set-Cookie: and
|
||||
they're sent from clients to servers with the Cookie: header.
|
||||
|
||||
To just send whatever cookie you want to a server, you can use CURLOPT_COOKIE
|
||||
to set a cookie string like this:
|
||||
|
||||
curl_easy_setopt(easyhandle, CURLOPT_COOKIE, "name1=var1; name2=var2;");
|
||||
|
||||
In many cases, that is not enough. You might want to dynamicly save whatever
|
||||
cookies the remote server passes to you, and make sure those cookies are then
|
||||
use accordingly on later requests.
|
||||
|
||||
One way to do this, is to save all headers you receive in a plain file and
|
||||
when you make a request, you tell libcurl to read the previous headers to
|
||||
figure out which cookies to use. Set header file to read cookies from with
|
||||
CURLOPT_COOKIEFILE.
|
||||
|
||||
The CURLOPT_COOKIEFILE option also automaticly enables the cookie parser in
|
||||
libcurl. Until the cookie parser is enabled, libcurl will not parse or
|
||||
understand incoming cookies and they will just be ignored. However, when the
|
||||
parser is enabled the cookies will be understood and the cookies will be kept
|
||||
in memory and used properly in subsequent requests when the same handle is
|
||||
used. Many times this is enough, and you may not have to save the cookies to
|
||||
disk at all. Note that the file you specify to CURLOPT_COOKIEFILE doesn't
|
||||
have to exist to enable the parser, so a common way to just enable the parser
|
||||
and not read able might be to use a file name you know doesn't exist.
|
||||
|
||||
If you rather use existing cookies that you've previously received with your
|
||||
Netscape or Mozilla browsers, you can make libcurl use that cookie file as
|
||||
input. The CURLOPT_COOKIEFILE is used for that too, as libcurl will
|
||||
automaticly find out what kind of file it is and act accordingly.
|
||||
|
||||
The perhaps most advanced cookie operation libcurl offers, is saving the
|
||||
entire internal cookie state back into a Netscape/Mozilla formatted cookie
|
||||
file. We call that the cookie-jar. When you set a file name with
|
||||
CURLOPT_COOKIEJAR, that file name will be created and all received cookies
|
||||
will be stored in it when curl_easy_cleanup() is called. This enabled cookies
|
||||
to get passed on properly between multiple handles without any information
|
||||
getting lost.
|
||||
|
||||
|
||||
Headers Equal Fun
|
||||
|
||||
[ use the header callback for HTTP, FTP etc ]
|
||||
|
||||
|
||||
Post Transfer Information
|
||||
|
||||
[ curl_easy_getinfo ]
|
||||
|
||||
|
||||
Security Considerations
|
||||
|
||||
[ 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:
|
||||
|
||||
[1] = HTTP PUT without knowing the size prior to transfer is indeed possible,
|
||||
but libcurl does not support the chunked transfers on uploading that is
|
||||
necessary for this feature to work. We'd gratefully appreciate patches
|
||||
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.
|
68
docs/libcurl/Makefile.am
Normal file
68
docs/libcurl/Makefile.am
Normal file
@@ -0,0 +1,68 @@
|
||||
#
|
||||
# $Id$
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
|
||||
man_MANS = \
|
||||
curl_easy_cleanup.3 \
|
||||
curl_easy_getinfo.3 \
|
||||
curl_easy_init.3 \
|
||||
curl_easy_perform.3 \
|
||||
curl_easy_setopt.3 \
|
||||
curl_easy_duphandle.3 \
|
||||
curl_formparse.3 \
|
||||
curl_formadd.3 \
|
||||
curl_formfree.3 \
|
||||
curl_getdate.3 \
|
||||
curl_getenv.3 \
|
||||
curl_slist_append.3 \
|
||||
curl_slist_free_all.3 \
|
||||
curl_version.3 \
|
||||
curl_escape.3 \
|
||||
curl_unescape.3 \
|
||||
curl_strequal.3 \
|
||||
curl_strnequal.3 \
|
||||
curl_mprintf.3 \
|
||||
curl_global_init.3 \
|
||||
curl_global_cleanup.3 \
|
||||
libcurl.3
|
||||
|
||||
HTMLPAGES = \
|
||||
curl_easy_cleanup.html \
|
||||
curl_easy_getinfo.html \
|
||||
curl_easy_init.html \
|
||||
curl_easy_perform.html \
|
||||
curl_easy_setopt.html \
|
||||
curl_easy_duphandle.html \
|
||||
curl_formadd.html \
|
||||
curl_formparse.html \
|
||||
curl_formfree.html \
|
||||
curl_getdate.html \
|
||||
curl_getenv.html \
|
||||
curl_slist_append.html \
|
||||
curl_slist_free_all.html \
|
||||
curl_version.html \
|
||||
curl_escape.html \
|
||||
curl_unescape.html \
|
||||
curl_strequal.html \
|
||||
curl_strnequal.html \
|
||||
curl_mprintf.html \
|
||||
curl_global_init.html \
|
||||
curl_global_cleanup.html \
|
||||
libcurl.html \
|
||||
index.html
|
||||
|
||||
EXTRA_DIST = $(man_MANS) $(HTMLPAGES)
|
||||
|
||||
MAN2HTML= gnroff -man $< | man2html >$@
|
||||
|
||||
SUFFIXES = .1 .3 .html
|
||||
|
||||
html: $(HTMLPAGES)
|
||||
|
||||
.3.html:
|
||||
$(MAN2HTML)
|
||||
|
||||
.1.html:
|
||||
$(MAN2HTML)
|
25
docs/libcurl/curl_easy_cleanup.3
Normal file
25
docs/libcurl/curl_easy_cleanup.3
Normal file
@@ -0,0 +1,25 @@
|
||||
.\" You can view this file with:
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_cleanup 3 "4 March 2002" "libcurl 7.7" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_cleanup - End a libcurl easy session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "void curl_easy_cleanup(CURL *" handle ");"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function must be the last function to call for an easy session. It is the
|
||||
opposite of the \fIcurl_easy_init\fP function and must be called with the same
|
||||
\fIhandle\fP as input that the curl_easy_init call returned.
|
||||
|
||||
This will effectively close all connections this handle has used and possibly
|
||||
has kept open until now. Don't call this function if you intend to transfer
|
||||
more files.
|
||||
.SH RETURN VALUE
|
||||
None
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_easy_init "(3), "
|
||||
|
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man [file]
|
||||
.\" $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
|
||||
curl_easy_getinfo - Extract information from a curl session (added in 7.4)
|
||||
.SH SYNOPSIS
|
||||
@@ -30,9 +30,11 @@ Pass a pointer to a long to receive the last received HTTP code.
|
||||
.TP
|
||||
.B CURLINFO_FILETIME
|
||||
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
|
||||
hides it or the server doesn't support the command that tells document time
|
||||
etc) and the time of the document is unknown. (Added in 7.5)
|
||||
document. If you get -1, it can be because of many reasons (unknown, the
|
||||
server hides it or the server doesn't support the command that tells document
|
||||
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
|
||||
.B CURLINFO_TOTAL_TIME
|
||||
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
|
||||
Pass a pointer to a double to receive the specified size of the upload.
|
||||
(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
|
||||
|
||||
.SH RETURN VALUE
|
25
docs/libcurl/curl_easy_init.3
Normal file
25
docs/libcurl/curl_easy_init.3
Normal file
@@ -0,0 +1,25 @@
|
||||
.\" You can view this file with:
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_easy_init 3 "4 March 2002" "libcurl 7.8.1" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_easy_init - Start a libcurl easy session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "CURL *curl_easy_init( );"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function must be the first function to call, and it returns a CURL easy
|
||||
handle that you must use as input to other easy-functions. curl_easy_init
|
||||
intializes curl and this call MUST have a corresponding call to
|
||||
\fIcurl_easy_cleanup\fP when the operation is complete.
|
||||
|
||||
.SH RETURN VALUE
|
||||
If this function returns NULL, something went wrong and you cannot use the
|
||||
other curl functions.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_easy_cleanup "(3), " curl_global_init "(3)
|
||||
.SH BUGS
|
||||
Surely there are some, you tell me!
|
@@ -319,13 +319,59 @@ with \fIcurl_easy_cleanup(3)\fP.
|
||||
.TP
|
||||
.B CURLOPT_SSLCERT
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the file name of your certificate in PEM format.
|
||||
the file name of your certificate. The default format is "PEM" and can be
|
||||
changed with \fICURLOPT_SSLCERTTYPE\fP.
|
||||
.TP
|
||||
.B CURLOPT_SSLCERTTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your certificate. Supported formats are "PEM" and "DER". (Added
|
||||
in 7.9.3)
|
||||
.TP
|
||||
.B CURLOPT_SSLCERTPASSWD
|
||||
Pass a pointer to a zero terminated string as parameter. It will be used as
|
||||
the password required to use the CURLOPT_SSLCERT certificate. If the password
|
||||
is not supplied, you will be prompted for it. \fICURLOPT_PASSWDFUNCTION\fP can
|
||||
be used to set your own prompt function.
|
||||
|
||||
\fBNOTE:\fPThis option is replaced by \fICURLOPT_SSLKEYPASSWD\fP and only
|
||||
cept for backward compatibility. You never needed a pass phrase to load
|
||||
a certificate but you need one to load your private key.
|
||||
.TP
|
||||
.B CURLOPT_SSLKEY
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the file name of your private key. The default format is "PEM" and can be
|
||||
changed with \fICURLOPT_SSLKEYTYPE\fP. (Added in 7.9.3)
|
||||
.TP
|
||||
.B CURLOPT_SSLKEYTYPE
|
||||
Pass a pointer to a zero terminated string as parameter. The string should be
|
||||
the format of your private key. Supported formats are "PEM", "DER" and "ENG".
|
||||
(Added in 7.9.3)
|
||||
|
||||
\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
|
||||
the engine. You have to set the crypto engine with \fICURLOPT_SSL_ENGINE\fP.
|
||||
.TP
|
||||
.B CURLOPT_SSLKEYASSWD
|
||||
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 is not supplied, you will be prompted for
|
||||
it. \fICURLOPT_PASSWDFUNCTION\fP can be used to set your own prompt function.
|
||||
(Added in 7.9.3)
|
||||
.TP
|
||||
.B CURLOPT_SSL_ENGINE
|
||||
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. (Added in 7.9.3)
|
||||
|
||||
\fBNOTE:\fPIf the crypto device cannot be loaded,
|
||||
\fICURLE_SSL_ENGINE_NOTFOUND\fP is returned.
|
||||
.TP
|
||||
.B CURLOPT_SSL_ENGINEDEFAULT
|
||||
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 is returned.
|
||||
.TP
|
||||
.B CURLOPT_CRLF
|
||||
Convert Unix newlines to CRLF newlines on FTP uploads.
|
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_escape 3 "22 March 2001" "libcurl 7.7" "libcurl Manual"
|
||||
.TH curl_escape 3 "6 March 2002" "libcurl 7.9" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_escape - URL encodes the given string
|
||||
.SH SYNOPSIS
|
||||
@@ -13,10 +13,8 @@ curl_escape - URL encodes the given string
|
||||
.SH DESCRIPTION
|
||||
This function will convert the given input string to an URL encoded string and
|
||||
return that as a new allocated string. All input characters that are not a-z,
|
||||
A-Z or 0-9 will be converted to their "URL escaped" version. If a sequence of
|
||||
%NN (where NN is a two-digit hexadecimal number) is found in the string to
|
||||
encode, that 3-letter combination will be copied to the output unmodifed,
|
||||
assuming that it is an already encoded piece of data.
|
||||
A-Z or 0-9 will be converted to their "URL escaped" version (%NN where NN is a
|
||||
two-digit hexadecimal number).
|
||||
|
||||
If the 'length' argument is set to 0, curl_escape() will use strlen() on the
|
||||
input 'url' string to find out the size.
|
@@ -2,7 +2,7 @@
|
||||
.\" nroff -man [file]
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_formadd 3 "29 October 2001" "libcurl 7.9.1" "libcurl Manual"
|
||||
.TH curl_formadd 3 "1 Match 2002" "libcurl 7.9.1" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_formadd - add a section to a multipart/formdata HTTP POST
|
||||
.SH SYNOPSIS
|
||||
@@ -87,8 +87,8 @@ Returns non-zero if an error occurs.
|
||||
.SH EXAMPLE
|
||||
.nf
|
||||
|
||||
HttpPost* post = NULL;
|
||||
HttpPost* last = NULL;
|
||||
struct HttpPost* post = NULL;
|
||||
struct HttpPost* last = NULL;
|
||||
char namebuffer[] = "name buffer";
|
||||
long namelength = strlen(namebuffer);
|
||||
char buffer[] = "test buffer";
|
20
docs/libcurl/curl_multi_add_handle.3
Normal file
20
docs/libcurl/curl_multi_add_handle.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_add_handle 3 "4 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_add_handle - add an easy handle to a multi session
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLMcode curl_multi_add_handle(CURLM *multi_handle, CURL *easy_handle);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
Adds a standard easy handle to the multi stack. This will make this multi
|
||||
handle control the specified easy handle.
|
||||
|
||||
When an easy handle has been added to a multi stack, you can not and you must
|
||||
not use curl_easy_perform() on that handle!
|
||||
.SH RETURN VALUE
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3)"
|
18
docs/libcurl/curl_multi_cleanup.3
Normal file
18
docs/libcurl/curl_multi_cleanup.3
Normal file
@@ -0,0 +1,18 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_cleanup 3 "1 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_cleanup - close down a multi session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "CURLMcode curl_multi_cleanup( CURLM *multi_handle );"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
Cleans up and removes a whole multi stack. It does not free or touch any
|
||||
individual easy handles in any way - they still need to be closed
|
||||
individually, using the usual curl_easy_cleanup() way.
|
||||
.SH RETURN VALUE
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_init "(3)," curl_easy_cleanup "(3)," curl_easy_init "(3)"
|
23
docs/libcurl/curl_multi_fdset.3
Normal file
23
docs/libcurl/curl_multi_fdset.3
Normal file
@@ -0,0 +1,23 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_fdset 3 "1 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_fdset - add an easy handle to a multi session
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||
fd_set *read_fd_set,
|
||||
fd_set *write_fd_set,
|
||||
fd_set *exc_fd_set,
|
||||
int *max_fd);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function extracts file descriptor information from a given multi_handle.
|
||||
libcurl returns its fd_set sets. The application can use these to select() or
|
||||
poll() on. The curl_multi_perform() function should be called as soon as one
|
||||
of them are ready to be read from or written to.
|
||||
.SH RETURN VALUE
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3)"
|
35
docs/libcurl/curl_multi_info_read.3
Normal file
35
docs/libcurl/curl_multi_info_read.3
Normal file
@@ -0,0 +1,35 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_info_read 3 "1 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_info_read - read multi stack informationals
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLMsg *curl_multi_info_read( CURLM *multi_handle,
|
||||
int *msgs_in_queue);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
Ask the multi handle if there's any messages/informationals from the
|
||||
individual transfers. Messages include informationals such as an error code
|
||||
from the transfer or just the fact that a transfer is completed. More details
|
||||
on these should be written down as well.
|
||||
|
||||
Repeated calls to this function will return a new struct each time, until a
|
||||
special "end of msgs" struct is returned as a signal that there is no more to
|
||||
get at this point. The integer pointed to with \fImsgs_in_queue\fP will
|
||||
contain the number of remaining messages after this function was called.
|
||||
|
||||
The data the returned pointer points to will not survive calling
|
||||
curl_multi_cleanup().
|
||||
|
||||
The 'CURLMsg' struct is very simple and only contain very basic informations.
|
||||
If more involved information is wanted, the particular "easy handle" in
|
||||
present in that struct and can thus be used in subsequent regular
|
||||
curl_easy_getinfo() calls (or similar).
|
||||
.SH "RETURN VALUE"
|
||||
A pointer to a filled-in struct, or NULL if it failed or ran out of
|
||||
structs. It also writes the number of messages left in the queue (after this
|
||||
read) in the integer the second argument points to.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3)," curl_multi_perform "(3)"
|
22
docs/libcurl/curl_multi_init.3
Normal file
22
docs/libcurl/curl_multi_init.3
Normal file
@@ -0,0 +1,22 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_init 3 "1 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_init - Start a multi session
|
||||
.SH SYNOPSIS
|
||||
.B #include <curl/curl.h>
|
||||
.sp
|
||||
.BI "CURLM *curl_multi_init( );"
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
This function returns a CURLM handle to be used as input to all the other
|
||||
multi-functions, sometimes refered to as a multi handle on some places in the
|
||||
documentation. This init call MUST have a corresponding call to
|
||||
\fIcurl_multi_cleanup\fP when the operation is complete.
|
||||
.SH RETURN VALUE
|
||||
If this function returns NULL, something went wrong and you cannot use the
|
||||
other curl functions.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_global_init "(3)," curl_easy_init "(3)"
|
||||
.SH BUGS
|
||||
Surely there are some, you tell me!
|
30
docs/libcurl/curl_multi_perform.3
Normal file
30
docs/libcurl/curl_multi_perform.3
Normal file
@@ -0,0 +1,30 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_perform 3 "1 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_perform - add an easy handle to a multi session
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
When the app thinks there's data available for the multi_handle, it should
|
||||
call this function to read/write whatever there is to read or write right
|
||||
now. curl_multi_perform() returns as soon as the reads/writes are done. This
|
||||
function does not require that there actually is any data available for
|
||||
reading or that data can be written, it can be called just in case. It will
|
||||
write the number of handles that still transfer data in the second argument's
|
||||
integer-pointer.
|
||||
.SH "RETURN VALUE"
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
|
||||
NOTE that this only returns errors etc regarding the whole multi stack. There
|
||||
might still have occurred problems on invidual transfers even when this
|
||||
function returns OK.
|
||||
.SH "TYPICAL USAGE"
|
||||
Most application will use \fIcurl_multi_fdset\fP to get the multi_handle's
|
||||
file descriptors, then it'll wait for action on them using select() and as
|
||||
soon as one or more of them are ready, \fIcurl_multi_perform\fP gets called.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3)"
|
20
docs/libcurl/curl_multi_remove_handle.3
Normal file
20
docs/libcurl/curl_multi_remove_handle.3
Normal file
@@ -0,0 +1,20 @@
|
||||
.\" $Id$
|
||||
.\"
|
||||
.TH curl_multi_remove_handle 3 "6 March 2002" "libcurl 7.9.5" "libcurl Manual"
|
||||
.SH NAME
|
||||
curl_multi_remove_handle - add an easy handle to a multi session
|
||||
.SH SYNOPSIS
|
||||
#include <curl/curl.h>
|
||||
|
||||
CURLMcode curl_multi_remove_handle(CURLM *multi_handle, CURL *easy_handle);
|
||||
.ad
|
||||
.SH DESCRIPTION
|
||||
Removes a given easy_handle from the multi_handle. This will make the
|
||||
specified easy handle be removed from this multi handle's control.
|
||||
|
||||
When the easy handle has been removed from a multi stack, it is again
|
||||
perfectly legal to invoke \fIcurl_easy_perform()\fP on this easy handle.
|
||||
.SH RETURN VALUE
|
||||
CURLMcode type, general libcurl multi interface error code.
|
||||
.SH "SEE ALSO"
|
||||
.BR curl_multi_cleanup "(3)," curl_multi_init "(3)"
|
@@ -6,8 +6,10 @@
|
||||
.SH NAME
|
||||
libcurl \- client-side URL transfers
|
||||
.SH DESCRIPTION
|
||||
This is an overview on how to use libcurl in your c/c++ programs. There are
|
||||
specific man pages for each function mentioned in here.
|
||||
This is an overview on how to use libcurl in your C programs. There are
|
||||
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
|
||||
Tcl programs as well, look elsewhere for documentation on this!
|
||||
@@ -56,9 +58,6 @@ get information about a performed transfer
|
||||
.B curl_formadd()
|
||||
helps building a HTTP form POST
|
||||
.TP
|
||||
.B curl_formparse()
|
||||
helps building a HTTP form POST (deprecated since 7.9 use curl_formadd()!)
|
||||
.TP
|
||||
.B curl_formfree()
|
||||
free a list built with curl_formparse()/curl_formadd()
|
||||
.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
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@@ -30,11 +30,11 @@
|
||||
# include <time.h>
|
||||
#else
|
||||
# include <sys/types.h>
|
||||
# if TIME_WITH_SYS_TIME
|
||||
# ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
# else
|
||||
# if HAVE_SYS_TIME_H
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
@@ -75,10 +75,10 @@ struct HttpPost {
|
||||
};
|
||||
|
||||
typedef int (*curl_progress_callback)(void *clientp,
|
||||
size_t dltotal,
|
||||
size_t dlnow,
|
||||
size_t ultotal,
|
||||
size_t ulnow);
|
||||
double dltotal,
|
||||
double dlnow,
|
||||
double ultotal,
|
||||
double ulnow);
|
||||
|
||||
typedef size_t (*curl_write_callback)(char *buffer,
|
||||
size_t size,
|
||||
@@ -272,7 +272,7 @@ typedef enum {
|
||||
/* Set cookie in request: */
|
||||
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),
|
||||
|
||||
/* This points to a linked list of post entries, struct HttpPost */
|
||||
@@ -488,6 +488,15 @@ typedef enum {
|
||||
*/
|
||||
CINIT(SSLENGINE_DEFAULT, LONG, 90),
|
||||
|
||||
/* Non-zero value means to use the global dns cache */
|
||||
CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91),
|
||||
|
||||
/* DNS cache timeout */
|
||||
CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
|
||||
|
||||
/* send linked-list of pre-transfer QUOTE commands (Wesley Laxton)*/
|
||||
CINIT(PREQUOTE, OBJECTPOINT, 93),
|
||||
|
||||
CURLOPT_LASTENTRY /* the last unusued */
|
||||
} CURLoption;
|
||||
|
||||
@@ -607,8 +616,8 @@ CURLcode curl_global_init(long flags);
|
||||
void curl_global_cleanup(void);
|
||||
|
||||
/* This is the version number */
|
||||
#define LIBCURL_VERSION "7.9.2"
|
||||
#define LIBCURL_VERSION_NUM 0x070902
|
||||
#define LIBCURL_VERSION "7.9.5"
|
||||
#define LIBCURL_VERSION_NUM 0x070905
|
||||
|
||||
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
|
||||
struct curl_slist {
|
||||
@@ -660,7 +669,11 @@ typedef enum {
|
||||
|
||||
CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
|
||||
|
||||
CURLINFO_LASTONE = 18
|
||||
CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
|
||||
|
||||
/* Fill in new entries here! */
|
||||
|
||||
CURLINFO_LASTONE = 19
|
||||
} CURLINFO;
|
||||
|
||||
/* unfortunately, the easy.h include file needs the options and info stuff
|
||||
|
@@ -2,16 +2,20 @@
|
||||
# $Id$
|
||||
#
|
||||
|
||||
AUTOMAKE_OPTIONS = foreign no-dependencies
|
||||
AUTOMAKE_OPTIONS = foreign nostdinc
|
||||
|
||||
EXTRA_DIST = getdate.y \
|
||||
Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \
|
||||
libcurl.def dllinit.c curllib.dsp curllib.dsw
|
||||
libcurl.def dllinit.c curllib.dsp curllib.dsw \
|
||||
config-vms.h config-win32.h config-riscos.h config-mac.h \
|
||||
config.h.in
|
||||
|
||||
lib_LTLIBRARIES = libcurl.la
|
||||
|
||||
INCLUDES = -I$(top_srcdir)/include
|
||||
|
||||
# we use srcdir/include for the static global include files
|
||||
# we use builddir/lib for the generated lib/config.h file to get found
|
||||
# we use srcdir/lib for the lib-private header files
|
||||
INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/lib -I$(top_srcdir)/lib
|
||||
|
||||
libcurl_la_LDFLAGS = -no-undefined -version-info 2:2:0
|
||||
# This flag accepts an argument of the form current[:revision[:age]]. So,
|
||||
@@ -56,7 +60,9 @@ escape.c mprintf.c telnet.c \
|
||||
escape.h getpass.c netrc.c telnet.h \
|
||||
getinfo.c getinfo.h transfer.c strequal.c strequal.h easy.c \
|
||||
security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h \
|
||||
http_chunks.c http_chunks.h strtok.c strtok.h connect.c connect.h
|
||||
http_chunks.c http_chunks.h strtok.c strtok.h connect.c connect.h \
|
||||
llist.c llist.h hash.c hash.h multi.c multi.h
|
||||
|
||||
|
||||
noinst_HEADERS = setup.h transfer.h
|
||||
|
||||
|
@@ -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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
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 \
|
||||
strtok.o connect.o
|
||||
strtok.o connect.o hash.o llist.o
|
||||
|
||||
LIBRARIES = $(libcurl_a_LIBRARIES)
|
||||
SOURCES = $(libcurl_a_SOURCES)
|
||||
|
@@ -23,13 +23,18 @@
|
||||
# CHANGE LOG
|
||||
# ------------------------------------------------------------
|
||||
# 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_DEBUG = libcurld
|
||||
!IFNDEF OPENSSL_PATH
|
||||
OPENSSL_PATH = ../../openssl-0.9.6
|
||||
!ENDIF
|
||||
|
||||
#############################################################
|
||||
## Nothing more to do below this line!
|
||||
@@ -46,6 +51,8 @@ LFLAGSSSL = /LIBPATH:$(OPENSSL_PATH)/out32dll
|
||||
LINKLIBS = ws2_32.lib
|
||||
SSLLIBS = libeay32.lib ssleay32.lib RSAglue.lib
|
||||
CFGSET = FALSE
|
||||
LFLAGSSSL=
|
||||
SSLLIBS =
|
||||
|
||||
######################
|
||||
# release
|
||||
@@ -193,8 +200,9 @@ X_OBJS= \
|
||||
$(DIROBJ)\easy.obj \
|
||||
$(DIROBJ)\strequal.obj \
|
||||
$(DIROBJ)\strtok.obj \
|
||||
$(DIROBJ)\connect.obj
|
||||
|
||||
$(DIROBJ)\connect.obj \
|
||||
$(DIROBJ)\hash.obj \
|
||||
$(DIROBJ)\llist.obj
|
||||
|
||||
all : $(TARGET)
|
||||
|
||||
|
@@ -221,22 +221,22 @@
|
||||
#define HAVE_NETINET_IN_H 1
|
||||
|
||||
/* 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. */
|
||||
#undef HAVE_OPENSSL_ERR_H
|
||||
#define HAVE_OPENSSL_ERR_H 1
|
||||
|
||||
/* 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. */
|
||||
#undef HAVE_OPENSSL_RSA_H
|
||||
#define HAVE_OPENSSL_RSA_H 1
|
||||
|
||||
/* 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. */
|
||||
#undef HAVE_OPENSSL_X509_H
|
||||
#define HAVE_OPENSSL_X509_H 1
|
||||
|
||||
/* Define if you have the <pem.h> header file. */
|
||||
#undef HAVE_PEM_H
|
||||
@@ -296,7 +296,7 @@
|
||||
#undef HAVE_X509_H
|
||||
|
||||
/* Define if you have the crypto library (-lcrypto). */
|
||||
#undef HAVE_LIBCRYPTO
|
||||
#define HAVE_LIBCRYPTO 1
|
||||
|
||||
/* Define if you have the dl library (-ldl). */
|
||||
#undef HAVE_LIBDL
|
||||
@@ -314,7 +314,7 @@
|
||||
#define HAVE_LIBSOCKET 1
|
||||
|
||||
/* Define if you have the ssl library (-lssl). */
|
||||
#undef HAVE_LIBSSL
|
||||
#define HAVE_LIBSSL 1
|
||||
|
||||
/* Define if you have the ucb library (-lucb). */
|
||||
#undef HAVE_LIBUCB
|
||||
@@ -346,7 +346,7 @@
|
||||
#undef HAVE_GETPASS
|
||||
|
||||
/* Define if you have a working OpenSSL installation */
|
||||
#undef OPENSSL_ENABLED
|
||||
#define OPENSSL_ENABLED 1
|
||||
|
||||
/* Define if you have the `dlopen' function. */
|
||||
#undef HAVE_DLOPEN
|
||||
@@ -365,3 +365,4 @@
|
||||
|
||||
#define HAVE_MEMORY_H 1
|
||||
|
||||
#define HAVE_FIONBIO 1
|
@@ -48,6 +48,10 @@
|
||||
#include <stdlib.h> /* required for free() prototype, without it, this crashes
|
||||
on macos 68K */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
|
||||
#endif
|
||||
#include <stdio.h>
|
||||
@@ -210,11 +214,11 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
in_addr_t in;
|
||||
|
||||
if(Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
|
||||
h = Curl_getaddrinfo(data, myhost, 0, &hostdataptr);
|
||||
h = Curl_resolv(data, myhost, 0, &hostdataptr);
|
||||
}
|
||||
else {
|
||||
if(strlen(data->set.device)>1) {
|
||||
h = Curl_getaddrinfo(data, data->set.device, 0, &hostdataptr);
|
||||
h = Curl_resolv(data, data->set.device, 0, &hostdataptr);
|
||||
}
|
||||
if(h) {
|
||||
/* we know data->set.device is shorter than the myhost array */
|
||||
@@ -229,8 +233,6 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
hostent_buf,
|
||||
sizeof(hostent_buf));
|
||||
*/
|
||||
if(hostdataptr)
|
||||
free(hostdataptr); /* allocated by Curl_getaddrinfo() */
|
||||
return CURLE_HTTP_PORT_FAILED;
|
||||
}
|
||||
|
||||
@@ -304,9 +306,6 @@ static CURLcode bindlocal(struct connectdata *conn,
|
||||
return CURLE_HTTP_PORT_FAILED;
|
||||
}
|
||||
|
||||
if(hostdataptr)
|
||||
free(hostdataptr); /* allocated by Curl_getaddrinfo() */
|
||||
|
||||
return CURLE_OK;
|
||||
|
||||
} /* end of device selection support */
|
||||
@@ -365,8 +364,13 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
#endif
|
||||
|
||||
/* get the most strict timeout of the ones converted to milliseconds */
|
||||
if(data->set.timeout &&
|
||||
(data->set.timeout>data->set.connecttimeout))
|
||||
if(data->set.timeout && data->set.connecttimeout) {
|
||||
if (data->set.timeout < data->set.connecttimeout)
|
||||
timeout_ms = data->set.timeout*1000;
|
||||
else
|
||||
timeout_ms = data->set.connecttimeout*1000;
|
||||
}
|
||||
else if(data->set.timeout)
|
||||
timeout_ms = data->set.timeout*1000;
|
||||
else
|
||||
timeout_ms = data->set.connecttimeout*1000;
|
||||
@@ -374,9 +378,11 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
/* subtract the passed time */
|
||||
timeout_ms -= (long)has_passed;
|
||||
|
||||
if(timeout_ms < 0)
|
||||
if(timeout_ms < 0) {
|
||||
/* a precaution, no need to continue if time already is up */
|
||||
failf(data, "Connection time-out");
|
||||
return CURLE_OPERATION_TIMEOUTED;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
@@ -453,8 +459,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
|
||||
/* now disable the non-blocking mode again */
|
||||
Curl_nonblock(sockfd, FALSE);
|
||||
/* leave the socket in non-blocking mode */
|
||||
|
||||
if(addr)
|
||||
*addr = ai; /* the address we ended up connected to */
|
||||
@@ -560,8 +565,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
|
||||
return CURLE_COULDNT_CONNECT;
|
||||
}
|
||||
|
||||
/* now disable the non-blocking mode again */
|
||||
Curl_nonblock(sockfd, FALSE);
|
||||
/* leave the socket in non-blocking mode */
|
||||
|
||||
if(addr)
|
||||
/* this is the address we've connected to */
|
||||
|
62
lib/cookie.c
62
lib/cookie.c
@@ -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
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@@ -127,22 +127,37 @@ Curl_cookie_add(struct CookieInfo *c,
|
||||
|
||||
if(httpheader) {
|
||||
/* This line was read off a HTTP-header */
|
||||
|
||||
char *sep;
|
||||
semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
|
||||
ptr = lineptr;
|
||||
do {
|
||||
/* we have a <what>=<this> pair or a 'secure' word here */
|
||||
if(strchr(ptr, '=')) {
|
||||
sep = strchr(ptr, '=');
|
||||
if(sep && (!semiptr || (semiptr>sep)) ) {
|
||||
/*
|
||||
* There is a = sign and if there was a semicolon too, which make sure
|
||||
* that the semicolon comes _after_ the equal sign.
|
||||
*/
|
||||
|
||||
name[0]=what[0]=0; /* init the buffers */
|
||||
if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^=]=%"
|
||||
if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;=]=%"
|
||||
MAX_COOKIE_LINE_TXT "[^;\r\n]",
|
||||
name, what)) {
|
||||
/* this is a legal <what>=<this> pair */
|
||||
/* this is a <name>=<what> pair */
|
||||
|
||||
/* Strip off trailing whitespace from the 'what' */
|
||||
int len=strlen(what);
|
||||
while(len && isspace((int)what[len-1])) {
|
||||
what[len-1]=0;
|
||||
len--;
|
||||
}
|
||||
|
||||
if(strequal("path", name)) {
|
||||
co->path=strdup(what);
|
||||
}
|
||||
else if(strequal("domain", name)) {
|
||||
co->domain=strdup(what);
|
||||
co->field1= (what[0]=='.')?2:1;
|
||||
}
|
||||
else if(strequal("version", name)) {
|
||||
co->version=strdup(what);
|
||||
@@ -159,7 +174,7 @@ Curl_cookie_add(struct CookieInfo *c,
|
||||
*/
|
||||
co->maxage = strdup(what);
|
||||
co->expires =
|
||||
atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]);
|
||||
atoi((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0]) + now;
|
||||
}
|
||||
else if(strequal("expires", name)) {
|
||||
co->expirestr=strdup(what);
|
||||
@@ -187,15 +202,37 @@ Curl_cookie_add(struct CookieInfo *c,
|
||||
|
||||
}
|
||||
}
|
||||
if(!semiptr)
|
||||
continue; /* we already know there are no more cookies */
|
||||
if(!semiptr || !*semiptr) {
|
||||
/* we already know there are no more cookies */
|
||||
semiptr = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
ptr=semiptr+1;
|
||||
while(ptr && *ptr && isspace((int)*ptr))
|
||||
ptr++;
|
||||
semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
|
||||
|
||||
if(!semiptr && *ptr)
|
||||
/* There are no more semicolons, but there's a final name=value pair
|
||||
coming up */
|
||||
semiptr=strchr(ptr, '\0');
|
||||
} while(semiptr);
|
||||
|
||||
if(NULL == co->name) {
|
||||
/* we didn't get a cookie name, this is an illegal line, bail out */
|
||||
if(co->domain)
|
||||
free(co->domain);
|
||||
if(co->path)
|
||||
free(co->path);
|
||||
if(co->name)
|
||||
free(co->name);
|
||||
if(co->value)
|
||||
free(co->value);
|
||||
free(co);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if(NULL == co->domain)
|
||||
/* no domain given in the header line, set the default now */
|
||||
co->domain=domain?strdup(domain):NULL;
|
||||
@@ -377,8 +414,15 @@ Curl_cookie_add(struct CookieInfo *c,
|
||||
|
||||
free(co); /* free the newly alloced memory */
|
||||
co = clist; /* point to the previous struct instead */
|
||||
}
|
||||
|
||||
/* We have replaced a cookie, now skip the rest of the list but
|
||||
make sure the 'lastc' pointer is properly set */
|
||||
do {
|
||||
lastc = clist;
|
||||
clist = clist->next;
|
||||
} while(clist);
|
||||
break;
|
||||
}
|
||||
}
|
||||
lastc = clist;
|
||||
clist = clist->next;
|
||||
|
@@ -38,7 +38,7 @@ struct Cookie {
|
||||
char *value; /* name = <this> */
|
||||
char *path; /* path = <this> */
|
||||
char *domain; /* domain = <this> */
|
||||
time_t expires; /* expires = <this> */
|
||||
long expires; /* expires = <this> */
|
||||
char *expirestr; /* the plain text version */
|
||||
|
||||
char field1; /* read from a cookie file, 1 => FALSE, 2=> TRUE */
|
||||
|
@@ -151,6 +151,10 @@ SOURCE=.\getpass.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hash.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\hostip.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@@ -179,6 +183,10 @@ SOURCE=.\libcurl.def
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\llist.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\memdebug.c
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@@ -81,6 +81,10 @@ DllMain (
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
#ifdef VMS
|
||||
int VOID_VAR_DLLINIT;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
|
15
lib/easy.c
15
lib/easy.c
@@ -76,6 +76,7 @@
|
||||
#include "ssluse.h"
|
||||
#include "url.h"
|
||||
#include "getinfo.h"
|
||||
#include "hostip.h"
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
@@ -162,6 +163,8 @@ void curl_global_cleanup(void)
|
||||
if (!initialized)
|
||||
return;
|
||||
|
||||
Curl_global_host_cache_dtor();
|
||||
|
||||
if (init_flags & CURL_GLOBAL_SSL)
|
||||
Curl_SSL_cleanup();
|
||||
|
||||
@@ -230,12 +233,24 @@ CURLcode curl_easy_perform(CURL *curl)
|
||||
{
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
|
||||
if (!data->hostcache) {
|
||||
if (Curl_global_host_cache_use(data)) {
|
||||
data->hostcache = Curl_global_host_cache_get();
|
||||
}
|
||||
else {
|
||||
data->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo);
|
||||
}
|
||||
}
|
||||
|
||||
return Curl_perform(data);
|
||||
}
|
||||
|
||||
void curl_easy_cleanup(CURL *curl)
|
||||
{
|
||||
struct SessionHandle *data = (struct SessionHandle *)curl;
|
||||
if (!Curl_global_host_cache_use(data)) {
|
||||
curl_hash_destroy(data->hostcache);
|
||||
}
|
||||
Curl_close(data);
|
||||
}
|
||||
|
||||
|
@@ -235,7 +235,6 @@ int FormParse(char *input,
|
||||
|
||||
if(2 != sscanf(type, "%127[^/]/%127[^,\n]",
|
||||
major, minor)) {
|
||||
fprintf(stderr, "Illegally formatted content-type field!\n");
|
||||
free(contents);
|
||||
return 2; /* illegal content-type syntax! */
|
||||
}
|
||||
@@ -371,7 +370,6 @@ int FormParse(char *input,
|
||||
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Illegally formatted input field!\n");
|
||||
free(contents);
|
||||
return 1;
|
||||
}
|
||||
@@ -841,7 +839,6 @@ FORMcode FormAdd(struct HttpPost **httppost,
|
||||
break;
|
||||
}
|
||||
default:
|
||||
fprintf (stderr, "got unknown CURLFORM_OPTION: %d\n", option);
|
||||
return_value = FORMADD_UNKNOWN_OPTION;
|
||||
}
|
||||
}
|
||||
@@ -1068,8 +1065,11 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
|
||||
|
||||
do {
|
||||
|
||||
if(size)
|
||||
size += AddFormDataf(&form, "\r\n");
|
||||
|
||||
/* boundary */
|
||||
size += AddFormDataf(&form, "\r\n--%s\r\n", boundary);
|
||||
size += AddFormDataf(&form, "--%s\r\n", boundary);
|
||||
|
||||
size += AddFormData(&form,
|
||||
"Content-Disposition: form-data; name=\"", 0);
|
||||
@@ -1155,10 +1155,13 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
|
||||
}
|
||||
if(fileread != stdin)
|
||||
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 */
|
||||
size += AddFormData(&form, post->contents, post->contentslength);
|
||||
}
|
||||
|
108
lib/ftp.c
108
lib/ftp.c
@@ -55,6 +55,7 @@
|
||||
#include <netdb.h>
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#endif
|
||||
#endif
|
||||
@@ -84,6 +85,10 @@
|
||||
#include "ssluse.h"
|
||||
#include "connect.h"
|
||||
|
||||
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
|
||||
#include "inet_ntoa_r.h"
|
||||
#endif
|
||||
|
||||
#define _MPRINTF_REPLACE /* use our functions only */
|
||||
#include <curl/mprintf.h>
|
||||
|
||||
@@ -192,9 +197,12 @@ int Curl_GetFTPResponse(char *buf,
|
||||
char *line_start;
|
||||
int code=0; /* default "error code" to return */
|
||||
|
||||
#define SELECT_OK 0
|
||||
#define SELECT_ERROR 1
|
||||
#define SELECT_TIMEOUT 2
|
||||
#define SELECT_OK 0
|
||||
#define SELECT_ERROR 1 /* select() problems */
|
||||
#define SELECT_TIMEOUT 2 /* took too long */
|
||||
#define SELECT_MEMORY 3 /* no available memory */
|
||||
#define SELECT_CALLBACK 4 /* aborted by callback */
|
||||
|
||||
int error = SELECT_OK;
|
||||
|
||||
struct FTP *ftp = conn->proto.ftp;
|
||||
@@ -260,9 +268,16 @@ int Curl_GetFTPResponse(char *buf,
|
||||
ftp->cache = NULL; /* clear the pointer */
|
||||
ftp->cache_size = 0; /* zero the size just in case */
|
||||
}
|
||||
else if(CURLE_OK != Curl_read(conn, sockfd, ptr,
|
||||
BUFSIZE-nread, &gotbytes))
|
||||
keepon = FALSE;
|
||||
else {
|
||||
int res = Curl_read(conn, sockfd, ptr,
|
||||
BUFSIZE-nread, &gotbytes);
|
||||
if(res < 0)
|
||||
/* EWOULDBLOCK */
|
||||
continue; /* go looping again */
|
||||
|
||||
if(CURLE_OK != res)
|
||||
keepon = FALSE;
|
||||
}
|
||||
|
||||
if(!keepon)
|
||||
;
|
||||
@@ -283,6 +298,7 @@ int Curl_GetFTPResponse(char *buf,
|
||||
if(*ptr=='\n') {
|
||||
/* a newline is CRLF in ftp-talk, so the CR is ignored as
|
||||
the line isn't really terminated until the LF comes */
|
||||
CURLcode result;
|
||||
|
||||
/* output debug output if that is requested */
|
||||
if(data->set.verbose) {
|
||||
@@ -291,6 +307,16 @@ int Curl_GetFTPResponse(char *buf,
|
||||
/* no need to output LF here, it is part of the data */
|
||||
}
|
||||
|
||||
/*
|
||||
* We pass all response-lines to the callback function registered
|
||||
* for "headers". The response lines can be seen as a kind of
|
||||
* headers.
|
||||
*/
|
||||
result = Curl_client_write(data, CLIENTWRITE_HEADER,
|
||||
line_start, perline);
|
||||
if(result)
|
||||
return -SELECT_CALLBACK;
|
||||
|
||||
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
|
||||
isdigit((int)line[2]) && (' ' == line[3]))
|
||||
|
||||
@@ -324,7 +350,7 @@ int Curl_GetFTPResponse(char *buf,
|
||||
if(ftp->cache)
|
||||
memcpy(ftp->cache, line_start, ftp->cache_size);
|
||||
else
|
||||
return CURLE_OUT_OF_MEMORY; /**BANG**/
|
||||
return -SELECT_MEMORY; /**BANG**/
|
||||
}
|
||||
} /* there was data */
|
||||
} /* if(no error) */
|
||||
@@ -333,7 +359,7 @@ int Curl_GetFTPResponse(char *buf,
|
||||
if(!error)
|
||||
code = atoi(buf);
|
||||
|
||||
#if KRB4
|
||||
#ifdef KRB4
|
||||
/* handle the security-oriented responses 6xx ***/
|
||||
/* FIXME: some errorchecking perhaps... ***/
|
||||
switch(code) {
|
||||
@@ -847,13 +873,17 @@ ftp_pasv_verbose(struct connectdata *conn,
|
||||
#ifdef HAVE_INET_NTOA_R
|
||||
char ntoa_buf[64];
|
||||
#endif
|
||||
char hostent_buf[9000];
|
||||
/* The array size trick below is to make this a large chunk of memory
|
||||
suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
|
||||
suggested by Philip Gladstone. */
|
||||
long bigbuf[9000 / sizeof(long)];
|
||||
|
||||
#if defined(HAVE_INET_ADDR)
|
||||
in_addr_t address;
|
||||
# if defined(HAVE_GETHOSTBYADDR_R)
|
||||
int h_errnop;
|
||||
# endif
|
||||
char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
|
||||
|
||||
address = inet_addr(newhost);
|
||||
# ifdef HAVE_GETHOSTBYADDR_R
|
||||
@@ -882,7 +912,7 @@ ftp_pasv_verbose(struct connectdata *conn,
|
||||
# ifdef HAVE_GETHOSTBYADDR_R_7
|
||||
/* Solaris and IRIX */
|
||||
answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
|
||||
(struct hostent *)hostent_buf,
|
||||
(struct hostent *)bigbuf,
|
||||
hostent_buf + sizeof(*answer),
|
||||
sizeof(hostent_buf) - sizeof(*answer),
|
||||
&h_errnop);
|
||||
@@ -1174,19 +1204,19 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
||||
|
||||
if(data->set.ftpport) {
|
||||
if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
|
||||
h = Curl_getaddrinfo(data, myhost, 0, &hostdataptr);
|
||||
h = Curl_resolv(data, myhost, 0, &hostdataptr);
|
||||
}
|
||||
else {
|
||||
if(strlen(data->set.ftpport)>1)
|
||||
h = Curl_getaddrinfo(data, data->set.ftpport, 0, &hostdataptr);
|
||||
int len = strlen(data->set.ftpport);
|
||||
if(len>1)
|
||||
h = Curl_resolv(data, data->set.ftpport, 0, &hostdataptr);
|
||||
if(h)
|
||||
strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
|
||||
}
|
||||
}
|
||||
if(! *myhost) {
|
||||
h=Curl_getaddrinfo(data,
|
||||
getmyhost(myhost, sizeof(myhost)),
|
||||
0, &hostdataptr);
|
||||
char *tmp_host = getmyhost(myhost, sizeof(myhost));
|
||||
h=Curl_resolv(data, tmp_host, 0, &hostdataptr);
|
||||
}
|
||||
infof(data, "We connect from %s\n", myhost);
|
||||
|
||||
@@ -1237,9 +1267,6 @@ CURLcode ftp_use_port(struct connectdata *conn)
|
||||
free(hostdataptr);
|
||||
return CURLE_FTP_PORT_FAILED;
|
||||
}
|
||||
if(hostdataptr)
|
||||
/* free the memory used for name lookup */
|
||||
Curl_freeaddrinfo(hostdataptr);
|
||||
}
|
||||
else {
|
||||
failf(data, "could't find my own IP address (%s)", myhost);
|
||||
@@ -1431,7 +1458,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
|
||||
}
|
||||
else {
|
||||
/* normal, direct, ftp connection */
|
||||
addr = Curl_getaddrinfo(data, newhostp, newport, &hostdataptr);
|
||||
addr = Curl_resolv(data, newhostp, newport, &hostdataptr);
|
||||
if(!addr) {
|
||||
failf(data, "Can't resolve new host %s", newhost);
|
||||
return CURLE_FTP_CANT_GET_HOST;
|
||||
@@ -1450,9 +1477,6 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
|
||||
/* this just dumps information about this second connection */
|
||||
ftp_pasv_verbose(conn, conninfo, newhost, connectport);
|
||||
|
||||
if(hostdataptr)
|
||||
Curl_freeaddrinfo(hostdataptr);
|
||||
|
||||
if(CURLE_OK != result)
|
||||
return result;
|
||||
|
||||
@@ -1552,7 +1576,7 @@ CURLcode ftp_perform(struct connectdata *conn)
|
||||
struct tm buffer;
|
||||
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
|
||||
#else
|
||||
tm = localtime(&data->info.filetime);
|
||||
tm = localtime((unsigned long *)&data->info.filetime);
|
||||
#endif
|
||||
/* 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",
|
||||
@@ -1594,6 +1618,12 @@ CURLcode ftp_perform(struct connectdata *conn)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
|
||||
if(data->set.prequote) {
|
||||
if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
if(conn->resume_from) {
|
||||
/* we're about to continue the uploading of a file */
|
||||
/* 1. get already existing file's size. We use the SIZE
|
||||
@@ -1779,6 +1809,12 @@ CURLcode ftp_perform(struct connectdata *conn)
|
||||
if(result)
|
||||
return result;
|
||||
|
||||
/* Send any PREQUOTE strings after transfer type is set? (Wesley Laxton)*/
|
||||
if(data->set.prequote) {
|
||||
if ((result = ftp_sendquote(conn, data->set.prequote)) != CURLE_OK)
|
||||
return result;
|
||||
}
|
||||
|
||||
/* Attempt to get the size, it'll be useful in some cases: for resumed
|
||||
downloads and when talking to servers that don't give away the size
|
||||
in the RETR response line. */
|
||||
@@ -2035,9 +2071,11 @@ CURLcode Curl_ftp(struct connectdata *conn)
|
||||
CURLcode Curl_ftpsendf(struct connectdata *conn,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
size_t bytes_written;
|
||||
ssize_t bytes_written;
|
||||
char s[256];
|
||||
size_t write_len;
|
||||
ssize_t write_len;
|
||||
char *sptr=s;
|
||||
CURLcode res = CURLE_OK;
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
@@ -2051,9 +2089,23 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
|
||||
|
||||
bytes_written=0;
|
||||
write_len = strlen(s);
|
||||
Curl_write(conn, conn->firstsocket, s, write_len, &bytes_written);
|
||||
|
||||
return (bytes_written==write_len)?CURLE_OK:CURLE_WRITE_ERROR;
|
||||
do {
|
||||
res = Curl_write(conn, conn->firstsocket, sptr, write_len,
|
||||
&bytes_written);
|
||||
|
||||
if(CURLE_OK != res)
|
||||
break;
|
||||
|
||||
if(bytes_written != write_len) {
|
||||
write_len -= bytes_written;
|
||||
sptr += bytes_written;
|
||||
}
|
||||
else
|
||||
break;
|
||||
} while(1);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
531
lib/getdate.c
531
lib/getdate.c
@@ -34,8 +34,6 @@
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# endif
|
||||
@@ -43,6 +41,10 @@
|
||||
# ifdef HAVE_TIME_H
|
||||
# include <time.h>
|
||||
# endif
|
||||
|
||||
#ifndef YYDEBUG
|
||||
/* to satisfy gcc -Wundef, we set this to 0 */
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
|
||||
/* Since the code of getdate.y is not included in the Emacs executable
|
||||
@@ -192,38 +194,40 @@ typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} 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;
|
||||
|
||||
/*
|
||||
** Global variables. We could get rid of most of these by using a good
|
||||
** 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.
|
||||
/* enable use of extra argument to yyparse and yylex which can be used to pass
|
||||
** in a user defined value (CONTEXT struct in our case)
|
||||
*/
|
||||
static const char *yyInput;
|
||||
static int yyDayOrdinal;
|
||||
static int yyDayNumber;
|
||||
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;
|
||||
#define YYPARSE_PARAM cookie
|
||||
#define YYLEX_PARAM cookie
|
||||
#define context ((CONTEXT *) cookie)
|
||||
|
||||
|
||||
#line 206 "getdate.y"
|
||||
#line 215 "getdate.y"
|
||||
typedef union {
|
||||
int Number;
|
||||
enum _MERIDIAN Meridian;
|
||||
@@ -306,11 +310,11 @@ static const short yyrhs[] = { -1,
|
||||
|
||||
#if YYDEBUG != 0
|
||||
static const short yyrline[] = { 0,
|
||||
222, 223, 226, 229, 232, 235, 238, 241, 244, 250,
|
||||
256, 265, 271, 283, 286, 289, 295, 299, 303, 309,
|
||||
313, 331, 337, 343, 347, 352, 356, 363, 371, 374,
|
||||
377, 380, 383, 386, 389, 392, 395, 398, 401, 404,
|
||||
407, 410, 413, 416, 419, 422, 425, 430, 463, 467
|
||||
231, 232, 235, 238, 241, 244, 247, 250, 253, 259,
|
||||
265, 274, 280, 292, 295, 298, 304, 308, 312, 318,
|
||||
322, 340, 346, 352, 356, 361, 365, 372, 380, 383,
|
||||
386, 389, 392, 395, 398, 401, 404, 407, 410, 413,
|
||||
416, 419, 422, 425, 428, 431, 434, 439, 473, 477
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -390,6 +394,8 @@ static const short yycheck[] = { 0,
|
||||
11, 15, 13, 14, 16, 19, 17, 16, 21, 0,
|
||||
56
|
||||
};
|
||||
#define YYPURE 1
|
||||
|
||||
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
|
||||
#line 3 "/usr/local/share/bison.simple"
|
||||
/* This file comes from bison-1.28. */
|
||||
@@ -934,135 +940,135 @@ yyreduce:
|
||||
switch (yyn) {
|
||||
|
||||
case 3:
|
||||
#line 226 "getdate.y"
|
||||
#line 235 "getdate.y"
|
||||
{
|
||||
yyHaveTime++;
|
||||
context->yyHaveTime++;
|
||||
;
|
||||
break;}
|
||||
case 4:
|
||||
#line 229 "getdate.y"
|
||||
#line 238 "getdate.y"
|
||||
{
|
||||
yyHaveZone++;
|
||||
context->yyHaveZone++;
|
||||
;
|
||||
break;}
|
||||
case 5:
|
||||
#line 232 "getdate.y"
|
||||
#line 241 "getdate.y"
|
||||
{
|
||||
yyHaveDate++;
|
||||
context->yyHaveDate++;
|
||||
;
|
||||
break;}
|
||||
case 6:
|
||||
#line 235 "getdate.y"
|
||||
#line 244 "getdate.y"
|
||||
{
|
||||
yyHaveDay++;
|
||||
context->yyHaveDay++;
|
||||
;
|
||||
break;}
|
||||
case 7:
|
||||
#line 238 "getdate.y"
|
||||
#line 247 "getdate.y"
|
||||
{
|
||||
yyHaveRel++;
|
||||
context->yyHaveRel++;
|
||||
;
|
||||
break;}
|
||||
case 9:
|
||||
#line 244 "getdate.y"
|
||||
#line 253 "getdate.y"
|
||||
{
|
||||
yyHour = yyvsp[-1].Number;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = yyvsp[0].Meridian;
|
||||
context->yyHour = yyvsp[-1].Number;
|
||||
context->yyMinutes = 0;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = yyvsp[0].Meridian;
|
||||
;
|
||||
break;}
|
||||
case 10:
|
||||
#line 250 "getdate.y"
|
||||
#line 259 "getdate.y"
|
||||
{
|
||||
yyHour = yyvsp[-3].Number;
|
||||
yyMinutes = yyvsp[-1].Number;
|
||||
yySeconds = 0;
|
||||
yyMeridian = yyvsp[0].Meridian;
|
||||
context->yyHour = yyvsp[-3].Number;
|
||||
context->yyMinutes = yyvsp[-1].Number;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = yyvsp[0].Meridian;
|
||||
;
|
||||
break;}
|
||||
case 11:
|
||||
#line 256 "getdate.y"
|
||||
#line 265 "getdate.y"
|
||||
{
|
||||
yyHour = yyvsp[-3].Number;
|
||||
yyMinutes = yyvsp[-1].Number;
|
||||
yyMeridian = MER24;
|
||||
yyHaveZone++;
|
||||
yyTimezone = (yyvsp[0].Number < 0
|
||||
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
|
||||
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
|
||||
context->yyHour = yyvsp[-3].Number;
|
||||
context->yyMinutes = yyvsp[-1].Number;
|
||||
context->yyMeridian = MER24;
|
||||
context->yyHaveZone++;
|
||||
context->yyTimezone = (yyvsp[0].Number < 0
|
||||
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
|
||||
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
|
||||
;
|
||||
break;}
|
||||
case 12:
|
||||
#line 265 "getdate.y"
|
||||
#line 274 "getdate.y"
|
||||
{
|
||||
yyHour = yyvsp[-5].Number;
|
||||
yyMinutes = yyvsp[-3].Number;
|
||||
yySeconds = yyvsp[-1].Number;
|
||||
yyMeridian = yyvsp[0].Meridian;
|
||||
context->yyHour = yyvsp[-5].Number;
|
||||
context->yyMinutes = yyvsp[-3].Number;
|
||||
context->yySeconds = yyvsp[-1].Number;
|
||||
context->yyMeridian = yyvsp[0].Meridian;
|
||||
;
|
||||
break;}
|
||||
case 13:
|
||||
#line 271 "getdate.y"
|
||||
#line 280 "getdate.y"
|
||||
{
|
||||
yyHour = yyvsp[-5].Number;
|
||||
yyMinutes = yyvsp[-3].Number;
|
||||
yySeconds = yyvsp[-1].Number;
|
||||
yyMeridian = MER24;
|
||||
yyHaveZone++;
|
||||
yyTimezone = (yyvsp[0].Number < 0
|
||||
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
|
||||
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
|
||||
context->yyHour = yyvsp[-5].Number;
|
||||
context->yyMinutes = yyvsp[-3].Number;
|
||||
context->yySeconds = yyvsp[-1].Number;
|
||||
context->yyMeridian = MER24;
|
||||
context->yyHaveZone++;
|
||||
context->yyTimezone = (yyvsp[0].Number < 0
|
||||
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
|
||||
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
|
||||
;
|
||||
break;}
|
||||
case 14:
|
||||
#line 283 "getdate.y"
|
||||
#line 292 "getdate.y"
|
||||
{
|
||||
yyTimezone = yyvsp[0].Number;
|
||||
context->yyTimezone = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 15:
|
||||
#line 286 "getdate.y"
|
||||
#line 295 "getdate.y"
|
||||
{
|
||||
yyTimezone = yyvsp[0].Number - 60;
|
||||
context->yyTimezone = yyvsp[0].Number - 60;
|
||||
;
|
||||
break;}
|
||||
case 16:
|
||||
#line 290 "getdate.y"
|
||||
#line 299 "getdate.y"
|
||||
{
|
||||
yyTimezone = yyvsp[-1].Number - 60;
|
||||
context->yyTimezone = yyvsp[-1].Number - 60;
|
||||
;
|
||||
break;}
|
||||
case 17:
|
||||
#line 295 "getdate.y"
|
||||
#line 304 "getdate.y"
|
||||
{
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = yyvsp[0].Number;
|
||||
context->yyDayOrdinal = 1;
|
||||
context->yyDayNumber = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 18:
|
||||
#line 299 "getdate.y"
|
||||
#line 308 "getdate.y"
|
||||
{
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = yyvsp[-1].Number;
|
||||
context->yyDayOrdinal = 1;
|
||||
context->yyDayNumber = yyvsp[-1].Number;
|
||||
;
|
||||
break;}
|
||||
case 19:
|
||||
#line 303 "getdate.y"
|
||||
#line 312 "getdate.y"
|
||||
{
|
||||
yyDayOrdinal = yyvsp[-1].Number;
|
||||
yyDayNumber = yyvsp[0].Number;
|
||||
context->yyDayOrdinal = yyvsp[-1].Number;
|
||||
context->yyDayNumber = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 20:
|
||||
#line 309 "getdate.y"
|
||||
#line 318 "getdate.y"
|
||||
{
|
||||
yyMonth = yyvsp[-2].Number;
|
||||
yyDay = yyvsp[0].Number;
|
||||
context->yyMonth = yyvsp[-2].Number;
|
||||
context->yyDay = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 21:
|
||||
#line 313 "getdate.y"
|
||||
#line 322 "getdate.y"
|
||||
{
|
||||
/* 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
|
||||
@@ -1070,226 +1076,227 @@ case 21:
|
||||
you want portability, use the ISO 8601 format. */
|
||||
if (yyvsp[-4].Number >= 1000)
|
||||
{
|
||||
yyYear = yyvsp[-4].Number;
|
||||
yyMonth = yyvsp[-2].Number;
|
||||
yyDay = yyvsp[0].Number;
|
||||
context->yyYear = yyvsp[-4].Number;
|
||||
context->yyMonth = yyvsp[-2].Number;
|
||||
context->yyDay = yyvsp[0].Number;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyMonth = yyvsp[-4].Number;
|
||||
yyDay = yyvsp[-2].Number;
|
||||
yyYear = yyvsp[0].Number;
|
||||
context->yyMonth = yyvsp[-4].Number;
|
||||
context->yyDay = yyvsp[-2].Number;
|
||||
context->yyYear = yyvsp[0].Number;
|
||||
}
|
||||
;
|
||||
break;}
|
||||
case 22:
|
||||
#line 331 "getdate.y"
|
||||
#line 340 "getdate.y"
|
||||
{
|
||||
/* ISO 8601 format. yyyy-mm-dd. */
|
||||
yyYear = yyvsp[-2].Number;
|
||||
yyMonth = -yyvsp[-1].Number;
|
||||
yyDay = -yyvsp[0].Number;
|
||||
context->yyYear = yyvsp[-2].Number;
|
||||
context->yyMonth = -yyvsp[-1].Number;
|
||||
context->yyDay = -yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 23:
|
||||
#line 337 "getdate.y"
|
||||
#line 346 "getdate.y"
|
||||
{
|
||||
/* e.g. 17-JUN-1992. */
|
||||
yyDay = yyvsp[-2].Number;
|
||||
yyMonth = yyvsp[-1].Number;
|
||||
yyYear = -yyvsp[0].Number;
|
||||
context->yyDay = yyvsp[-2].Number;
|
||||
context->yyMonth = yyvsp[-1].Number;
|
||||
context->yyYear = -yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 24:
|
||||
#line 343 "getdate.y"
|
||||
#line 352 "getdate.y"
|
||||
{
|
||||
yyMonth = yyvsp[-1].Number;
|
||||
yyDay = yyvsp[0].Number;
|
||||
context->yyMonth = yyvsp[-1].Number;
|
||||
context->yyDay = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 25:
|
||||
#line 347 "getdate.y"
|
||||
#line 356 "getdate.y"
|
||||
{
|
||||
yyMonth = yyvsp[-3].Number;
|
||||
yyDay = yyvsp[-2].Number;
|
||||
yyYear = yyvsp[0].Number;
|
||||
context->yyMonth = yyvsp[-3].Number;
|
||||
context->yyDay = yyvsp[-2].Number;
|
||||
context->yyYear = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 26:
|
||||
#line 352 "getdate.y"
|
||||
#line 361 "getdate.y"
|
||||
{
|
||||
yyMonth = yyvsp[0].Number;
|
||||
yyDay = yyvsp[-1].Number;
|
||||
context->yyMonth = yyvsp[0].Number;
|
||||
context->yyDay = yyvsp[-1].Number;
|
||||
;
|
||||
break;}
|
||||
case 27:
|
||||
#line 356 "getdate.y"
|
||||
#line 365 "getdate.y"
|
||||
{
|
||||
yyMonth = yyvsp[-1].Number;
|
||||
yyDay = yyvsp[-2].Number;
|
||||
yyYear = yyvsp[0].Number;
|
||||
context->yyMonth = yyvsp[-1].Number;
|
||||
context->yyDay = yyvsp[-2].Number;
|
||||
context->yyYear = yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 28:
|
||||
#line 363 "getdate.y"
|
||||
#line 372 "getdate.y"
|
||||
{
|
||||
yyRelSeconds = -yyRelSeconds;
|
||||
yyRelMinutes = -yyRelMinutes;
|
||||
yyRelHour = -yyRelHour;
|
||||
yyRelDay = -yyRelDay;
|
||||
yyRelMonth = -yyRelMonth;
|
||||
yyRelYear = -yyRelYear;
|
||||
context->yyRelSeconds = -context->yyRelSeconds;
|
||||
context->yyRelMinutes = -context->yyRelMinutes;
|
||||
context->yyRelHour = -context->yyRelHour;
|
||||
context->yyRelDay = -context->yyRelDay;
|
||||
context->yyRelMonth = -context->yyRelMonth;
|
||||
context->yyRelYear = -context->yyRelYear;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 32:
|
||||
#line 380 "getdate.y"
|
||||
#line 389 "getdate.y"
|
||||
{
|
||||
yyRelYear += yyvsp[0].Number;
|
||||
context->yyRelYear += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 35:
|
||||
#line 389 "getdate.y"
|
||||
#line 398 "getdate.y"
|
||||
{
|
||||
yyRelMonth += yyvsp[0].Number;
|
||||
context->yyRelMonth += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 38:
|
||||
#line 398 "getdate.y"
|
||||
#line 407 "getdate.y"
|
||||
{
|
||||
yyRelDay += yyvsp[0].Number;
|
||||
context->yyRelDay += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 41:
|
||||
#line 407 "getdate.y"
|
||||
#line 416 "getdate.y"
|
||||
{
|
||||
yyRelHour += yyvsp[0].Number;
|
||||
context->yyRelHour += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 44:
|
||||
#line 416 "getdate.y"
|
||||
#line 425 "getdate.y"
|
||||
{
|
||||
yyRelMinutes += yyvsp[0].Number;
|
||||
context->yyRelMinutes += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
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;}
|
||||
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;}
|
||||
case 47:
|
||||
#line 425 "getdate.y"
|
||||
#line 434 "getdate.y"
|
||||
{
|
||||
yyRelSeconds += yyvsp[0].Number;
|
||||
context->yyRelSeconds += yyvsp[0].Number;
|
||||
;
|
||||
break;}
|
||||
case 48:
|
||||
#line 431 "getdate.y"
|
||||
#line 440 "getdate.y"
|
||||
{
|
||||
if (yyHaveTime && yyHaveDate && !yyHaveRel)
|
||||
yyYear = yyvsp[0].Number;
|
||||
if (context->yyHaveTime && context->yyHaveDate &&
|
||||
!context->yyHaveRel)
|
||||
context->yyYear = yyvsp[0].Number;
|
||||
else
|
||||
{
|
||||
if (yyvsp[0].Number>10000)
|
||||
{
|
||||
yyHaveDate++;
|
||||
yyDay= (yyvsp[0].Number)%100;
|
||||
yyMonth= (yyvsp[0].Number/100)%100;
|
||||
yyYear = yyvsp[0].Number/10000;
|
||||
context->yyHaveDate++;
|
||||
context->yyDay= (yyvsp[0].Number)%100;
|
||||
context->yyMonth= (yyvsp[0].Number/100)%100;
|
||||
context->yyYear = yyvsp[0].Number/10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyHaveTime++;
|
||||
context->yyHaveTime++;
|
||||
if (yyvsp[0].Number < 100)
|
||||
{
|
||||
yyHour = yyvsp[0].Number;
|
||||
yyMinutes = 0;
|
||||
context->yyHour = yyvsp[0].Number;
|
||||
context->yyMinutes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyHour = yyvsp[0].Number / 100;
|
||||
yyMinutes = yyvsp[0].Number % 100;
|
||||
context->yyHour = yyvsp[0].Number / 100;
|
||||
context->yyMinutes = yyvsp[0].Number % 100;
|
||||
}
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = MER24;
|
||||
}
|
||||
}
|
||||
;
|
||||
break;}
|
||||
case 49:
|
||||
#line 464 "getdate.y"
|
||||
#line 474 "getdate.y"
|
||||
{
|
||||
yyval.Meridian = MER24;
|
||||
;
|
||||
break;}
|
||||
case 50:
|
||||
#line 468 "getdate.y"
|
||||
#line 478 "getdate.y"
|
||||
{
|
||||
yyval.Meridian = yyvsp[0].Meridian;
|
||||
;
|
||||
@@ -1516,7 +1523,7 @@ yyerrhandle:
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#line 473 "getdate.y"
|
||||
#line 483 "getdate.y"
|
||||
|
||||
|
||||
/* Include this file down here because bison inserts code above which
|
||||
@@ -1772,7 +1779,8 @@ ToYear (Year)
|
||||
}
|
||||
|
||||
static int
|
||||
LookupWord (buff)
|
||||
LookupWord (yylval, buff)
|
||||
YYSTYPE *yylval;
|
||||
char *buff;
|
||||
{
|
||||
register char *p;
|
||||
@@ -1788,12 +1796,12 @@ LookupWord (buff)
|
||||
|
||||
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
|
||||
{
|
||||
yylval.Meridian = MERam;
|
||||
yylval->Meridian = MERam;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
|
||||
{
|
||||
yylval.Meridian = MERpm;
|
||||
yylval->Meridian = MERpm;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
|
||||
@@ -1814,13 +1822,13 @@ LookupWord (buff)
|
||||
{
|
||||
if (strncmp (buff, tp->name, 3) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
else if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
@@ -1828,7 +1836,7 @@ LookupWord (buff)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -1838,7 +1846,7 @@ LookupWord (buff)
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -1850,7 +1858,7 @@ LookupWord (buff)
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
buff[i] = 's'; /* Put back for "this" in OtherTable. */
|
||||
@@ -1859,7 +1867,7 @@ LookupWord (buff)
|
||||
for (tp = OtherTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -1869,7 +1877,7 @@ LookupWord (buff)
|
||||
for (tp = MilitaryTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
@@ -1885,7 +1893,7 @@ LookupWord (buff)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -1893,7 +1901,9 @@ LookupWord (buff)
|
||||
}
|
||||
|
||||
static int
|
||||
yylex ()
|
||||
yylex (yylval, cookie)
|
||||
YYSTYPE *yylval;
|
||||
void *cookie;
|
||||
{
|
||||
register unsigned char c;
|
||||
register char *p;
|
||||
@@ -1903,42 +1913,42 @@ yylex ()
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (ISSPACE ((unsigned char) *yyInput))
|
||||
yyInput++;
|
||||
while (ISSPACE ((unsigned char) *context->yyInput))
|
||||
context->yyInput++;
|
||||
|
||||
if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
|
||||
if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
|
||||
{
|
||||
if (c == '-' || c == '+')
|
||||
{
|
||||
sign = c == '-' ? -1 : 1;
|
||||
if (!ISDIGIT (*++yyInput))
|
||||
if (!ISDIGIT (*++context->yyInput))
|
||||
/* skip the '-' sign */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
|
||||
yylval.Number = 10 * yylval.Number + c - '0';
|
||||
yyInput--;
|
||||
for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
|
||||
yylval->Number = 10 * yylval->Number + c - '0';
|
||||
context->yyInput--;
|
||||
if (sign < 0)
|
||||
yylval.Number = -yylval.Number;
|
||||
yylval->Number = -yylval->Number;
|
||||
return sign ? tSNUMBER : tUNUMBER;
|
||||
}
|
||||
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])
|
||||
*p++ = c;
|
||||
*p = '\0';
|
||||
yyInput--;
|
||||
return LookupWord (buff);
|
||||
context->yyInput--;
|
||||
return LookupWord (yylval, buff);
|
||||
}
|
||||
if (c != '(')
|
||||
return *yyInput++;
|
||||
return *context->yyInput++;
|
||||
Count = 0;
|
||||
do
|
||||
{
|
||||
c = *yyInput++;
|
||||
c = *context->yyInput++;
|
||||
if (c == '\0')
|
||||
return c;
|
||||
if (c == '(')
|
||||
@@ -1978,10 +1988,11 @@ curl_getdate (const char *p, const time_t *now)
|
||||
{
|
||||
struct tm tm, tm0, *tmp;
|
||||
time_t Start;
|
||||
CONTEXT cookie;
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
struct tm keeptime;
|
||||
#endif
|
||||
yyInput = p;
|
||||
cookie.yyInput = p;
|
||||
Start = now ? *now : time ((time_t *) NULL);
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
tmp = (struct tm *)localtime_r(&Start, &keeptime);
|
||||
@@ -1990,52 +2001,55 @@ curl_getdate (const char *p, const time_t *now)
|
||||
#endif
|
||||
if (!tmp)
|
||||
return -1;
|
||||
yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
|
||||
yyMonth = tmp->tm_mon + 1;
|
||||
yyDay = tmp->tm_mday;
|
||||
yyHour = tmp->tm_hour;
|
||||
yyMinutes = tmp->tm_min;
|
||||
yySeconds = tmp->tm_sec;
|
||||
cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
|
||||
cookie.yyMonth = tmp->tm_mon + 1;
|
||||
cookie.yyDay = tmp->tm_mday;
|
||||
cookie.yyHour = tmp->tm_hour;
|
||||
cookie.yyMinutes = tmp->tm_min;
|
||||
cookie.yySeconds = tmp->tm_sec;
|
||||
tm.tm_isdst = tmp->tm_isdst;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
yyRelMinutes = 0;
|
||||
yyRelHour = 0;
|
||||
yyRelDay = 0;
|
||||
yyRelMonth = 0;
|
||||
yyRelYear = 0;
|
||||
yyHaveDate = 0;
|
||||
yyHaveDay = 0;
|
||||
yyHaveRel = 0;
|
||||
yyHaveTime = 0;
|
||||
yyHaveZone = 0;
|
||||
cookie.yyMeridian = MER24;
|
||||
cookie.yyRelSeconds = 0;
|
||||
cookie.yyRelMinutes = 0;
|
||||
cookie.yyRelHour = 0;
|
||||
cookie.yyRelDay = 0;
|
||||
cookie.yyRelMonth = 0;
|
||||
cookie.yyRelYear = 0;
|
||||
cookie.yyHaveDate = 0;
|
||||
cookie.yyHaveDay = 0;
|
||||
cookie.yyHaveRel = 0;
|
||||
cookie.yyHaveTime = 0;
|
||||
cookie.yyHaveZone = 0;
|
||||
|
||||
if (yyparse ()
|
||||
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
|
||||
if (yyparse (&cookie)
|
||||
|| cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
|
||||
cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
|
||||
return -1;
|
||||
|
||||
tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
|
||||
tm.tm_mon = yyMonth - 1 + yyRelMonth;
|
||||
tm.tm_mday = yyDay + yyRelDay;
|
||||
if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
|
||||
tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
|
||||
tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
|
||||
tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
|
||||
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)
|
||||
return -1;
|
||||
tm.tm_min = yyMinutes;
|
||||
tm.tm_sec = yySeconds;
|
||||
tm.tm_min = cookie.yyMinutes;
|
||||
tm.tm_sec = cookie.yySeconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
}
|
||||
tm.tm_hour += yyRelHour;
|
||||
tm.tm_min += yyRelMinutes;
|
||||
tm.tm_sec += yyRelSeconds;
|
||||
tm.tm_hour += cookie.yyRelHour;
|
||||
tm.tm_min += cookie.yyRelMinutes;
|
||||
tm.tm_sec += cookie.yyRelSeconds;
|
||||
|
||||
/* Let mktime deduce tm_isdst if we have an absolute timestamp,
|
||||
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;
|
||||
|
||||
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
|
||||
zone by 24 hours to compensate. This algorithm assumes that
|
||||
there is no DST transition within a day of the time_t boundaries. */
|
||||
if (yyHaveZone)
|
||||
if (cookie.yyHaveZone)
|
||||
{
|
||||
tm = tm0;
|
||||
if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
|
||||
{
|
||||
tm.tm_mday++;
|
||||
yyTimezone -= 24 * 60;
|
||||
cookie.yyTimezone -= 24 * 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tm_mday--;
|
||||
yyTimezone += 24 * 60;
|
||||
cookie.yyTimezone += 24 * 60;
|
||||
}
|
||||
Start = mktime (&tm);
|
||||
}
|
||||
@@ -2073,22 +2087,29 @@ curl_getdate (const char *p, const time_t *now)
|
||||
return Start;
|
||||
}
|
||||
|
||||
if (yyHaveDay && !yyHaveDate)
|
||||
if (cookie.yyHaveDay && !cookie.yyHaveDate)
|
||||
{
|
||||
tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
|
||||
+ 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
|
||||
tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
|
||||
+ 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
|
||||
Start = mktime (&tm);
|
||||
if (Start == (time_t) -1)
|
||||
return Start;
|
||||
}
|
||||
|
||||
if (yyHaveZone)
|
||||
if (cookie.yyHaveZone)
|
||||
{
|
||||
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)
|
||||
return -1;
|
||||
delta = yyTimezone * 60L + difftm (&tm, gmt);
|
||||
delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
|
||||
if ((Start + delta < Start) != (delta < 0))
|
||||
return -1; /* time_t overflow */
|
||||
Start += delta;
|
||||
@@ -2126,11 +2147,3 @@ main (ac, av)
|
||||
/* NOTREACHED */
|
||||
}
|
||||
#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.
|
||||
*/
|
||||
|
||||
#if HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#endif
|
||||
# include "setup.h"
|
||||
|
||||
#ifndef PARAMS
|
||||
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)
|
||||
|
420
lib/getdate.y
420
lib/getdate.y
@@ -10,8 +10,6 @@
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
# ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
# endif
|
||||
@@ -19,6 +17,10 @@
|
||||
# ifdef HAVE_TIME_H
|
||||
# include <time.h>
|
||||
# endif
|
||||
|
||||
#ifndef YYDEBUG
|
||||
/* to satisfy gcc -Wundef, we set this to 0 */
|
||||
#define YYDEBUG 0
|
||||
#endif
|
||||
|
||||
/* Since the code of getdate.y is not included in the Emacs executable
|
||||
@@ -168,41 +170,48 @@ typedef enum _MERIDIAN {
|
||||
MERam, MERpm, MER24
|
||||
} 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;
|
||||
|
||||
/*
|
||||
** Global variables. We could get rid of most of these by using a good
|
||||
** 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.
|
||||
/* enable use of extra argument to yyparse and yylex which can be used to pass
|
||||
** in a user defined value (CONTEXT struct in our case)
|
||||
*/
|
||||
static const char *yyInput;
|
||||
static int yyDayOrdinal;
|
||||
static int yyDayNumber;
|
||||
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;
|
||||
|
||||
#define YYPARSE_PARAM cookie
|
||||
#define YYLEX_PARAM cookie
|
||||
#define context ((CONTEXT *) cookie)
|
||||
%}
|
||||
|
||||
/* This grammar has 13 shift/reduce conflicts. */
|
||||
%expect 13
|
||||
|
||||
/* turn global variables into locals, additionally enable extra arguments
|
||||
** for yylex (pointer to yylval and user defined value)
|
||||
*/
|
||||
%pure_parser
|
||||
|
||||
%union {
|
||||
int Number;
|
||||
enum _MERIDIAN Meridian;
|
||||
@@ -224,91 +233,91 @@ spec : /* NULL */
|
||||
;
|
||||
|
||||
item : time {
|
||||
yyHaveTime++;
|
||||
context->yyHaveTime++;
|
||||
}
|
||||
| zone {
|
||||
yyHaveZone++;
|
||||
context->yyHaveZone++;
|
||||
}
|
||||
| date {
|
||||
yyHaveDate++;
|
||||
context->yyHaveDate++;
|
||||
}
|
||||
| day {
|
||||
yyHaveDay++;
|
||||
context->yyHaveDay++;
|
||||
}
|
||||
| rel {
|
||||
yyHaveRel++;
|
||||
context->yyHaveRel++;
|
||||
}
|
||||
| number
|
||||
;
|
||||
|
||||
time : tUNUMBER tMERIDIAN {
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $2;
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = 0;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = $2;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = 0;
|
||||
yyMeridian = $4;
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = $3;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = $4;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yyMeridian = MER24;
|
||||
yyHaveZone++;
|
||||
yyTimezone = ($4 < 0
|
||||
? -$4 % 100 + (-$4 / 100) * 60
|
||||
: - ($4 % 100 + ($4 / 100) * 60));
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = $3;
|
||||
context->yyMeridian = MER24;
|
||||
context->yyHaveZone++;
|
||||
context->yyTimezone = ($4 < 0
|
||||
? -$4 % 100 + (-$4 / 100) * 60
|
||||
: - ($4 % 100 + ($4 / 100) * 60));
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = $6;
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = $3;
|
||||
context->yySeconds = $5;
|
||||
context->yyMeridian = $6;
|
||||
}
|
||||
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
|
||||
yyHour = $1;
|
||||
yyMinutes = $3;
|
||||
yySeconds = $5;
|
||||
yyMeridian = MER24;
|
||||
yyHaveZone++;
|
||||
yyTimezone = ($6 < 0
|
||||
? -$6 % 100 + (-$6 / 100) * 60
|
||||
: - ($6 % 100 + ($6 / 100) * 60));
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = $3;
|
||||
context->yySeconds = $5;
|
||||
context->yyMeridian = MER24;
|
||||
context->yyHaveZone++;
|
||||
context->yyTimezone = ($6 < 0
|
||||
? -$6 % 100 + (-$6 / 100) * 60
|
||||
: - ($6 % 100 + ($6 / 100) * 60));
|
||||
}
|
||||
;
|
||||
|
||||
zone : tZONE {
|
||||
yyTimezone = $1;
|
||||
context->yyTimezone = $1;
|
||||
}
|
||||
| tDAYZONE {
|
||||
yyTimezone = $1 - 60;
|
||||
context->yyTimezone = $1 - 60;
|
||||
}
|
||||
|
|
||||
tZONE tDST {
|
||||
yyTimezone = $1 - 60;
|
||||
context->yyTimezone = $1 - 60;
|
||||
}
|
||||
;
|
||||
|
||||
day : tDAY {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
context->yyDayOrdinal = 1;
|
||||
context->yyDayNumber = $1;
|
||||
}
|
||||
| tDAY ',' {
|
||||
yyDayOrdinal = 1;
|
||||
yyDayNumber = $1;
|
||||
context->yyDayOrdinal = 1;
|
||||
context->yyDayNumber = $1;
|
||||
}
|
||||
| tUNUMBER tDAY {
|
||||
yyDayOrdinal = $1;
|
||||
yyDayNumber = $2;
|
||||
context->yyDayOrdinal = $1;
|
||||
context->yyDayNumber = $2;
|
||||
}
|
||||
;
|
||||
|
||||
date : tUNUMBER '/' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
context->yyMonth = $1;
|
||||
context->yyDay = $3;
|
||||
}
|
||||
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
|
||||
/* 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. */
|
||||
if ($1 >= 1000)
|
||||
{
|
||||
yyYear = $1;
|
||||
yyMonth = $3;
|
||||
yyDay = $5;
|
||||
context->yyYear = $1;
|
||||
context->yyMonth = $3;
|
||||
context->yyDay = $5;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyMonth = $1;
|
||||
yyDay = $3;
|
||||
yyYear = $5;
|
||||
context->yyMonth = $1;
|
||||
context->yyDay = $3;
|
||||
context->yyYear = $5;
|
||||
}
|
||||
}
|
||||
| tUNUMBER tSNUMBER tSNUMBER {
|
||||
/* ISO 8601 format. yyyy-mm-dd. */
|
||||
yyYear = $1;
|
||||
yyMonth = -$2;
|
||||
yyDay = -$3;
|
||||
context->yyYear = $1;
|
||||
context->yyMonth = -$2;
|
||||
context->yyDay = -$3;
|
||||
}
|
||||
| tUNUMBER tMONTH tSNUMBER {
|
||||
/* e.g. 17-JUN-1992. */
|
||||
yyDay = $1;
|
||||
yyMonth = $2;
|
||||
yyYear = -$3;
|
||||
context->yyDay = $1;
|
||||
context->yyMonth = $2;
|
||||
context->yyYear = -$3;
|
||||
}
|
||||
| tMONTH tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
context->yyMonth = $1;
|
||||
context->yyDay = $2;
|
||||
}
|
||||
| tMONTH tUNUMBER ',' tUNUMBER {
|
||||
yyMonth = $1;
|
||||
yyDay = $2;
|
||||
yyYear = $4;
|
||||
context->yyMonth = $1;
|
||||
context->yyDay = $2;
|
||||
context->yyYear = $4;
|
||||
}
|
||||
| tUNUMBER tMONTH {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
context->yyMonth = $2;
|
||||
context->yyDay = $1;
|
||||
}
|
||||
| tUNUMBER tMONTH tUNUMBER {
|
||||
yyMonth = $2;
|
||||
yyDay = $1;
|
||||
yyYear = $3;
|
||||
context->yyMonth = $2;
|
||||
context->yyDay = $1;
|
||||
context->yyYear = $3;
|
||||
}
|
||||
;
|
||||
|
||||
rel : relunit tAGO {
|
||||
yyRelSeconds = -yyRelSeconds;
|
||||
yyRelMinutes = -yyRelMinutes;
|
||||
yyRelHour = -yyRelHour;
|
||||
yyRelDay = -yyRelDay;
|
||||
yyRelMonth = -yyRelMonth;
|
||||
yyRelYear = -yyRelYear;
|
||||
context->yyRelSeconds = -context->yyRelSeconds;
|
||||
context->yyRelMinutes = -context->yyRelMinutes;
|
||||
context->yyRelHour = -context->yyRelHour;
|
||||
context->yyRelDay = -context->yyRelDay;
|
||||
context->yyRelMonth = -context->yyRelMonth;
|
||||
context->yyRelYear = -context->yyRelYear;
|
||||
}
|
||||
| relunit
|
||||
;
|
||||
|
||||
relunit : tUNUMBER tYEAR_UNIT {
|
||||
yyRelYear += $1 * $2;
|
||||
context->yyRelYear += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tYEAR_UNIT {
|
||||
yyRelYear += $1 * $2;
|
||||
context->yyRelYear += $1 * $2;
|
||||
}
|
||||
| tYEAR_UNIT {
|
||||
yyRelYear += $1;
|
||||
context->yyRelYear += $1;
|
||||
}
|
||||
| tUNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
context->yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tMONTH_UNIT {
|
||||
yyRelMonth += $1 * $2;
|
||||
context->yyRelMonth += $1 * $2;
|
||||
}
|
||||
| tMONTH_UNIT {
|
||||
yyRelMonth += $1;
|
||||
context->yyRelMonth += $1;
|
||||
}
|
||||
| tUNUMBER tDAY_UNIT {
|
||||
yyRelDay += $1 * $2;
|
||||
context->yyRelDay += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tDAY_UNIT {
|
||||
yyRelDay += $1 * $2;
|
||||
context->yyRelDay += $1 * $2;
|
||||
}
|
||||
| tDAY_UNIT {
|
||||
yyRelDay += $1;
|
||||
context->yyRelDay += $1;
|
||||
}
|
||||
| tUNUMBER tHOUR_UNIT {
|
||||
yyRelHour += $1 * $2;
|
||||
context->yyRelHour += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tHOUR_UNIT {
|
||||
yyRelHour += $1 * $2;
|
||||
context->yyRelHour += $1 * $2;
|
||||
}
|
||||
| tHOUR_UNIT {
|
||||
yyRelHour += $1;
|
||||
context->yyRelHour += $1;
|
||||
}
|
||||
| tUNUMBER tMINUTE_UNIT {
|
||||
yyRelMinutes += $1 * $2;
|
||||
context->yyRelMinutes += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tMINUTE_UNIT {
|
||||
yyRelMinutes += $1 * $2;
|
||||
context->yyRelMinutes += $1 * $2;
|
||||
}
|
||||
| tMINUTE_UNIT {
|
||||
yyRelMinutes += $1;
|
||||
context->yyRelMinutes += $1;
|
||||
}
|
||||
| tUNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1 * $2;
|
||||
context->yyRelSeconds += $1 * $2;
|
||||
}
|
||||
| tSNUMBER tSEC_UNIT {
|
||||
yyRelSeconds += $1 * $2;
|
||||
context->yyRelSeconds += $1 * $2;
|
||||
}
|
||||
| tSEC_UNIT {
|
||||
yyRelSeconds += $1;
|
||||
context->yyRelSeconds += $1;
|
||||
}
|
||||
;
|
||||
|
||||
number : tUNUMBER
|
||||
{
|
||||
if (yyHaveTime && yyHaveDate && !yyHaveRel)
|
||||
yyYear = $1;
|
||||
if (context->yyHaveTime && context->yyHaveDate &&
|
||||
!context->yyHaveRel)
|
||||
context->yyYear = $1;
|
||||
else
|
||||
{
|
||||
if ($1>10000)
|
||||
{
|
||||
yyHaveDate++;
|
||||
yyDay= ($1)%100;
|
||||
yyMonth= ($1/100)%100;
|
||||
yyYear = $1/10000;
|
||||
context->yyHaveDate++;
|
||||
context->yyDay= ($1)%100;
|
||||
context->yyMonth= ($1/100)%100;
|
||||
context->yyYear = $1/10000;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyHaveTime++;
|
||||
context->yyHaveTime++;
|
||||
if ($1 < 100)
|
||||
{
|
||||
yyHour = $1;
|
||||
yyMinutes = 0;
|
||||
context->yyHour = $1;
|
||||
context->yyMinutes = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
yyHour = $1 / 100;
|
||||
yyMinutes = $1 % 100;
|
||||
context->yyHour = $1 / 100;
|
||||
context->yyMinutes = $1 % 100;
|
||||
}
|
||||
yySeconds = 0;
|
||||
yyMeridian = MER24;
|
||||
context->yySeconds = 0;
|
||||
context->yyMeridian = MER24;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -725,7 +735,8 @@ ToYear (Year)
|
||||
}
|
||||
|
||||
static int
|
||||
LookupWord (buff)
|
||||
LookupWord (yylval, buff)
|
||||
YYSTYPE *yylval;
|
||||
char *buff;
|
||||
{
|
||||
register char *p;
|
||||
@@ -741,12 +752,12 @@ LookupWord (buff)
|
||||
|
||||
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
|
||||
{
|
||||
yylval.Meridian = MERam;
|
||||
yylval->Meridian = MERam;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
|
||||
{
|
||||
yylval.Meridian = MERpm;
|
||||
yylval->Meridian = MERpm;
|
||||
return tMERIDIAN;
|
||||
}
|
||||
|
||||
@@ -767,13 +778,13 @@ LookupWord (buff)
|
||||
{
|
||||
if (strncmp (buff, tp->name, 3) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
else if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
@@ -781,7 +792,7 @@ LookupWord (buff)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -791,7 +802,7 @@ LookupWord (buff)
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -803,7 +814,7 @@ LookupWord (buff)
|
||||
for (tp = UnitsTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
buff[i] = 's'; /* Put back for "this" in OtherTable. */
|
||||
@@ -812,7 +823,7 @@ LookupWord (buff)
|
||||
for (tp = OtherTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -822,7 +833,7 @@ LookupWord (buff)
|
||||
for (tp = MilitaryTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
}
|
||||
@@ -838,7 +849,7 @@ LookupWord (buff)
|
||||
for (tp = TimezoneTable; tp->name; tp++)
|
||||
if (strcmp (buff, tp->name) == 0)
|
||||
{
|
||||
yylval.Number = tp->value;
|
||||
yylval->Number = tp->value;
|
||||
return tp->type;
|
||||
}
|
||||
|
||||
@@ -846,7 +857,9 @@ LookupWord (buff)
|
||||
}
|
||||
|
||||
static int
|
||||
yylex ()
|
||||
yylex (yylval, cookie)
|
||||
YYSTYPE *yylval;
|
||||
void *cookie;
|
||||
{
|
||||
register unsigned char c;
|
||||
register char *p;
|
||||
@@ -856,42 +869,42 @@ yylex ()
|
||||
|
||||
for (;;)
|
||||
{
|
||||
while (ISSPACE ((unsigned char) *yyInput))
|
||||
yyInput++;
|
||||
while (ISSPACE ((unsigned char) *context->yyInput))
|
||||
context->yyInput++;
|
||||
|
||||
if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
|
||||
if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
|
||||
{
|
||||
if (c == '-' || c == '+')
|
||||
{
|
||||
sign = c == '-' ? -1 : 1;
|
||||
if (!ISDIGIT (*++yyInput))
|
||||
if (!ISDIGIT (*++context->yyInput))
|
||||
/* skip the '-' sign */
|
||||
continue;
|
||||
}
|
||||
else
|
||||
sign = 0;
|
||||
for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
|
||||
yylval.Number = 10 * yylval.Number + c - '0';
|
||||
yyInput--;
|
||||
for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
|
||||
yylval->Number = 10 * yylval->Number + c - '0';
|
||||
context->yyInput--;
|
||||
if (sign < 0)
|
||||
yylval.Number = -yylval.Number;
|
||||
yylval->Number = -yylval->Number;
|
||||
return sign ? tSNUMBER : tUNUMBER;
|
||||
}
|
||||
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])
|
||||
*p++ = c;
|
||||
*p = '\0';
|
||||
yyInput--;
|
||||
return LookupWord (buff);
|
||||
context->yyInput--;
|
||||
return LookupWord (yylval, buff);
|
||||
}
|
||||
if (c != '(')
|
||||
return *yyInput++;
|
||||
return *context->yyInput++;
|
||||
Count = 0;
|
||||
do
|
||||
{
|
||||
c = *yyInput++;
|
||||
c = *context->yyInput++;
|
||||
if (c == '\0')
|
||||
return c;
|
||||
if (c == '(')
|
||||
@@ -931,10 +944,11 @@ curl_getdate (const char *p, const time_t *now)
|
||||
{
|
||||
struct tm tm, tm0, *tmp;
|
||||
time_t Start;
|
||||
CONTEXT cookie;
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
struct tm keeptime;
|
||||
#endif
|
||||
yyInput = p;
|
||||
cookie.yyInput = p;
|
||||
Start = now ? *now : time ((time_t *) NULL);
|
||||
#ifdef HAVE_LOCALTIME_R
|
||||
tmp = (struct tm *)localtime_r(&Start, &keeptime);
|
||||
@@ -943,52 +957,55 @@ curl_getdate (const char *p, const time_t *now)
|
||||
#endif
|
||||
if (!tmp)
|
||||
return -1;
|
||||
yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
|
||||
yyMonth = tmp->tm_mon + 1;
|
||||
yyDay = tmp->tm_mday;
|
||||
yyHour = tmp->tm_hour;
|
||||
yyMinutes = tmp->tm_min;
|
||||
yySeconds = tmp->tm_sec;
|
||||
cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
|
||||
cookie.yyMonth = tmp->tm_mon + 1;
|
||||
cookie.yyDay = tmp->tm_mday;
|
||||
cookie.yyHour = tmp->tm_hour;
|
||||
cookie.yyMinutes = tmp->tm_min;
|
||||
cookie.yySeconds = tmp->tm_sec;
|
||||
tm.tm_isdst = tmp->tm_isdst;
|
||||
yyMeridian = MER24;
|
||||
yyRelSeconds = 0;
|
||||
yyRelMinutes = 0;
|
||||
yyRelHour = 0;
|
||||
yyRelDay = 0;
|
||||
yyRelMonth = 0;
|
||||
yyRelYear = 0;
|
||||
yyHaveDate = 0;
|
||||
yyHaveDay = 0;
|
||||
yyHaveRel = 0;
|
||||
yyHaveTime = 0;
|
||||
yyHaveZone = 0;
|
||||
cookie.yyMeridian = MER24;
|
||||
cookie.yyRelSeconds = 0;
|
||||
cookie.yyRelMinutes = 0;
|
||||
cookie.yyRelHour = 0;
|
||||
cookie.yyRelDay = 0;
|
||||
cookie.yyRelMonth = 0;
|
||||
cookie.yyRelYear = 0;
|
||||
cookie.yyHaveDate = 0;
|
||||
cookie.yyHaveDay = 0;
|
||||
cookie.yyHaveRel = 0;
|
||||
cookie.yyHaveTime = 0;
|
||||
cookie.yyHaveZone = 0;
|
||||
|
||||
if (yyparse ()
|
||||
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
|
||||
if (yyparse (&cookie)
|
||||
|| cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
|
||||
cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
|
||||
return -1;
|
||||
|
||||
tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
|
||||
tm.tm_mon = yyMonth - 1 + yyRelMonth;
|
||||
tm.tm_mday = yyDay + yyRelDay;
|
||||
if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
|
||||
tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
|
||||
tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
|
||||
tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
|
||||
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)
|
||||
return -1;
|
||||
tm.tm_min = yyMinutes;
|
||||
tm.tm_sec = yySeconds;
|
||||
tm.tm_min = cookie.yyMinutes;
|
||||
tm.tm_sec = cookie.yySeconds;
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
|
||||
}
|
||||
tm.tm_hour += yyRelHour;
|
||||
tm.tm_min += yyRelMinutes;
|
||||
tm.tm_sec += yyRelSeconds;
|
||||
tm.tm_hour += cookie.yyRelHour;
|
||||
tm.tm_min += cookie.yyRelMinutes;
|
||||
tm.tm_sec += cookie.yyRelSeconds;
|
||||
|
||||
/* Let mktime deduce tm_isdst if we have an absolute timestamp,
|
||||
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;
|
||||
|
||||
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
|
||||
zone by 24 hours to compensate. This algorithm assumes that
|
||||
there is no DST transition within a day of the time_t boundaries. */
|
||||
if (yyHaveZone)
|
||||
if (cookie.yyHaveZone)
|
||||
{
|
||||
tm = tm0;
|
||||
if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
|
||||
{
|
||||
tm.tm_mday++;
|
||||
yyTimezone -= 24 * 60;
|
||||
cookie.yyTimezone -= 24 * 60;
|
||||
}
|
||||
else
|
||||
{
|
||||
tm.tm_mday--;
|
||||
yyTimezone += 24 * 60;
|
||||
cookie.yyTimezone += 24 * 60;
|
||||
}
|
||||
Start = mktime (&tm);
|
||||
}
|
||||
@@ -1026,22 +1043,29 @@ curl_getdate (const char *p, const time_t *now)
|
||||
return Start;
|
||||
}
|
||||
|
||||
if (yyHaveDay && !yyHaveDate)
|
||||
if (cookie.yyHaveDay && !cookie.yyHaveDate)
|
||||
{
|
||||
tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
|
||||
+ 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
|
||||
tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
|
||||
+ 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
|
||||
Start = mktime (&tm);
|
||||
if (Start == (time_t) -1)
|
||||
return Start;
|
||||
}
|
||||
|
||||
if (yyHaveZone)
|
||||
if (cookie.yyHaveZone)
|
||||
{
|
||||
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)
|
||||
return -1;
|
||||
delta = yyTimezone * 60L + difftm (&tm, gmt);
|
||||
delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
|
||||
if ((Start + delta < Start) != (delta < 0))
|
||||
return -1; /* time_t overflow */
|
||||
Start += delta;
|
||||
|
@@ -55,7 +55,6 @@ char *GetEnv(const char *variable)
|
||||
if (env && strcmp("HOME",variable) == 0) {
|
||||
env = decc$translate_vms(env);
|
||||
}
|
||||
/* printf ("Getenv: %s=%s\n",variable,env); */
|
||||
#else
|
||||
/* no length control */
|
||||
char *env = getenv(variable);
|
||||
|
@@ -31,6 +31,10 @@
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef VMS
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* This is supposed to be called in the beginning of a permform() session
|
||||
* and should reset all session-info variables
|
||||
@@ -44,11 +48,18 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
|
||||
pro->t_connect = 0;
|
||||
pro->t_pretransfer = 0;
|
||||
pro->t_starttransfer = 0;
|
||||
pro->timespent = 0;
|
||||
|
||||
info->httpcode = 0;
|
||||
info->httpversion=0;
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -132,6 +143,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
|
||||
case CURLINFO_CONTENT_LENGTH_UPLOAD:
|
||||
*param_doublep = data->progress.size_ul;
|
||||
break;
|
||||
case CURLINFO_CONTENT_TYPE:
|
||||
*param_charp = data->info.contenttype;
|
||||
break;
|
||||
default:
|
||||
return CURLE_BAD_FUNCTION_ARGUMENT;
|
||||
}
|
||||
|
285
lib/hash.c
Normal file
285
lib/hash.c
Normal file
@@ -0,0 +1,285 @@
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
|
||||
* licenses. You may pick one of these licenses.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* $Id$
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include "hash.h"
|
||||
#include "llist.h"
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
/* this must be the last include file */
|
||||
#include "memdebug.h"
|
||||
#endif
|
||||
|
||||
|
||||
static unsigned long
|
||||
curl_hash_str(const char *key, unsigned int key_length)
|
||||
{
|
||||
register unsigned long h = 0;
|
||||
register unsigned long g;
|
||||
register char *p = (char *) key;
|
||||
register char *end = (char *) key + key_length;
|
||||
|
||||
while (p < end) {
|
||||
h = (h << 4) + *p++;
|
||||
if ((g = (h & 0xF0000000))) {
|
||||
h = h ^ (g >> 24);
|
||||
h = h ^ g;
|
||||
}
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
static unsigned long
|
||||
curl_hash_num(unsigned long key)
|
||||
{
|
||||
key += ~(key << 15);
|
||||
key ^= (key >> 10);
|
||||
key += (key << 3);
|
||||
key ^= (key >> 6);
|
||||
key += (key << 11);
|
||||
key ^= (key >> 16);
|
||||
|
||||
return key;
|
||||
}
|
||||
|
||||
static void
|
||||
hash_element_dtor(void *u, void *ele)
|
||||
{
|
||||
curl_hash_element *e = (curl_hash_element *) ele;
|
||||
curl_hash *h = (curl_hash *) u;
|
||||
|
||||
if (e->key.type == CURL_HASH_KEY_IS_STRING) {
|
||||
free(e->key.value.str.val);
|
||||
}
|
||||
h->dtor(e->ptr);
|
||||
|
||||
free(e);
|
||||
e = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
|
||||
{
|
||||
int i;
|
||||
|
||||
h->dtor = dtor;
|
||||
h->size = 0;
|
||||
h->slots = slots;
|
||||
|
||||
h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
|
||||
for (i = 0; i < h->slots; ++i) {
|
||||
h->table[i] = curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
|
||||
}
|
||||
}
|
||||
|
||||
curl_hash *
|
||||
curl_hash_alloc(int slots, curl_hash_dtor dtor)
|
||||
{
|
||||
curl_hash *h;
|
||||
|
||||
h = (curl_hash *)malloc(sizeof(curl_hash));
|
||||
if(NULL == h)
|
||||
return NULL;
|
||||
|
||||
curl_hash_init(h, slots, dtor);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
#define FIND_SLOT(__h, __s_key, __s_key_len, __n_key) \
|
||||
((__s_key ? curl_hash_str(__s_key, __s_key_len) : curl_hash_num(__n_key)) % (__h)->slots)
|
||||
|
||||
#define KEY_CREATE(__k, __s_key, __s_key_len, __n_key, __dup) \
|
||||
if (__s_key) { \
|
||||
if (__dup) { \
|
||||
(__k)->value.str.val = (char *) malloc(__s_key_len); \
|
||||
memcpy((__k)->value.str.val, __s_key, __s_key_len); \
|
||||
} else { \
|
||||
(__k)->value.str.val = __s_key; \
|
||||
} \
|
||||
(__k)->value.str.len = __s_key_len; \
|
||||
(__k)->type = CURL_HASH_KEY_IS_STRING; \
|
||||
} else { \
|
||||
(__k)->value.num = __n_key; \
|
||||
(__k)->type = CURL_HASH_KEY_IS_NUM; \
|
||||
}
|
||||
|
||||
#define MIN(a, b) (a > b ? b : a)
|
||||
|
||||
static int
|
||||
curl_hash_key_compare(curl_hash_key *key1, curl_hash_key *key2)
|
||||
{
|
||||
if (key1->type == CURL_HASH_KEY_IS_NUM) {
|
||||
if (key2->type == CURL_HASH_KEY_IS_STRING)
|
||||
return 0;
|
||||
|
||||
if (key1->value.num == key2->value.num)
|
||||
return 1;
|
||||
} else {
|
||||
if (key2->type == CURL_HASH_KEY_IS_NUM)
|
||||
return 0;
|
||||
|
||||
if (memcmp(key1->value.str.val, key2->value.str.val,
|
||||
MIN(key1->value.str.len, key2->value.str.len)) == 0)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
curl_hash_add_or_update(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key, const void *p)
|
||||
{
|
||||
curl_hash_element *e;
|
||||
curl_hash_key tmp;
|
||||
curl_llist *l;
|
||||
curl_llist_element *le;
|
||||
int slot;
|
||||
|
||||
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
|
||||
l = h->table[slot];
|
||||
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
|
||||
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
|
||||
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
|
||||
curl_hash_element *to_update = CURL_LLIST_VALP(le);
|
||||
h->dtor(to_update->ptr);
|
||||
to_update->ptr = (void *) p;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
e = (curl_hash_element *) malloc(sizeof(curl_hash_element));
|
||||
KEY_CREATE(&e->key, str_key, str_key_len, num_key, 1);
|
||||
e->ptr = (void *) p;
|
||||
|
||||
if (curl_llist_insert_next(l, CURL_LLIST_TAIL(l), e)) {
|
||||
++h->size;
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key)
|
||||
{
|
||||
curl_llist *l;
|
||||
curl_llist_element *le;
|
||||
curl_hash_key tmp;
|
||||
int slot;
|
||||
|
||||
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
|
||||
l = h->table[slot];
|
||||
|
||||
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
|
||||
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
|
||||
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
|
||||
curl_llist_remove(l, le, (void *) h);
|
||||
--h->size;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key, void **p)
|
||||
{
|
||||
curl_llist *l;
|
||||
curl_llist_element *le;
|
||||
curl_hash_key tmp;
|
||||
int slot;
|
||||
|
||||
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
|
||||
l = h->table[slot];
|
||||
|
||||
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
|
||||
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
|
||||
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
|
||||
*p = ((curl_hash_element *) CURL_LLIST_VALP(le))->ptr;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *))
|
||||
{
|
||||
curl_llist_element *le;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < h->slots; ++i) {
|
||||
for (le = CURL_LLIST_HEAD(h->table[i]); le != NULL; le = CURL_LLIST_NEXT(le)) {
|
||||
cb(user, (curl_hash_element *) CURL_LLIST_VALP(le));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
curl_hash_clean(curl_hash *h)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < h->slots; ++i) {
|
||||
curl_llist_destroy(h->table[i], (void *) h);
|
||||
}
|
||||
|
||||
free(h->table);
|
||||
h->table = NULL;
|
||||
}
|
||||
|
||||
size_t
|
||||
curl_hash_count(curl_hash *h)
|
||||
{
|
||||
return h->size;
|
||||
}
|
||||
|
||||
void
|
||||
curl_hash_destroy(curl_hash *h)
|
||||
{
|
||||
if (!h) {
|
||||
return;
|
||||
}
|
||||
|
||||
curl_hash_clean(h);
|
||||
free(h);
|
||||
h = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* local variables:
|
||||
* eval: (load-file "../curl-mode.el")
|
||||
* end:
|
||||
* vim600: fdm=marker
|
||||
* vim: et sw=2 ts=2 sts=2 tw=78
|
||||
*/
|
85
lib/hash.h
Normal file
85
lib/hash.h
Normal file
@@ -0,0 +1,85 @@
|
||||
#ifndef __HASH_H
|
||||
#define __HASH_H
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
|
||||
* licenses. You may pick one of these licenses.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* $Id$
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
#define CURL_HASH_KEY_IS_STRING 0
|
||||
#define CURL_HASH_KEY_IS_NUM 1
|
||||
|
||||
typedef void (*curl_hash_dtor)(void *);
|
||||
|
||||
typedef struct _curl_hash {
|
||||
curl_llist **table;
|
||||
curl_hash_dtor dtor;
|
||||
int slots;
|
||||
size_t size;
|
||||
} curl_hash;
|
||||
|
||||
typedef struct _curl_hash_key {
|
||||
union {
|
||||
struct {
|
||||
char *val;
|
||||
unsigned int len;
|
||||
} str;
|
||||
|
||||
unsigned long num;
|
||||
} value;
|
||||
|
||||
int type;
|
||||
} curl_hash_key;
|
||||
|
||||
typedef struct _curl_hash_element {
|
||||
curl_hash_key key;
|
||||
void *ptr;
|
||||
} curl_hash_element;
|
||||
|
||||
|
||||
void curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor);
|
||||
curl_hash *curl_hash_alloc(int slots, curl_hash_dtor dtor);
|
||||
int curl_hash_add_or_update(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key, const void *p);
|
||||
int curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key);
|
||||
int curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len,
|
||||
unsigned long num_key, void **p);
|
||||
void curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *));
|
||||
size_t curl_hash_count(curl_hash *h);
|
||||
void curl_hash_clean(curl_hash *h);
|
||||
void curl_hash_destroy(curl_hash *h);
|
||||
|
||||
#define curl_hash_find(h, key, key_len, p) curl_hash_extended_find(h, key, key_len, 0, p)
|
||||
#define curl_hash_delete(h, key, key_len) curl_hash_extended_delete(h, key, key_len, 0)
|
||||
#define curl_hash_add(h, key, key_len, p) curl_hash_add_or_update(h, key, key_len, 0, p)
|
||||
#define curl_hash_update curl_hash_add
|
||||
#define curl_hash_index_find(h, key, p) curl_hash_extended_find(h, NULL, 0, key, p)
|
||||
#define curl_hash_index_delete(h, key) curl_hash_extended_delete(h, NULL, 0, key)
|
||||
#define curl_hash_index_add(h, key, p) curl_hash_add_or_update(h, NULL, 0, key, p)
|
||||
#define curl_hash_index_update curl_hash_index_add
|
||||
|
||||
#endif
|
177
lib/hostip.c
177
lib/hostip.c
@@ -50,6 +50,7 @@
|
||||
#include <stdlib.h> /* required for free() prototypes */
|
||||
#endif
|
||||
#ifdef VMS
|
||||
#include <in.h>
|
||||
#include <inet.h>
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
@@ -58,6 +59,10 @@
|
||||
#include "urldata.h"
|
||||
#include "sendf.h"
|
||||
#include "hostip.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)
|
||||
#include "inet_ntoa_r.h"
|
||||
@@ -68,6 +73,151 @@
|
||||
#include "memdebug.h"
|
||||
#endif
|
||||
|
||||
static curl_hash hostname_cache;
|
||||
static int host_cache_initialized;
|
||||
|
||||
void Curl_global_host_cache_init(void)
|
||||
{
|
||||
if (!host_cache_initialized) {
|
||||
curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo);
|
||||
host_cache_initialized = 1;
|
||||
}
|
||||
}
|
||||
|
||||
curl_hash *Curl_global_host_cache_get(void)
|
||||
{
|
||||
return &hostname_cache;
|
||||
}
|
||||
|
||||
void Curl_global_host_cache_dtor(void)
|
||||
{
|
||||
if (host_cache_initialized) {
|
||||
curl_hash_clean(&hostname_cache);
|
||||
host_cache_initialized = 0;
|
||||
}
|
||||
}
|
||||
|
||||
struct curl_dns_cache_entry {
|
||||
Curl_addrinfo *addr;
|
||||
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,
|
||||
char *hostname,
|
||||
int port,
|
||||
char **bufp)
|
||||
{
|
||||
char *entry_id = NULL;
|
||||
struct curl_dns_cache_entry *p = NULL;
|
||||
ssize_t entry_len;
|
||||
time_t now;
|
||||
|
||||
/* If the host cache timeout is 0, we don't do DNS cach'ing
|
||||
so fall through */
|
||||
if (data->set.dns_cache_timeout == 0) {
|
||||
return Curl_getaddrinfo(data, hostname, port, bufp);
|
||||
}
|
||||
|
||||
/* 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);
|
||||
/* See if its already in our dns cache */
|
||||
if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) {
|
||||
/* Do we need to check for a cache timeout? */
|
||||
if (data->set.dns_cache_timeout != -1) {
|
||||
/* Return if the entry has not timed out */
|
||||
if ((now - p->timestamp) < data->set.dns_cache_timeout) {
|
||||
_hostcache_return(p->addr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_hostcache_return(p->addr);
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a new cache entry */
|
||||
p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry));
|
||||
if (!p) {
|
||||
_hostcache_return(NULL);
|
||||
}
|
||||
|
||||
p->addr = Curl_getaddrinfo(data, hostname, port, bufp);
|
||||
if (!p->addr) {
|
||||
free(p);
|
||||
_hostcache_return(NULL);
|
||||
}
|
||||
p->timestamp = now;
|
||||
|
||||
/* Save it in our host cache */
|
||||
curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p);
|
||||
|
||||
_hostcache_return(p->addr);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is a wrapper function for freeing name information in a protocol
|
||||
* independent way. This takes care of using the appropriate underlaying
|
||||
@@ -75,11 +225,15 @@
|
||||
*/
|
||||
void Curl_freeaddrinfo(void *freethis)
|
||||
{
|
||||
struct curl_dns_cache_entry *p = (struct curl_dns_cache_entry *) freethis;
|
||||
|
||||
#ifdef ENABLE_IPV6
|
||||
freeaddrinfo(freethis);
|
||||
freeaddrinfo(p->addr);
|
||||
#else
|
||||
free(freethis);
|
||||
free(p->addr);
|
||||
#endif
|
||||
|
||||
free(p);
|
||||
}
|
||||
|
||||
/* --- resolve name or IP-number --- */
|
||||
@@ -102,7 +256,7 @@ int curl_getaddrinfo(char *hostname, char *service,
|
||||
/* success */
|
||||
if(logfile)
|
||||
fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
|
||||
source, line, *result);
|
||||
source, line, (void *)*result);
|
||||
}
|
||||
else {
|
||||
if(logfile)
|
||||
@@ -118,7 +272,7 @@ void curl_freeaddrinfo(struct addrinfo *freethis,
|
||||
(freeaddrinfo)(freethis);
|
||||
if(logfile)
|
||||
fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
|
||||
source, line, freethis);
|
||||
source, line, (void *)freethis);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -139,7 +293,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
char sbuf[NI_MAXSERV];
|
||||
|
||||
memset(&hints, 0, sizeof(hints));
|
||||
hints.ai_family = PF_UNSPEC;
|
||||
hints.ai_family = PF_INET;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_CANONNAME;
|
||||
snprintf(sbuf, sizeof(sbuf), "%d", port);
|
||||
@@ -256,7 +410,7 @@ static char *MakeIP(unsigned long num,char *addr, int addr_len)
|
||||
considerably. */
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE (unsigned long) ~0
|
||||
#define INADDR_NONE (in_addr_t) ~0
|
||||
#endif
|
||||
|
||||
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
@@ -273,10 +427,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
* everything. OSF1 is known to require at least 8872 bytes. The buffer
|
||||
* required for storing all possible aliases and IP numbers is according to
|
||||
* 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)
|
||||
return NULL; /* major failure */
|
||||
*bufp = buf;
|
||||
*bufp = (char *)buf;
|
||||
|
||||
port=0; /* unused in IPv4 code */
|
||||
ret = 0; /* to prevent the compiler warning */
|
||||
@@ -306,7 +460,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
/* Solaris, IRIX and more */
|
||||
if ((h = gethostbyname_r(hostname,
|
||||
(struct hostent *)buf,
|
||||
buf + sizeof(struct hostent),
|
||||
(char *)buf + sizeof(struct hostent),
|
||||
CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
|
||||
&h_errnop)) == NULL )
|
||||
#endif
|
||||
@@ -314,7 +468,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
/* Linux */
|
||||
if( gethostbyname_r(hostname,
|
||||
(struct hostent *)buf,
|
||||
buf + sizeof(struct hostent),
|
||||
(char *)buf + sizeof(struct hostent),
|
||||
CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
|
||||
&h, /* DIFFERENCE */
|
||||
&h_errnop))
|
||||
@@ -357,7 +511,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
/* 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
|
||||
want/expect that */
|
||||
h = pack_hostent(buf, h);
|
||||
h = pack_hostent((char *)buf, h);
|
||||
#endif
|
||||
}
|
||||
return (h);
|
||||
@@ -372,3 +526,4 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
* vim600: fdm=marker
|
||||
* vim: et sw=2 ts=2 sts=2 tw=78
|
||||
*/
|
||||
|
||||
|
13
lib/hostip.h
13
lib/hostip.h
@@ -23,10 +23,23 @@
|
||||
* $Id$
|
||||
*****************************************************************************/
|
||||
|
||||
#include "hash.h"
|
||||
|
||||
struct addrinfo;
|
||||
struct hostent;
|
||||
struct SessionHandle;
|
||||
|
||||
void Curl_global_host_cache_init(void);
|
||||
void Curl_global_host_cache_dtor(void);
|
||||
curl_hash *Curl_global_host_cache_get(void);
|
||||
|
||||
#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
|
||||
|
||||
Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
|
||||
char *hostname,
|
||||
int port,
|
||||
char **bufp);
|
||||
|
||||
/* Get name info */
|
||||
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
|
||||
char *hostname,
|
||||
|
58
lib/http.c
58
lib/http.c
@@ -128,8 +128,10 @@ static
|
||||
CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
|
||||
long *bytes_written)
|
||||
{
|
||||
size_t amount;
|
||||
CURLcode result;
|
||||
ssize_t amount;
|
||||
CURLcode res;
|
||||
char *ptr;
|
||||
int size;
|
||||
|
||||
if(conn->data->set.verbose) {
|
||||
fputs("> ", conn->data->set.err);
|
||||
@@ -137,7 +139,25 @@ CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
|
||||
fwrite(in->buffer, in->size_used, 1, conn->data->set.err);
|
||||
}
|
||||
|
||||
result = Curl_write(conn, sockfd, in->buffer, in->size_used, &amount);
|
||||
/* The looping below is required since we use non-blocking sockets, but due
|
||||
to the circumstances we will just loop and try again and again etc */
|
||||
|
||||
ptr = in->buffer;
|
||||
size = in->size_used;
|
||||
do {
|
||||
res = Curl_write(conn, sockfd, ptr, size, &amount);
|
||||
|
||||
if(CURLE_OK != res)
|
||||
break;
|
||||
|
||||
if(amount != size) {
|
||||
size -= amount;
|
||||
ptr += amount;
|
||||
}
|
||||
else
|
||||
break;
|
||||
|
||||
} while(1);
|
||||
|
||||
if(in->buffer)
|
||||
free(in->buffer);
|
||||
@@ -145,7 +165,7 @@ CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
|
||||
|
||||
*bytes_written = amount;
|
||||
|
||||
return result;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -235,6 +255,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
|
||||
int subversion=0;
|
||||
struct SessionHandle *data=conn->data;
|
||||
CURLcode result;
|
||||
int res;
|
||||
|
||||
int nread; /* total size read */
|
||||
int perline; /* count bytes per line */
|
||||
@@ -317,8 +338,12 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
|
||||
* to read, but when we use Curl_read() it may do so. Do confirm
|
||||
* that this is still ok and then remove this comment!
|
||||
*/
|
||||
if(CURLE_OK != Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
|
||||
&gotbytes))
|
||||
res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
|
||||
&gotbytes);
|
||||
if(res< 0)
|
||||
/* EWOULDBLOCK */
|
||||
continue; /* go loop yourself */
|
||||
else if(res)
|
||||
keepon = FALSE;
|
||||
else if(gotbytes <= 0) {
|
||||
keepon = FALSE;
|
||||
@@ -790,8 +815,6 @@ CURLcode Curl_http(struct connectdata *conn)
|
||||
}
|
||||
|
||||
if(HTTPREQ_POST_FORM == data->set.httpreq) {
|
||||
char contentType[256];
|
||||
int linelength=0;
|
||||
if(Curl_FormInit(&http->form, http->sendit)) {
|
||||
failf(data, "Internal HTTP POST error!");
|
||||
return CURLE_HTTP_POST_ERROR;
|
||||
@@ -806,7 +829,7 @@ CURLcode Curl_http(struct connectdata *conn)
|
||||
data->set.in = (FILE *)&http->form;
|
||||
|
||||
add_bufferf(req_buffer,
|
||||
"Content-Length: %d\r\n", http->postsize-2);
|
||||
"Content-Length: %d\r\n", http->postsize);
|
||||
|
||||
if(!checkheaders(data, "Expect:")) {
|
||||
/* if not disabled explicitly we add a Expect: 100-continue
|
||||
@@ -815,10 +838,19 @@ CURLcode Curl_http(struct connectdata *conn)
|
||||
add_bufferf(req_buffer,
|
||||
"Expect: 100-continue\r\n");
|
||||
data->set.expect100header = TRUE;
|
||||
}
|
||||
|
||||
if(!checkheaders(data, "Content-Type:")) {
|
||||
/* Get Content-Type: line from Curl_FormReadOneLine, which happens
|
||||
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,
|
||||
sizeof(contentType),
|
||||
1,
|
||||
@@ -830,6 +862,9 @@ CURLcode Curl_http(struct connectdata *conn)
|
||||
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 */
|
||||
Curl_pgrsSetUploadSize(data, http->postsize);
|
||||
|
||||
@@ -910,12 +945,11 @@ CURLcode Curl_http(struct connectdata *conn)
|
||||
add_buffer(req_buffer, "\r\n", 2);
|
||||
add_buffer(req_buffer, data->set.postfields,
|
||||
data->set.postfieldsize);
|
||||
add_buffer(req_buffer, "\r\n", 2);
|
||||
}
|
||||
else {
|
||||
add_bufferf(req_buffer,
|
||||
"\r\n"
|
||||
"%s\r\n",
|
||||
"%s",
|
||||
data->set.postfields );
|
||||
}
|
||||
}
|
||||
|
69
lib/krb4.c
69
lib/krb4.c
@@ -57,6 +57,10 @@
|
||||
#include "ftp.h"
|
||||
#include "sendf.h"
|
||||
|
||||
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
|
||||
#include "inet_ntoa_r.h"
|
||||
#endif
|
||||
|
||||
/* The last #include file should be: */
|
||||
#ifdef MALLOCDEBUG
|
||||
#include "memdebug.h"
|
||||
@@ -193,10 +197,10 @@ krb4_auth(void *app_data, struct connectdata *conn)
|
||||
int checksum;
|
||||
u_int32_t cs;
|
||||
struct krb4_data *d = app_data;
|
||||
struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
|
||||
char *host = conn->hostaddr->h_name;
|
||||
ssize_t nread;
|
||||
int l = sizeof(conn->local_addr);
|
||||
struct SessionHandle *data = conn->data;
|
||||
|
||||
if(getsockname(conn->firstsocket,
|
||||
(struct sockaddr *)LOCAL_ADDR, &l) < 0)
|
||||
@@ -207,80 +211,76 @@ krb4_auth(void *app_data, struct connectdata *conn)
|
||||
if(ret == KDC_PR_UNKNOWN)
|
||||
ret = mk_auth(d, &adat, "rcmd", host, checksum);
|
||||
if(ret) {
|
||||
printf("%s\n", krb_get_err_text(ret));
|
||||
Curl_infof(data, "%s\n", krb_get_err_text(ret));
|
||||
return AUTH_CONTINUE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
|
||||
if (krb_get_config_bool("nat_in_use")) {
|
||||
struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
|
||||
struct in_addr natAddr;
|
||||
|
||||
if (krb_get_our_ip_for_realm(krb_realmofhost(host),
|
||||
&natAddr) != KSUCCESS
|
||||
&& krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
|
||||
printf("Can't get address for realm %s\n",
|
||||
krb_realmofhost(host));
|
||||
Curl_infof(data, "Can't get address for realm %s\n",
|
||||
krb_realmofhost(host));
|
||||
else {
|
||||
if (natAddr.s_addr != localaddr->sin_addr.s_addr) {
|
||||
printf("Using NAT IP address (%s) for kerberos 4\n",
|
||||
(char *)inet_ntoa(natAddr));
|
||||
#ifdef HAVE_INET_NTOA_R
|
||||
char ntoa_buf[64];
|
||||
char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf));
|
||||
#else
|
||||
char *ip = (char *)inet_ntoa(natAddr);
|
||||
#endif
|
||||
Curl_infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
|
||||
localaddr->sin_addr = natAddr;
|
||||
|
||||
/*
|
||||
* This not the best place to do this, but it is here we know that
|
||||
* (probably) NAT is in use! */
|
||||
|
||||
/*passivemode = 1;***/
|
||||
/*printf("Setting: Passive mode on.\n");***/
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/*printf("Local address is %s\n", inet_ntoa(localaddr->sin_addr));***/
|
||||
/*printf("Remote address is %s\n", inet_ntoa(remoteaddr->sin_addr));***/
|
||||
|
||||
if(Curl_base64_encode(adat.dat, adat.length, &p) < 0) {
|
||||
printf("Out of memory base64-encoding.\n");
|
||||
Curl_failf(data, "Out of memory base64-encoding");
|
||||
return AUTH_CONTINUE;
|
||||
}
|
||||
|
||||
if(Curl_ftpsendf(conn, "ADAT %s", p))
|
||||
return -2;
|
||||
|
||||
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, NULL);
|
||||
nread = Curl_GetFTPResponse(data->state.buffer, conn, NULL);
|
||||
if(nread < 0)
|
||||
return -1;
|
||||
free(p);
|
||||
|
||||
if(/*ret != COMPLETE*/conn->data->state.buffer[0] != '2'){
|
||||
printf("Server didn't accept auth data.\n");
|
||||
if(data->state.buffer[0] != '2'){
|
||||
Curl_failf(data, "Server didn't accept auth data");
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
|
||||
p = strstr(conn->data->state.buffer, "ADAT=");
|
||||
if(!p){
|
||||
printf("Remote host didn't send adat reply.\n");
|
||||
p = strstr(data->state.buffer, "ADAT=");
|
||||
if(!p) {
|
||||
Curl_failf(data, "Remote host didn't send adat reply");
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
p += 5;
|
||||
len = Curl_base64_decode(p, adat.dat);
|
||||
if(len < 0){
|
||||
printf("Failed to decode base64 from server.\n");
|
||||
if(len < 0) {
|
||||
Curl_failf(data, "Failed to decode base64 from server");
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
adat.length = len;
|
||||
ret = krb_rd_safe(adat.dat, adat.length, &d->key,
|
||||
(struct sockaddr_in *)hisctladdr,
|
||||
(struct sockaddr_in *)myctladdr, &msg_data);
|
||||
if(ret){
|
||||
printf("Error reading reply from server: %s.\n",
|
||||
krb_get_err_text(ret));
|
||||
if(ret) {
|
||||
Curl_failf(data, "Error reading reply from server: %s",
|
||||
krb_get_err_text(ret));
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
krb_get_int(msg_data.app_data, &cs, 4, 0);
|
||||
if(cs - checksum != 1){
|
||||
printf("Bad checksum returned from server.\n");
|
||||
if(cs - checksum != 1) {
|
||||
Curl_failf(data, "Bad checksum returned from server");
|
||||
return AUTH_ERROR;
|
||||
}
|
||||
return AUTH_OK;
|
||||
@@ -321,15 +321,14 @@ void Curl_krb_kauth(struct connectdata *conn)
|
||||
if(nread < 0)
|
||||
return /*CURLE_OPERATION_TIMEOUTED*/;
|
||||
|
||||
if(/*ret != CONTINUE*/conn->data->state.buffer[0] != '3'){
|
||||
if(conn->data->state.buffer[0] != '3'){
|
||||
Curl_set_command_prot(conn, save);
|
||||
/*code = -1;***/
|
||||
return;
|
||||
}
|
||||
|
||||
p = strstr(conn->data->state.buffer, "T=");
|
||||
if(!p) {
|
||||
printf("Bad reply from server.\n");
|
||||
Curl_failf(conn->data, "Bad reply from server");
|
||||
Curl_set_command_prot(conn, save);
|
||||
return;
|
||||
}
|
||||
@@ -337,7 +336,7 @@ void Curl_krb_kauth(struct connectdata *conn)
|
||||
p += 2;
|
||||
tmp = Curl_base64_decode(p, &tkt.dat);
|
||||
if(tmp < 0) {
|
||||
printf("Failed to decode base64 in reply.\n");
|
||||
Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
|
||||
Curl_set_command_prot(conn, save);
|
||||
return;
|
||||
}
|
||||
@@ -346,7 +345,7 @@ void Curl_krb_kauth(struct connectdata *conn)
|
||||
|
||||
p = strstr(conn->data->state.buffer, "P=");
|
||||
if(!p) {
|
||||
printf("Bad reply from server.\n");
|
||||
Curl_failf(conn->data, "Bad reply from server");
|
||||
Curl_set_command_prot(conn, save);
|
||||
return;
|
||||
}
|
||||
|
168
lib/llist.c
Normal file
168
lib/llist.c
Normal file
@@ -0,0 +1,168 @@
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
|
||||
* licenses. You may pick one of these licenses.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* $Id$
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "llist.h"
|
||||
|
||||
#ifdef MALLOCDEBUG
|
||||
/* this must be the last include file */
|
||||
#include "memdebug.h"
|
||||
#endif
|
||||
void
|
||||
curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
|
||||
{
|
||||
l->size = 0;
|
||||
l->dtor = dtor;
|
||||
l->head = NULL;
|
||||
l->tail = NULL;
|
||||
}
|
||||
|
||||
curl_llist *
|
||||
curl_llist_alloc(curl_llist_dtor dtor)
|
||||
{
|
||||
curl_llist *list;
|
||||
|
||||
list = (curl_llist *)malloc(sizeof(curl_llist));
|
||||
if(NULL == list)
|
||||
return NULL;
|
||||
|
||||
curl_llist_init(list, dtor);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
int
|
||||
curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
|
||||
{
|
||||
curl_llist_element *ne;
|
||||
|
||||
ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
|
||||
ne->ptr = (void *) p;
|
||||
if (list->size == 0) {
|
||||
list->head = ne;
|
||||
list->head->prev = NULL;
|
||||
list->head->next = NULL;
|
||||
list->tail = ne;
|
||||
} else {
|
||||
ne->next = e->next;
|
||||
ne->prev = e;
|
||||
if (e->next) {
|
||||
e->next->prev = ne;
|
||||
} else {
|
||||
list->tail = ne;
|
||||
}
|
||||
e->next = ne;
|
||||
}
|
||||
|
||||
++list->size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
curl_llist_insert_prev(curl_llist *list, curl_llist_element *e, const void *p)
|
||||
{
|
||||
curl_llist_element *ne;
|
||||
|
||||
ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
|
||||
ne->ptr = (void *) p;
|
||||
if (list->size == 0) {
|
||||
list->head = ne;
|
||||
list->head->prev = NULL;
|
||||
list->head->next = NULL;
|
||||
list->tail = ne;
|
||||
} else {
|
||||
ne->next = e;
|
||||
ne->prev = e->prev;
|
||||
if (e->prev)
|
||||
e->prev->next = ne;
|
||||
else
|
||||
list->head = ne;
|
||||
e->prev = ne;
|
||||
}
|
||||
|
||||
++list->size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
|
||||
{
|
||||
if (e == NULL || list->size == 0)
|
||||
return 1;
|
||||
|
||||
if (e == list->head) {
|
||||
list->head = e->next;
|
||||
|
||||
if (list->head == NULL)
|
||||
list->tail = NULL;
|
||||
else
|
||||
e->next->prev = NULL;
|
||||
} else {
|
||||
e->prev->next = e->next;
|
||||
if (!e->next)
|
||||
list->tail = e->prev;
|
||||
else
|
||||
e->next->prev = e->prev;
|
||||
}
|
||||
|
||||
list->dtor(user, e->ptr);
|
||||
free(e);
|
||||
--list->size;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
curl_llist_remove_next(curl_llist *list, curl_llist_element *e, void *user)
|
||||
{
|
||||
return curl_llist_remove(list, e->next, user);
|
||||
}
|
||||
|
||||
int
|
||||
curl_llist_remove_prev(curl_llist *list, curl_llist_element *e, void *user)
|
||||
{
|
||||
return curl_llist_remove(list, e->prev, user);
|
||||
}
|
||||
|
||||
size_t
|
||||
curl_llist_count(curl_llist *list)
|
||||
{
|
||||
return list->size;
|
||||
}
|
||||
|
||||
void
|
||||
curl_llist_destroy(curl_llist *list, void *user)
|
||||
{
|
||||
while (list->size > 0) {
|
||||
curl_llist_remove(list, CURL_LLIST_TAIL(list), user);
|
||||
}
|
||||
|
||||
free(list);
|
||||
list = NULL;
|
||||
}
|
64
lib/llist.h
Normal file
64
lib/llist.h
Normal file
@@ -0,0 +1,64 @@
|
||||
#ifndef __LLIST_H
|
||||
#define __LLIST_H
|
||||
/*****************************************************************************
|
||||
* _ _ ____ _
|
||||
* Project ___| | | | _ \| |
|
||||
* / __| | | | |_) | |
|
||||
* | (__| |_| | _ <| |___
|
||||
* \___|\___/|_| \_\_____|
|
||||
*
|
||||
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al
|
||||
*
|
||||
* In order to be useful for every potential user, curl and libcurl are
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
*
|
||||
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
|
||||
* copies of the Software, and permit persons to whom the Software is
|
||||
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
|
||||
* licenses. You may pick one of these licenses.
|
||||
*
|
||||
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
||||
* KIND, either express or implied.
|
||||
*
|
||||
* $Id$
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
#include <stddef.h>
|
||||
|
||||
typedef void (*curl_llist_dtor)(void *, void *);
|
||||
|
||||
typedef struct _curl_llist_element {
|
||||
void *ptr;
|
||||
|
||||
struct _curl_llist_element *prev;
|
||||
struct _curl_llist_element *next;
|
||||
} curl_llist_element;
|
||||
|
||||
typedef struct _curl_llist {
|
||||
curl_llist_element *head;
|
||||
curl_llist_element *tail;
|
||||
|
||||
curl_llist_dtor dtor;
|
||||
|
||||
size_t size;
|
||||
} curl_llist;
|
||||
|
||||
void curl_llist_init(curl_llist *, curl_llist_dtor);
|
||||
curl_llist *curl_llist_alloc(curl_llist_dtor);
|
||||
int curl_llist_insert_next(curl_llist *, curl_llist_element *, const void *);
|
||||
int curl_llist_insert_prev(curl_llist *, curl_llist_element *, const void *);
|
||||
int curl_llist_remove(curl_llist *, curl_llist_element *, void *);
|
||||
int curl_llist_remove_next(curl_llist *, curl_llist_element *, void *);
|
||||
size_t curl_llist_count(curl_llist *);
|
||||
void curl_llist_destroy(curl_llist *, void *);
|
||||
|
||||
#define CURL_LLIST_HEAD(__l) ((__l)->head)
|
||||
#define CURL_LLIST_TAIL(__l) ((__l)->tail)
|
||||
#define CURL_LLIST_NEXT(__e) ((__e)->next)
|
||||
#define CURL_LLIST_PREV(__e) ((__e)->prev)
|
||||
#define CURL_LLIST_VALP(__e) ((__e)->ptr)
|
||||
#define CURL_LLIST_IS_TAIL(__e) ((__e)->next ? 0 : 1)
|
||||
#define CURL_LLIST_IS_HEAD(__e) ((__e)->prev ? 0 : 1)
|
||||
|
||||
#endif
|
@@ -47,6 +47,11 @@
|
||||
|
||||
/* DONT include memdebug.h here! */
|
||||
|
||||
struct memdebug {
|
||||
int size;
|
||||
char mem[1];
|
||||
};
|
||||
|
||||
/*
|
||||
* Note that these debug functions are very simple and they are meant to
|
||||
* remain so. For advanced analysis, record a log file and write perl scripts
|
||||
@@ -67,16 +72,25 @@ void curl_memdebug(const char *logname)
|
||||
}
|
||||
|
||||
|
||||
void *curl_domalloc(size_t size, int line, const char *source)
|
||||
void *curl_domalloc(size_t wantedsize, int line, const char *source)
|
||||
{
|
||||
void *mem=(malloc)(size);
|
||||
if(mem)
|
||||
struct memdebug *mem;
|
||||
size_t size;
|
||||
|
||||
/* alloc at least 64 bytes */
|
||||
size = sizeof(struct memdebug)+wantedsize;
|
||||
|
||||
mem=(struct memdebug *)(malloc)(size);
|
||||
if(mem) {
|
||||
/* fill memory with junk */
|
||||
memset(mem, 0xA5, size);
|
||||
if(logfile)
|
||||
memset(mem->mem, 0xA5, wantedsize);
|
||||
mem->size = wantedsize;
|
||||
}
|
||||
|
||||
if(logfile && source)
|
||||
fprintf(logfile, "MEM %s:%d malloc(%d) = %p\n",
|
||||
source, line, size, mem);
|
||||
return mem;
|
||||
source, line, wantedsize, mem->mem);
|
||||
return mem->mem;
|
||||
}
|
||||
|
||||
char *curl_dostrdup(const char *str, int line, const char *source)
|
||||
@@ -90,32 +104,56 @@ char *curl_dostrdup(const char *str, int line, const char *source)
|
||||
exit(2);
|
||||
}
|
||||
|
||||
mem=(strdup)(str);
|
||||
len=strlen(str)+1;
|
||||
|
||||
mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
|
||||
memcpy(mem, str, len);
|
||||
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d strdup(%p) (%d) = %p\n",
|
||||
source, line, str, len, mem);
|
||||
|
||||
return mem;
|
||||
}
|
||||
|
||||
void *curl_dorealloc(void *ptr, size_t size, int line, const char *source)
|
||||
void *curl_dorealloc(void *ptr, size_t wantedsize,
|
||||
int line, const char *source)
|
||||
{
|
||||
void *mem=(realloc)(ptr, size);
|
||||
struct memdebug *mem;
|
||||
|
||||
size_t size = sizeof(struct memdebug)+wantedsize;
|
||||
|
||||
mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
|
||||
|
||||
mem=(struct memdebug *)(realloc)(mem, size);
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d realloc(%p, %d) = %p\n",
|
||||
source, line, ptr, size, mem);
|
||||
return mem;
|
||||
source, line, ptr, wantedsize, mem?mem->mem:NULL);
|
||||
|
||||
if(mem) {
|
||||
mem->size = wantedsize;
|
||||
return mem->mem;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void curl_dofree(void *ptr, int line, const char *source)
|
||||
{
|
||||
struct memdebug *mem;
|
||||
|
||||
if(NULL == ptr) {
|
||||
fprintf(stderr, "ILLEGAL free() on NULL at %s:%d\n",
|
||||
source, line);
|
||||
exit(2);
|
||||
}
|
||||
mem = (struct memdebug *)((char *)ptr - offsetof(struct memdebug, mem));
|
||||
|
||||
(free)(ptr);
|
||||
/* destroy */
|
||||
memset(mem->mem, 0x13, mem->size);
|
||||
|
||||
/* free for real */
|
||||
(free)(mem);
|
||||
|
||||
if(logfile)
|
||||
fprintf(logfile, "MEM %s:%d free(%p)\n", source, line, ptr);
|
||||
@@ -168,7 +206,10 @@ int curl_fclose(FILE *file, int line, const char *source)
|
||||
source, line, file);
|
||||
return res;
|
||||
}
|
||||
|
||||
#else
|
||||
#ifdef VMS
|
||||
int VOID_VAR_MEMDEBUG;
|
||||
#endif
|
||||
#endif /* MALLOCDEBUG */
|
||||
|
||||
/*
|
||||
|
@@ -24,73 +24,11 @@
|
||||
* - Max 128 parameters
|
||||
* - No 'long double' support.
|
||||
*
|
||||
*************************************************************************
|
||||
*
|
||||
*
|
||||
* 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
|
||||
*
|
||||
****************************************************************************/
|
||||
* 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/
|
||||
*/
|
||||
|
||||
|
||||
#include "setup.h"
|
||||
#include <sys/types.h>
|
||||
@@ -100,6 +38,15 @@
|
||||
#include <ctype.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: */
|
||||
#ifdef MALLOCDEBUG
|
||||
#include "memdebug.h"
|
||||
@@ -752,9 +699,8 @@ static int dprintf_formatf(
|
||||
#if SIZEOF_LONG_LONG
|
||||
if(p->flags & FLAGS_LONGLONG) {
|
||||
/* long long */
|
||||
num = p->data.lnum;
|
||||
is_neg = num < 0;
|
||||
num = is_neg ? (- num) : num;
|
||||
is_neg = p->data.lnum < 0;
|
||||
num = is_neg ? (- p->data.lnum) : p->data.lnum;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
@@ -1191,7 +1137,7 @@ int main()
|
||||
{
|
||||
char buffer[129];
|
||||
char *ptr;
|
||||
#ifdef SIZEOF_LONG_LONG
|
||||
#if SIZEOF_LONG_LONG>0
|
||||
long long hullo;
|
||||
dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65);
|
||||
#endif
|
||||
|
82
lib/multi.c
82
lib/multi.c
@@ -22,10 +22,16 @@
|
||||
*****************************************************************************/
|
||||
|
||||
#include "setup.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <curl/curl.h>
|
||||
|
||||
#include "multi.h" /* will become <curl/multi.h> soon */
|
||||
|
||||
#include "urldata.h"
|
||||
#include "transfer.h"
|
||||
#include "url.h"
|
||||
|
||||
struct Curl_message {
|
||||
/* the 'CURLMsg' is the part that is visible to the external user */
|
||||
struct CURLMsg extmsg;
|
||||
@@ -48,7 +54,9 @@ struct Curl_one_easy {
|
||||
struct Curl_one_easy *next;
|
||||
struct Curl_one_easy *prev;
|
||||
|
||||
CURL *easy_handle; /* this is the easy handle for this unit */
|
||||
struct SessionHandle *easy_handle; /* the easy handle for this unit */
|
||||
struct connectdata *easy_conn; /* the "unit's" connection */
|
||||
|
||||
CURLMstate state; /* the handle's state */
|
||||
CURLcode result; /* previous result */
|
||||
};
|
||||
@@ -74,7 +82,8 @@ struct Curl_multi {
|
||||
struct Curl_message *msgs;
|
||||
/* amount of messages in the queue */
|
||||
int num_msgs;
|
||||
|
||||
/* Hostname cache */
|
||||
curl_hash *hostcache;
|
||||
};
|
||||
|
||||
|
||||
@@ -134,7 +143,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
|
||||
/* increase the node-counter */
|
||||
multi->num_easy++;
|
||||
|
||||
return CURLM_OK;
|
||||
return CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
|
||||
@@ -190,23 +199,30 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
|
||||
and then we must make sure that is done. */
|
||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||
struct Curl_one_easy *easy;
|
||||
int this_max_fd=-1;
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
*max_fd = -1; /* so far none! */
|
||||
|
||||
easy=multi->easy.next;
|
||||
while(easy) {
|
||||
switch(easy->state) {
|
||||
case CURLM_STATE_INIT:
|
||||
case CURLM_STATE_CONNECT:
|
||||
case CURLM_STATE_DO:
|
||||
case CURLM_STATE_DONE:
|
||||
/* we want curl_multi_perform() to get called, but we don't have any
|
||||
file descriptors to set */
|
||||
default:
|
||||
break;
|
||||
case CURLM_STATE_PERFORM:
|
||||
/* This should have a set of file descriptors for us to set. */
|
||||
/* after the transfer is done, go DONE */
|
||||
|
||||
Curl_single_fdset(easy->easy_conn,
|
||||
read_fd_set, write_fd_set,
|
||||
exc_fd_set, &this_max_fd);
|
||||
|
||||
/* remember the maximum file descriptor */
|
||||
if(this_max_fd > *max_fd)
|
||||
*max_fd = this_max_fd;
|
||||
|
||||
break;
|
||||
}
|
||||
easy = easy->next; /* check next handle */
|
||||
@@ -222,12 +238,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
bool done;
|
||||
CURLMcode result=CURLM_OK;
|
||||
|
||||
*running_handles = 0; /* bump this once for every living handle */
|
||||
|
||||
if(!GOOD_MULTI_HANDLE(multi))
|
||||
return CURLM_BAD_HANDLE;
|
||||
|
||||
easy=multi->easy.next;
|
||||
while(easy) {
|
||||
|
||||
switch(easy->state) {
|
||||
case CURLM_STATE_INIT:
|
||||
/* init this transfer. */
|
||||
@@ -239,8 +256,20 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_CONNECT:
|
||||
/* connect */
|
||||
easy->result = Curl_connect(easy->easy_handle);
|
||||
if (Curl_global_host_cache_use(easy->easy_handle)) {
|
||||
easy->easy_handle->hostcache = Curl_global_host_cache_get();
|
||||
}
|
||||
else {
|
||||
if (multi->hostcache == NULL) {
|
||||
multi->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo);
|
||||
}
|
||||
|
||||
easy->easy_handle->hostcache = multi->hostcache;
|
||||
}
|
||||
|
||||
/* Connect. We get a connection identifier filled in. */
|
||||
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
|
||||
|
||||
/* after connect, go DO */
|
||||
if(CURLE_OK == easy->result) {
|
||||
easy->state = CURLM_STATE_DO;
|
||||
@@ -249,15 +278,18 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
break;
|
||||
case CURLM_STATE_DO:
|
||||
/* Do the fetch or put request */
|
||||
easy->result = Curl_do(easy->easy_handle);
|
||||
easy->result = Curl_do(&easy->easy_conn);
|
||||
/* after do, go PERFORM */
|
||||
if(CURLE_OK == easy->result) {
|
||||
easy->state = CURLM_STATE_PERFORM;
|
||||
if(CURLE_OK == Curl_readwrite_init(easy->easy_conn)) {
|
||||
easy->state = CURLM_STATE_PERFORM;
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_PERFORM:
|
||||
/* read/write data if it is ready to do so */
|
||||
easy->result = Curl_readwrite(easy->easy_handle, &done);
|
||||
easy->result = Curl_readwrite(easy->easy_conn, &done);
|
||||
/* hm, when we follow redirects, we may need to go back to the CONNECT
|
||||
state */
|
||||
/* after the transfer is done, go DONE */
|
||||
@@ -265,11 +297,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
/* call this even if the readwrite function returned error */
|
||||
easy->result = Curl_posttransfer(easy->easy_handle);
|
||||
easy->state = CURLM_STATE_DONE;
|
||||
result = CURLM_CALL_MULTI_PERFORM;
|
||||
}
|
||||
break;
|
||||
case CURLM_STATE_DONE:
|
||||
/* post-transfer command */
|
||||
easy->result = Curl_done(easy->easy_handle);
|
||||
easy->result = Curl_done(easy->easy_conn);
|
||||
/* after we have DONE what we're supposed to do, go COMPLETED */
|
||||
if(CURLE_OK == easy->result)
|
||||
easy->state = CURLM_STATE_COMPLETED;
|
||||
@@ -280,7 +313,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
/* This node should be delinked from the list now and we should post
|
||||
an information message that we are complete. */
|
||||
break;
|
||||
default:
|
||||
return CURLM_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if((CURLM_STATE_COMPLETED != easy->state) &&
|
||||
(CURLE_OK != easy->result)) {
|
||||
/*
|
||||
@@ -289,10 +325,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
|
||||
*/
|
||||
easy->state = CURLM_STATE_COMPLETED;
|
||||
}
|
||||
else if(CURLM_STATE_COMPLETED != easy->state)
|
||||
/* this one still lives! */
|
||||
(*running_handles)++;
|
||||
|
||||
easy = easy->next; /* operate on next handle */
|
||||
}
|
||||
return CURLM_OK;
|
||||
return result;
|
||||
}
|
||||
|
||||
CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
@@ -300,7 +339,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
|
||||
if(GOOD_MULTI_HANDLE(multi)) {
|
||||
multi->type = 0; /* not good anymore */
|
||||
|
||||
curl_hash_destroy(multi->hostcache);
|
||||
/* remove all easy handles */
|
||||
|
||||
free(multi);
|
||||
@@ -313,3 +352,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
|
||||
|
||||
CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue);
|
||||
|
||||
/*
|
||||
* local variables:
|
||||
* eval: (load-file "../curl-mode.el")
|
||||
* end:
|
||||
* vim600: fdm=marker
|
||||
* vim: et sw=2 ts=2 sts=2 tw=78
|
||||
*/
|
||||
|
@@ -44,13 +44,17 @@
|
||||
o Enable the application to select() on its own file descriptors and curl's
|
||||
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
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
#include <curl/types.h>
|
||||
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
|
||||
#include <winsock.h>
|
||||
#endif
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
typedef void CURLM;
|
||||
|
||||
@@ -60,6 +64,7 @@ typedef enum {
|
||||
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
|
||||
CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
|
||||
CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
|
||||
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
|
||||
CURLM_LAST
|
||||
} CURLMcode;
|
||||
|
||||
|
@@ -157,7 +157,7 @@ int Curl_parsenetrc(char *host,
|
||||
}
|
||||
else if(state_password) {
|
||||
strncpy(password, tok, PASSWORDSIZE-1);
|
||||
#if _NETRC_DEBUG
|
||||
#ifdef _NETRC_DEBUG
|
||||
printf("PASSWORD: %s\n", password);
|
||||
#endif
|
||||
state_password=0;
|
||||
|
101
lib/sendf.c
101
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
|
||||
* dual-licensed under the MPL and the MIT/X-derivate licenses.
|
||||
@@ -26,6 +26,8 @@
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
@@ -160,7 +162,7 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
struct SessionHandle *data = conn->data;
|
||||
size_t bytes_written;
|
||||
ssize_t bytes_written;
|
||||
CURLcode result;
|
||||
char *s;
|
||||
va_list ap;
|
||||
@@ -187,26 +189,32 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
|
||||
*/
|
||||
CURLcode Curl_write(struct connectdata *conn, int sockfd,
|
||||
void *mem, size_t len,
|
||||
size_t *written)
|
||||
ssize_t *written)
|
||||
{
|
||||
size_t bytes_written;
|
||||
ssize_t bytes_written;
|
||||
|
||||
#ifdef USE_SSLEAY
|
||||
/* SSL_write() is said to return 'int' while write() and send() returns
|
||||
'size_t' */
|
||||
int ssl_bytes;
|
||||
if (conn->ssl.use) {
|
||||
int loop=100; /* just a precaution to never loop endlessly */
|
||||
while(loop--) {
|
||||
ssl_bytes = SSL_write(conn->ssl.handle, mem, len);
|
||||
if((0 >= ssl_bytes) ||
|
||||
(SSL_ERROR_WANT_WRITE != SSL_get_error(conn->ssl.handle,
|
||||
ssl_bytes) )) {
|
||||
/* this converts from signed to unsigned... */
|
||||
bytes_written = ssl_bytes;
|
||||
break;
|
||||
int err;
|
||||
int rc = SSL_write(conn->ssl.handle, mem, len);
|
||||
|
||||
if(rc < 0) {
|
||||
err = SSL_get_error(conn->ssl.handle, rc);
|
||||
|
||||
switch(err) {
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* this is basicly the EWOULDBLOCK equivalent */
|
||||
*written = 0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
/* a true error */
|
||||
failf(conn->data, "SSL_write() return error %d\n", err);
|
||||
return CURLE_WRITE_ERROR;
|
||||
}
|
||||
bytes_written = rc;
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
@@ -216,13 +224,27 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd,
|
||||
}
|
||||
else
|
||||
#endif /* KRB4 */
|
||||
{
|
||||
bytes_written = swrite(sockfd, mem, len);
|
||||
}
|
||||
if(-1 == bytes_written) {
|
||||
#ifdef WIN32
|
||||
if(WSAEWOULDBLOCK == GetLastError())
|
||||
#else
|
||||
if(EWOULDBLOCK == errno)
|
||||
#endif
|
||||
{
|
||||
/* this is just a case of EWOULDBLOCK */
|
||||
*written=0;
|
||||
return CURLE_OK;
|
||||
}
|
||||
}
|
||||
#ifdef USE_SSLEAY
|
||||
}
|
||||
#endif
|
||||
|
||||
*written = bytes_written;
|
||||
return (bytes_written==len)?CURLE_OK:CURLE_WRITE_ERROR;
|
||||
return (-1 != bytes_written)?CURLE_OK:CURLE_WRITE_ERROR;
|
||||
}
|
||||
|
||||
/* client_write() sends data to the write callback(s)
|
||||
@@ -266,26 +288,47 @@ CURLcode Curl_client_write(struct SessionHandle *data,
|
||||
return CURLE_OK;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Internal read-from-socket function. This is meant to deal with plain
|
||||
* sockets, SSL sockets and kerberos sockets.
|
||||
*
|
||||
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
|
||||
* a regular CURLcode value.
|
||||
*/
|
||||
CURLcode Curl_read(struct connectdata *conn, int sockfd,
|
||||
char *buf, size_t buffersize,
|
||||
ssize_t *n)
|
||||
int Curl_read(struct connectdata *conn,
|
||||
int sockfd,
|
||||
char *buf,
|
||||
size_t buffersize,
|
||||
ssize_t *n)
|
||||
{
|
||||
ssize_t nread;
|
||||
|
||||
#ifdef USE_SSLEAY
|
||||
if (conn->ssl.use) {
|
||||
int loop=100; /* just a precaution to never loop endlessly */
|
||||
while(loop--) {
|
||||
bool loop=TRUE;
|
||||
int err;
|
||||
do {
|
||||
nread = SSL_read(conn->ssl.handle, buf, buffersize);
|
||||
if((-1 != nread) ||
|
||||
(SSL_ERROR_WANT_READ != SSL_get_error(conn->ssl.handle, nread) ))
|
||||
|
||||
if(nread >= 0)
|
||||
/* successful read */
|
||||
break;
|
||||
}
|
||||
|
||||
err = SSL_get_error(conn->ssl.handle, nread);
|
||||
|
||||
switch(err) {
|
||||
case SSL_ERROR_NONE: /* this is not an error */
|
||||
case SSL_ERROR_ZERO_RETURN: /* no more data */
|
||||
loop=0; /* get out of loop */
|
||||
break;
|
||||
case SSL_ERROR_WANT_READ:
|
||||
case SSL_ERROR_WANT_WRITE:
|
||||
/* if there's data pending, then we re-invoke SSL_read() */
|
||||
break;
|
||||
}
|
||||
} while(loop);
|
||||
if(loop && SSL_pending(conn->ssl.handle))
|
||||
return -1; /* basicly EWOULDBLOCK */
|
||||
}
|
||||
else {
|
||||
#endif
|
||||
@@ -295,6 +338,16 @@ CURLcode Curl_read(struct connectdata *conn, int sockfd,
|
||||
else
|
||||
#endif
|
||||
nread = sread (sockfd, buf, buffersize);
|
||||
|
||||
if(-1 == nread) {
|
||||
#ifdef WIN32
|
||||
if(WSAEWOULDBLOCK == GetLastError())
|
||||
#else
|
||||
if(EWOULDBLOCK == errno)
|
||||
#endif
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef USE_SSLEAY
|
||||
}
|
||||
#endif /* USE_SSLEAY */
|
||||
|
@@ -45,12 +45,12 @@ CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr,
|
||||
size_t len);
|
||||
|
||||
/* internal read-function, does plain socket, SSL and krb4 */
|
||||
CURLcode Curl_read(struct connectdata *conn, int sockfd,
|
||||
char *buf, size_t buffersize,
|
||||
ssize_t *n);
|
||||
int Curl_read(struct connectdata *conn, int sockfd,
|
||||
char *buf, size_t buffersize,
|
||||
ssize_t *n);
|
||||
/* internal write-function, does plain socket, SSL and krb4 */
|
||||
CURLcode Curl_write(struct connectdata *conn, int sockfd,
|
||||
void *mem, size_t len,
|
||||
size_t *written);
|
||||
ssize_t *written);
|
||||
|
||||
#endif
|
||||
|
15
lib/setup.h
15
lib/setup.h
@@ -34,25 +34,25 @@
|
||||
#ifdef HAVE_CONFIG_H
|
||||
|
||||
#ifdef VMS
|
||||
#include "../config-vms.h"
|
||||
#include "config-vms.h"
|
||||
#else
|
||||
#include "../config.h" /* the configure script results */
|
||||
#include "config.h" /* the configure script results */
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef WIN32
|
||||
/* hand-modified win32 config.h! */
|
||||
#include "../config-win32.h"
|
||||
#include "config-win32.h"
|
||||
#endif
|
||||
#ifdef macintosh
|
||||
/* hand-modified MacOS config.h! */
|
||||
#include "../config-mac.h"
|
||||
#include "config-mac.h"
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef __cplusplus /* (rabe) */
|
||||
typedef char bool;
|
||||
typedef unsigned char bool;
|
||||
#define typedef_bool
|
||||
#endif /* (rabe) */
|
||||
|
||||
@@ -94,11 +94,12 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
|
||||
#ifdef VMS
|
||||
#include "../include/curl/stdcheaders.h"
|
||||
#else
|
||||
#include "curl/stdcheaders.h"
|
||||
#include <curl/stdcheaders.h>
|
||||
#endif
|
||||
|
||||
#else
|
||||
#ifdef _AIX
|
||||
#include "curl/stdcheaders.h"
|
||||
#include <curl/stdcheaders.h>
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user