Compare commits

...

72 Commits

Author SHA1 Message Date
Daniel Stenberg
7e16ec8724 7.9.3 2002-01-23 18:10:00 +00:00
Daniel Stenberg
8c459156f8 7.9.3 public 2002-01-23 18:01:16 +00:00
Daniel Stenberg
2db894807b Andrs Garca found out that we didn't properly stop reading from a connection
after the headers on a HEAD request. This bug has been added in 7.9.3 and was
mnot present earlier.
2002-01-23 07:15:32 +00:00
Daniel Stenberg
95ceeb6e0b more about passwords and started about proxies 2002-01-22 13:41:00 +00:00
Daniel Stenberg
c9c00d2a23 verify big files 2002-01-22 13:10:16 +00:00
Daniel Stenberg
1afe49864d minor edit 2002-01-22 08:22:04 +00:00
Daniel Stenberg
6924bee3a0 added --cc description and an example 2002-01-21 14:57:07 +00:00
Daniel Stenberg
39d4552dab pre4 2002-01-21 12:11:45 +00:00
Daniel Stenberg
a23c63738f HTTP POST explained 2002-01-21 10:54:56 +00:00
Daniel Stenberg
e911945c55 #505514, as correctly pointed out by Antonio (anton@concord.ru), trying to
post a non-existing file should include nothing, not an error text!
2002-01-19 11:08:05 +00:00
Daniel Stenberg
6d58d13710 mingw fix, mac os x fix, long long check removed from configure,
--enable-debug uses even stricter options now
2002-01-18 15:16:08 +00:00
Daniel Stenberg
0b177cb165 newly generated 2002-01-18 15:14:35 +00:00
Daniel Stenberg
3e31b619de added more text in the 'passwords' section 2002-01-18 15:08:32 +00:00
Daniel Stenberg
f925979b2f satisfy gcc -Wundef 2002-01-18 13:10:41 +00:00
Daniel Stenberg
49f7fa82b9 #if [undefined] => #ifdef [undefined] 2002-01-18 13:04:48 +00:00
Daniel Stenberg
e4cd4cf3f3 playing with more strict gcc warnings with --enable-debug 2002-01-18 13:00:13 +00:00
Daniel Stenberg
e74b20926d prevents gcc -Wcast-align from complaining 2002-01-18 12:59:33 +00:00
Daniel Stenberg
a312127c91 made gcc -Wcast-align happy 2002-01-18 12:56:10 +00:00
Daniel Stenberg
1dc5bf4f73 #ifndef and #define magic to prevent compiler warnings when doing #if BLA
where BLA is undefined
2002-01-18 12:53:05 +00:00
Daniel Stenberg
01cfe670c5 updated to 2002 status ;-) 2002-01-18 12:48:36 +00:00
Daniel Stenberg
fd307bfe29 cut off a big piece of comment and added a pointer to the Trio web page
should anyone ever want a good printf() clone
2002-01-18 10:45:03 +00:00
Daniel Stenberg
a00de093a7 commented out the 'long long' and 'long double' checks, as we don't really
use them anyway and they cause warnings in lib/mprint.c
2002-01-18 10:43:55 +00:00
Daniel Stenberg
7bfe853af3 I wish I could type. Anyway, this proved it is a good habit to put the NULL
on the left side of comparisons...
2002-01-18 10:36:25 +00:00
Daniel Stenberg
cbaecca8e9 added typecast for a malloc() return, and added check for NULL 2002-01-18 10:30:51 +00:00
Daniel Stenberg
8edfb370a8 Added #include <errno.h> 2002-01-18 09:25:58 +00:00
Daniel Stenberg
4c08c8f7db Andrs Garca patched. It now checks for EWOULDBLOCK properly on windows
boxes.
2002-01-18 08:03:54 +00:00
Daniel Stenberg
c174680a03 patched by Andrs Garca 2002-01-18 08:03:12 +00:00
Daniel Stenberg
cb5f6e18e6 7.9.3-pre3 2002-01-17 14:34:26 +00:00
Daniel Stenberg
b798e7a5ae correct ssl version, fixed ssl writes, solved time-out disconnect without
text, fixed dns cache problem, made it compile with openssl before 0.9.5
again and extended libcurl-the-guide a bit more
2002-01-17 14:25:49 +00:00
Daniel Stenberg
5deab7ad27 more text added 2002-01-17 14:24:25 +00:00
Daniel Stenberg
12cdfd282d added a comment about this example only works with 7.9.3 and newer libs 2002-01-17 13:45:19 +00:00
Daniel Stenberg
eba8035e12 Richard Archer made it compile and build with OpenSSL versions prior to
0.9.5
2002-01-17 10:40:13 +00:00
Daniel Stenberg
edcbf4350b include our own sprintf() prototype to make it return sensible data on
all platforms, I also edited a few data types slightly to prevent my
compiler from warning on comparisions between signed and unsigned values
2002-01-17 08:03:48 +00:00
Sterling Hughes
9289ea471f Get this working, still need to check for leaks and such, but should be
fine..
2002-01-17 07:38:25 +00:00
Sterling Hughes
7d06185aa6 Make the keys for hostcache entries be in the format::
host:port, so accessing curl.haxx.se on port 80 would yield a key value
of ::
curl.haxx.se:80
2002-01-17 06:55:37 +00:00
Daniel Stenberg
01ecb1d7e7 filled-in text in the "Building" chapter and added a "libcurl with C++"
chapter
2002-01-17 00:27:56 +00:00
Daniel Stenberg
e177f14595 SSL writes passed back a silly length... 2002-01-16 23:28:58 +00:00
Daniel Stenberg
5c6eddcadd fixed time-out returned without error text set 2002-01-16 22:26:01 +00:00
Daniel Stenberg
b3b4786990 Kevin Roth's SSLeay() patch, slight edited by me. Works with OpenSSL 0.9.5
now.
2002-01-16 17:45:08 +00:00
Daniel Stenberg
fbe2907599 7.9.3-pre2 2002-01-16 15:12:12 +00:00
Daniel Stenberg
343da8d4b3 --cc and working non-blocking sockets uploads 2002-01-16 15:04:37 +00:00
Daniel Stenberg
8d97792dbc - shrunk the BUFSIZE define from 50K to 20K
- made a separate buffer for uploads (due to the non-blocking stuff)
- added two connectdata struct fields for non-blocking uploads
2002-01-16 14:53:19 +00:00
Daniel Stenberg
8d07c87be7 modified to deal with the new non-blocking versions of Curl_read() and
Curl_write().
2002-01-16 14:50:53 +00:00
Daniel Stenberg
ed21701df3 Curl_write's 5th argument now is signed 2002-01-16 14:49:51 +00:00
Daniel Stenberg
df01507582 Curl_read() and Curl_write() are both now adjusted to return properly in
cases where EWOULDBLOCK or equivalent is returned. We must not block.
2002-01-16 14:49:08 +00:00
Daniel Stenberg
f2bda5fd5b Curl_write() now takes a different 5th argument 2002-01-16 14:47:50 +00:00
Daniel Stenberg
cba9838e8f Somewhat ugly fix to deal with non-blocking sockets. We just loop and try
again. THIS IS NOT A NICE FIX.
2002-01-16 14:47:00 +00:00
Daniel Stenberg
b6dba9f5dd Somewhat ugly fix to deal with non-blocking sockets. We just loop and try
again. THIS IS NOT A NICE FIX. We should/must make a select() then and only
retry when we can write to the socket again.
2002-01-16 14:46:00 +00:00
Daniel Stenberg
6e9d1617c6 added support for --cc to output the compiler name. This makes it possible
to compile libcurl stuff without any prior knowledge:

cc=`curl-config --cc`
cflags=`curl-config --cflags`
libs=`curl-config --libs`

$cc $flags $libs -o example example.c

Or if you prefer, the oh-so-cool single-line version:

`curl-config --cc --cflags --libs` -o example example.c
2002-01-16 14:20:06 +00:00
Daniel Stenberg
ea811fee52 added a somewhat cool single-line command that builds most example sources
on unix-like systems
2002-01-16 14:13:54 +00:00
Daniel Stenberg
7391fd8f6a initial attempt to write a tutorial-like libcurl guide 2002-01-15 08:22:00 +00:00
Daniel Stenberg
6c00c58f2a fixed non-blocking reads, fixed ssl sessions, in_addr_t and more non-blocking 2002-01-14 23:32:57 +00:00
Daniel Stenberg
4931fbce49 Curl_read() now returns a negative return code if EWOULDBLOCK or similar 2002-01-14 23:14:59 +00:00
Daniel Stenberg
fefc7ea600 a memory leak when name lookup failed is now removed 2002-01-14 23:14:24 +00:00
Daniel Stenberg
d220389647 Stoned Elipot's patch for the in_addr_t test 2002-01-14 07:53:09 +00:00
Sterling Hughes
a1f910c159 Remove erreaneous include, setup.h is included one line above 2002-01-14 05:36:28 +00:00
Daniel Stenberg
e4866563de Gtz Babin-Ebell updated with some new 7.9.3 features 2002-01-13 11:32:36 +00:00
Daniel Stenberg
47f45aa229 Gtz Babin-Ebell provided some documantation for the ENGINE stuff 2002-01-13 11:32:05 +00:00
Daniel Stenberg
affe334675 added http-post.c 2002-01-10 09:00:02 +00:00
Daniel Stenberg
ee7e184e26 slightly extended to mention that -v and -i are good options to use when
reporting bugs
2002-01-10 07:38:53 +00:00
Daniel Stenberg
bec0ebacf1 bad comment begone 2002-01-09 13:23:01 +00:00
Daniel Stenberg
5bd6d631c6 cut off argc and argv as well 2002-01-09 13:22:31 +00:00
Daniel Stenberg
fd1799f3bb Cleaned up this example to make it even simpler. 2002-01-09 13:22:03 +00:00
Daniel Stenberg
d84a0c51e0 Cris Bailiff found out that when the SSL session cache was filled, libcurl
would crash. This corrects the problem.
2002-01-09 09:38:37 +00:00
Daniel Stenberg
d9a7c7de51 David Bentham's updated QNX notification 2002-01-08 23:27:42 +00:00
Daniel Stenberg
d57e09889a added a missing failf() before returning an error code 2002-01-08 23:23:24 +00:00
Daniel Stenberg
eecb86bfb0 this seems to correct the SSL reading problem introduced when switching
over to non-blocking sockets, but this loops very nastily. We should return
back to the select() and wait there until more data arrives, not just blindly
attempt again and again...
2002-01-08 23:19:32 +00:00
Daniel Stenberg
0b1197936c I made the write callback create the file the first time it gets called so
that it won't create an empty file if the remote file doesn't exist
2002-01-08 13:05:44 +00:00
Daniel Stenberg
b545ac6391 test case 38 added a few new requirements 2002-01-08 09:32:41 +00:00
Daniel Stenberg
a922132e4a updated 2002-01-08 09:32:21 +00:00
Daniel Stenberg
9474e8d6d2 added some tracability 2002-01-08 09:32:10 +00:00
Daniel Stenberg
6328428568 test case 38, try a HTTP download resume without the server supporting
ranges
2002-01-08 09:31:40 +00:00
44 changed files with 1431 additions and 351 deletions

93
CHANGES
View File

@@ -6,6 +6,99 @@
History of Changes
Version 7.9.3
Daniel (23 January 2002)
- Andr<64>s Garc<72>a found a persistancy problem when doing HTTP HEAD, that made
curl "hang" until the connection was closed by the server. This problem has
been introduced in 7.9.3 due to internal rewrites, this was not present in
7.9.2.
Version 7.9.3-pre4
Daniel (19 January 2002)
- Antonio filed bug report #505514 and provided a fix! When doing multipart
formposts, libcurl would include an error text in the actual post if a
specified file wasn't found. This is not libcurl's job. Instead we add an
empty part.
Daniel (18 January 2002)
- Played around with stricter compiler warnings for gcc (when ./configure
--enable-debug is used) and changed some minor things to stop the warnings.
- Commented out the 'long long' and 'long double' checks in configure.in, as
we don't currently use them anyway and the code in lib/mprintf.c that use
them causes warnings.
- Saul Good and jonatan pointed out Mac OS X build problems with pre3 and how
to correct them. Two compiler warnings were removed as well.
- Andr<64>s Garc<72>a fixed two minor mingw32 building problems.
Version 7.9.3-pre3
Daniel (17 January 2002)
- docs/libcurl-the-guide is a new tutorial for our libcurl programming
friends.
- Richard Archer brought back the ability to compile and build with OpenSSL
versions before 0.9.5.
[http://sourceforge.net/tracker/?func=detail&atid=100976&aid=504163&group_id=976]
- The DNS cache code didn't take the port number into account, which made it
work rather bad on IPv6-enabled hosts (especially when doing passive
FTP). Sterling fixed it.
Daniel (16 January 2002)
- Georg Horn could make a transfer time-out without error text. I found it and
corrected it.
- SSL writes didn't work, they return an uninitialized value that caused
havoc all over. Georg Horn experienced this.
- Kevin Roth patched the curl_version() function to use the proper OpenSSL
function for version information. This way, curl will report the version of
the SSL library actually running right now, not the one that had its headers
installed when libcurl was built. Mainly intersting when running with shared
OpenSSL libraries.
Version 7.9.3-pre2
Daniel (16 January 2002)
- Mofied the main transfer loop and related stuff to deal with non-blocking
sockets in the upload section. While doing this, I've now separated the
connection oriented buffers to have one for downloads and one for uploads
(as two can happen simultaneously). I also shrunk the buffers to 20K
each. As we have a scratch buffer twice the size of the upload buffer, we
arrived at 80K for buffers compared with the previous 150K.
- Added the --cc option to curl-config command as it enables so very cool
one-liners. Have a go a this one, building the simple.c example:
$ `curl-config --cc --cflags --libs` -o example simple.c
Daniel (14 January 2002)
- I made all socket reads (recv) handle EWOULDBLOCK. I hope nicely. Now we
only need to address all writes (send) too and then I'm ready for another
pre-release...
- Stoned Elipot patched the in_addr_t configure test to make it work better on
more platforms.
Daniel (9 January 2002)
- Cris Bailiff found out that filling up curl's SSL session cache caused a
crash!
- Posted the curl questionnaire on the web site. If you haven't posted your
opinions there yet, go there and do it now while it is still there:
http://curl.haxx.se/q/
- Georg Horn quickly found out that the SSL reading no longer worked as
supposed since the switch to non-blocking sockets. I've made a quick patch
(for reading only) but we should improve it even further.
Version 7.9.3-pre1
Daniel (7 January 2002)
- I made the 'bool' typedef use an "unsigned char". It makes it the same on

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -326,19 +326,15 @@ QNX
===
(This section was graciously brought to us by David Bentham)
By setting FD_SETSIZE early in connect.c we override the QNX default value
and thus avoid a crash.
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.
Fortunately in the QNX headers its defined as
#ifndef FD_SETSIZE
#define FD_SETSIZE 32
#endif
so its relatively easy to override without changing the original
definition. QNX claim posix compliance so this definition style could be
standard in other o/s's. Eg Microsoft Visual C++ 6 defines it similarly,
but its set to 64.
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
=============

View File

@@ -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, 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,11 +74,7 @@ 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
@@ -83,34 +99,53 @@ 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
* 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.
* 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 +154,10 @@ 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.
TEST SUITE

View File

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

View File

@@ -319,13 +319,54 @@ 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".
.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.
.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".
\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.
.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.
\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.
\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.

View File

@@ -7,7 +7,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit.c postit2.c \
win32sockets.c persistant.c ftpget.c Makefile.example \
multithread.c getinmemory.c ftpupload.c httpput.c \
simplessl.c ftpgetresp.c
simplessl.c ftpgetresp.c http-post.c
all:
@echo "done"

View File

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

View File

@@ -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;
/* local file name to store the file as */
ftpfile = fopen("curl.tar.gz", "wb"); /* b is binary for win */
struct FtpFile ftpfile={
"curl.tar.gz", /* name to store the file as if succesful */
NULL
};
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;
}

35
docs/examples/http-post.c Normal file
View 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;
}

View File

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

View File

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

529
docs/libcurl-the-guide Normal file
View File

@@ -0,0 +1,529 @@
$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/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 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. 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 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? 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);
The multipart formposts are a chain of parts using MIME-style separators and
headers. That means that each of these separate parts get a few headers set
that describes its individual content-type, size etc. Now, to enable your
application to handicraft this formpost even more, libcurl allows you to
supply your own custom headers to an individual form part. You can of course
supply headers to as many parts you like, but this little example will show
how you have set headers to one specific part when you add that to 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 */
Showing Progress
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.
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");
[ environment variables, SSL, tunneling, automatic proxy config (.pac) ]
Security Considerations
[ ps output, netrc plain text, plain text protocols / base64 ]
Certificates and Other SSL Tricks
Future
-----
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.

View File

@@ -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>
@@ -613,7 +613,7 @@ CURLcode curl_global_init(long flags);
void curl_global_cleanup(void);
/* This is the version number */
#define LIBCURL_VERSION "7.9.3-pre1"
#define LIBCURL_VERSION "7.9.3"
#define LIBCURL_VERSION_NUM 0x070903
/* linked-list structure for the CURLOPT_QUOTE option (and other) */

View File

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

View File

@@ -369,9 +369,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

View File

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

View File

@@ -267,9 +267,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)
;
@@ -351,7 +358,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) {
@@ -904,7 +911,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);
@@ -2051,9 +2058,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);
@@ -2067,9 +2076,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;
}
/***********************************************************************

View File

@@ -45,6 +45,11 @@
# endif
#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
itself, there is no need to #define static in this file. Even if
the code were included in the Emacs executable, it probably
@@ -223,7 +228,7 @@ static int yyRelSeconds;
static int yyRelYear;
#line 206 "getdate.y"
#line 211 "getdate.y"
typedef union {
int Number;
enum _MERIDIAN Meridian;
@@ -306,11 +311,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
227, 228, 231, 234, 237, 240, 243, 246, 249, 255,
261, 270, 276, 288, 291, 294, 300, 304, 308, 314,
318, 336, 342, 348, 352, 357, 361, 368, 376, 379,
382, 385, 388, 391, 394, 397, 400, 403, 406, 409,
412, 415, 418, 421, 424, 427, 430, 435, 468, 472
};
#endif
@@ -934,37 +939,37 @@ yyreduce:
switch (yyn) {
case 3:
#line 226 "getdate.y"
#line 231 "getdate.y"
{
yyHaveTime++;
;
break;}
case 4:
#line 229 "getdate.y"
#line 234 "getdate.y"
{
yyHaveZone++;
;
break;}
case 5:
#line 232 "getdate.y"
#line 237 "getdate.y"
{
yyHaveDate++;
;
break;}
case 6:
#line 235 "getdate.y"
#line 240 "getdate.y"
{
yyHaveDay++;
;
break;}
case 7:
#line 238 "getdate.y"
#line 243 "getdate.y"
{
yyHaveRel++;
;
break;}
case 9:
#line 244 "getdate.y"
#line 249 "getdate.y"
{
yyHour = yyvsp[-1].Number;
yyMinutes = 0;
@@ -973,7 +978,7 @@ case 9:
;
break;}
case 10:
#line 250 "getdate.y"
#line 255 "getdate.y"
{
yyHour = yyvsp[-3].Number;
yyMinutes = yyvsp[-1].Number;
@@ -982,7 +987,7 @@ case 10:
;
break;}
case 11:
#line 256 "getdate.y"
#line 261 "getdate.y"
{
yyHour = yyvsp[-3].Number;
yyMinutes = yyvsp[-1].Number;
@@ -994,7 +999,7 @@ case 11:
;
break;}
case 12:
#line 265 "getdate.y"
#line 270 "getdate.y"
{
yyHour = yyvsp[-5].Number;
yyMinutes = yyvsp[-3].Number;
@@ -1003,7 +1008,7 @@ case 12:
;
break;}
case 13:
#line 271 "getdate.y"
#line 276 "getdate.y"
{
yyHour = yyvsp[-5].Number;
yyMinutes = yyvsp[-3].Number;
@@ -1016,53 +1021,53 @@ case 13:
;
break;}
case 14:
#line 283 "getdate.y"
#line 288 "getdate.y"
{
yyTimezone = yyvsp[0].Number;
;
break;}
case 15:
#line 286 "getdate.y"
#line 291 "getdate.y"
{
yyTimezone = yyvsp[0].Number - 60;
;
break;}
case 16:
#line 290 "getdate.y"
#line 295 "getdate.y"
{
yyTimezone = yyvsp[-1].Number - 60;
;
break;}
case 17:
#line 295 "getdate.y"
#line 300 "getdate.y"
{
yyDayOrdinal = 1;
yyDayNumber = yyvsp[0].Number;
;
break;}
case 18:
#line 299 "getdate.y"
#line 304 "getdate.y"
{
yyDayOrdinal = 1;
yyDayNumber = yyvsp[-1].Number;
;
break;}
case 19:
#line 303 "getdate.y"
#line 308 "getdate.y"
{
yyDayOrdinal = yyvsp[-1].Number;
yyDayNumber = yyvsp[0].Number;
;
break;}
case 20:
#line 309 "getdate.y"
#line 314 "getdate.y"
{
yyMonth = yyvsp[-2].Number;
yyDay = yyvsp[0].Number;
;
break;}
case 21:
#line 313 "getdate.y"
#line 318 "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
@@ -1083,7 +1088,7 @@ case 21:
;
break;}
case 22:
#line 331 "getdate.y"
#line 336 "getdate.y"
{
/* ISO 8601 format. yyyy-mm-dd. */
yyYear = yyvsp[-2].Number;
@@ -1092,7 +1097,7 @@ case 22:
;
break;}
case 23:
#line 337 "getdate.y"
#line 342 "getdate.y"
{
/* e.g. 17-JUN-1992. */
yyDay = yyvsp[-2].Number;
@@ -1101,14 +1106,14 @@ case 23:
;
break;}
case 24:
#line 343 "getdate.y"
#line 348 "getdate.y"
{
yyMonth = yyvsp[-1].Number;
yyDay = yyvsp[0].Number;
;
break;}
case 25:
#line 347 "getdate.y"
#line 352 "getdate.y"
{
yyMonth = yyvsp[-3].Number;
yyDay = yyvsp[-2].Number;
@@ -1116,14 +1121,14 @@ case 25:
;
break;}
case 26:
#line 352 "getdate.y"
#line 357 "getdate.y"
{
yyMonth = yyvsp[0].Number;
yyDay = yyvsp[-1].Number;
;
break;}
case 27:
#line 356 "getdate.y"
#line 361 "getdate.y"
{
yyMonth = yyvsp[-1].Number;
yyDay = yyvsp[-2].Number;
@@ -1131,7 +1136,7 @@ case 27:
;
break;}
case 28:
#line 363 "getdate.y"
#line 368 "getdate.y"
{
yyRelSeconds = -yyRelSeconds;
yyRelMinutes = -yyRelMinutes;
@@ -1142,115 +1147,115 @@ case 28:
;
break;}
case 30:
#line 374 "getdate.y"
#line 379 "getdate.y"
{
yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 31:
#line 377 "getdate.y"
#line 382 "getdate.y"
{
yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 32:
#line 380 "getdate.y"
#line 385 "getdate.y"
{
yyRelYear += yyvsp[0].Number;
;
break;}
case 33:
#line 383 "getdate.y"
#line 388 "getdate.y"
{
yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 34:
#line 386 "getdate.y"
#line 391 "getdate.y"
{
yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 35:
#line 389 "getdate.y"
#line 394 "getdate.y"
{
yyRelMonth += yyvsp[0].Number;
;
break;}
case 36:
#line 392 "getdate.y"
#line 397 "getdate.y"
{
yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 37:
#line 395 "getdate.y"
#line 400 "getdate.y"
{
yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 38:
#line 398 "getdate.y"
#line 403 "getdate.y"
{
yyRelDay += yyvsp[0].Number;
;
break;}
case 39:
#line 401 "getdate.y"
#line 406 "getdate.y"
{
yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 40:
#line 404 "getdate.y"
#line 409 "getdate.y"
{
yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 41:
#line 407 "getdate.y"
#line 412 "getdate.y"
{
yyRelHour += yyvsp[0].Number;
;
break;}
case 42:
#line 410 "getdate.y"
#line 415 "getdate.y"
{
yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 43:
#line 413 "getdate.y"
#line 418 "getdate.y"
{
yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 44:
#line 416 "getdate.y"
#line 421 "getdate.y"
{
yyRelMinutes += yyvsp[0].Number;
;
break;}
case 45:
#line 419 "getdate.y"
#line 424 "getdate.y"
{
yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 46:
#line 422 "getdate.y"
#line 427 "getdate.y"
{
yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 47:
#line 425 "getdate.y"
#line 430 "getdate.y"
{
yyRelSeconds += yyvsp[0].Number;
;
break;}
case 48:
#line 431 "getdate.y"
#line 436 "getdate.y"
{
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = yyvsp[0].Number;
@@ -1283,13 +1288,13 @@ case 48:
;
break;}
case 49:
#line 464 "getdate.y"
#line 469 "getdate.y"
{
yyval.Meridian = MER24;
;
break;}
case 50:
#line 468 "getdate.y"
#line 473 "getdate.y"
{
yyval.Meridian = yyvsp[0].Meridian;
;
@@ -1516,7 +1521,7 @@ yyerrhandle:
}
return 1;
}
#line 473 "getdate.y"
#line 478 "getdate.y"
/* Include this file down here because bison inserts code above which
@@ -2126,11 +2131,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
*/

View File

@@ -21,6 +21,11 @@
# endif
#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
itself, there is no need to #define static in this file. Even if
the code were included in the Emacs executable, it probably

View File

@@ -101,7 +101,10 @@ curl_hash_alloc(int slots, curl_hash_dtor dtor)
{
curl_hash *h;
h = malloc(sizeof(curl_hash));
h = (curl_hash *)malloc(sizeof(curl_hash));
if(NULL == h)
return NULL;
curl_hash_init(h, slots, dtor);
return h;

View File

@@ -25,8 +25,6 @@
#include "setup.h"
#include "setup.h"
#include <stddef.h>
#include "llist.h"

View File

@@ -60,6 +60,9 @@
#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"
#endif
@@ -98,13 +101,71 @@ struct curl_dns_cache_entry {
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;
size_t hostname_len;
ssize_t entry_len;
time_t now;
/* If the host cache timeout is 0, we don't do DNS cach'ing
@@ -113,39 +174,47 @@ Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
return Curl_getaddrinfo(data, hostname, port, bufp);
}
hostname_len = strlen(hostname)+1;
/* Create an entry id, based upon the hostname and port */
entry_len = strlen(hostname);
entry_id = _create_hostcache_id(hostname, port, &entry_len);
/* If we can't create the entry id, don't cache, just fall-through
to the plain Curl_getaddrinfo() */
if (!entry_id) {
return Curl_getaddrinfo(data, hostname, port, bufp);
}
time(&now);
/* See if its already in our dns cache */
if (curl_hash_find(data->hostcache, hostname, hostname_len, (void **) &p)) {
if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) {
/* Do we need to check for a cache timeout? */
if (data->set.dns_cache_timeout != -1) {
/* Return if the entry has not timed out */
if ((now - p->timestamp) < data->set.dns_cache_timeout) {
return p->addr;
_hostcache_return(p->addr);
}
}
else {
return p->addr;
_hostcache_return(p->addr);
}
}
/* Create a new cache entry */
p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry));
if (!p) {
return NULL;
_hostcache_return(NULL);
}
p->addr = Curl_getaddrinfo(data, hostname, port, bufp);
if (!p->addr) {
return NULL;
free(p);
_hostcache_return(NULL);
}
p->timestamp = now;
/* Save it in our host cache */
curl_hash_update(data->hostcache, hostname, hostname_len, (const void *) p);
curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p);
return p->addr;
_hostcache_return(p->addr);
}
/*
@@ -357,10 +426,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 */
@@ -390,7 +459,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

View File

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

View File

@@ -46,7 +46,10 @@ curl_llist_alloc(curl_llist_dtor dtor)
{
curl_llist *list;
list = malloc(sizeof(curl_llist));
list = (curl_llist *)malloc(sizeof(curl_llist));
if(NULL == list)
return NULL;
curl_llist_init(list, dtor);
return list;

View File

@@ -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"
@@ -1191,7 +1138,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

View File

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

View File

@@ -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(0);
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 */

View File

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

View File

@@ -43,6 +43,12 @@
#include "memdebug.h"
#endif
#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
#define HAVE_SSL_GET1_SESSION 1
#else
#undef HAVE_SSL_GET1_SESSION
#endif
#if OPENSSL_VERSION_NUMBER >= 0x00904100L
#define HAVE_USERDATA_IN_PWD_CALLBACK 1
#else
@@ -552,23 +558,39 @@ int Curl_SSL_Close_All(struct SessionHandle *data)
static int Store_SSL_Session(struct connectdata *conn)
{
SSL_SESSION *ssl_sessionid;
struct curl_ssl_session *store;
int i;
struct SessionHandle *data=conn->data; /* the mother of all structs */
struct curl_ssl_session *store = &data->state.session[0];
int oldest_age=data->state.session[0].age; /* zero if unused */
/* ask OpenSSL, say please */
#ifdef HAVE_SSL_GET1_SESSION
ssl_sessionid = SSL_get1_session(conn->ssl.handle);
/* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with
SSL_SESSION_free(3), regardless of its state. */
SSL_SESSION_free(3), regardless of its state.
This function was introduced in openssl 0.9.5a. */
#else
ssl_sessionid = SSL_get_session(conn->ssl.handle);
/* if SSL_get1_session() is unavailable, use SSL_get_session().
This is an inferior option because the session can be flushed
at any time by openssl. It is included only so curl compiles
under versions of openssl < 0.9.5a.
WARNING: How curl behaves if it's session is flushed is
untested.
*/
#endif
/* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
/* find an empty slot for us, or find the oldest */
for(i=0; (i<data->set.ssl.numsessions) && data->state.session[i].sessionid; i++) {
for(i=1; (i<data->set.ssl.numsessions) &&
data->state.session[i].sessionid; i++) {
if(data->state.session[i].age < oldest_age) {
oldest_age = data->state.session[i].age;
store = &data->state.session[i];
@@ -783,9 +805,11 @@ Curl_SSLConnect(struct connectdata *conn)
/* 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 */
return CURLE_OPERATION_TIMEOUTED;
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEOUTED;
}
}
else
/* no particular time-out has been set */

View File

@@ -1090,7 +1090,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
{
unsigned char outbuf[2];
int out_count = 0;
size_t bytes_written;
ssize_t bytes_written;
char *buffer = buf;
if(!ReadFile(stdin_handle, buf, 255, &nread, NULL)) {
@@ -1116,6 +1116,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
{
if(events.lNetworkEvents & FD_READ)
{
/* This reallu OUGHT to check its return code. */
Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
telrcv(conn, (unsigned char *)buf, nread);
@@ -1159,7 +1160,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
if(FD_ISSET(0, &readfd)) { /* read from stdin */
unsigned char outbuf[2];
int out_count = 0;
size_t bytes_written;
ssize_t bytes_written;
char *buffer = buf;
nread = read(0, buf, 255);
@@ -1176,6 +1177,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
}
if(FD_ISSET(sockfd, &readfd)) {
/* This OUGHT to check the return code... */
Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
/* if we receive 0 or less here, the server closed the connection and

View File

@@ -173,7 +173,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
{
struct Curl_transfer_keeper *k = &conn->keep;
struct SessionHandle *data = conn->data;
CURLcode result;
int result;
ssize_t nread; /* number of bytes read */
int didwhat=0;
@@ -181,25 +181,28 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if((k->keepon & KEEP_READ) &&
FD_ISSET(conn->sockfd, &k->readfd)) {
if ((k->bytecount == 0) && (k->writebytecount == 0))
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
didwhat |= KEEP_READ;
/* read! */
result = Curl_read(conn, conn->sockfd, k->buf,
BUFSIZE -1, &nread);
if(result)
if(0>result)
break; /* get out of loop */
if(result>0)
return result;
if ((k->bytecount == 0) && (k->writebytecount == 0))
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
didwhat |= KEEP_READ;
/* NULL terminate, allowing string ops to be used */
if (0 < (signed int) nread)
if (0 < nread)
k->buf[nread] = 0;
/* if we receive 0 or less here, the server closed the connection and
we bail out from this! */
else if (0 >= (signed int) nread) {
else if (0 >= nread) {
k->keepon &= ~KEEP_READ;
FD_ZERO(&k->rkeepfd);
break;
@@ -353,10 +356,11 @@ CURLcode Curl_readwrite(struct connectdata *conn,
* If we requested a "no body", this is a good time to get
* out and return home.
*/
if(data->set.no_body)
return CURLE_OK;
bool stop_reading = FALSE;
if(!conn->bits.close) {
if(data->set.no_body)
stop_reading = TRUE;
else if(!conn->bits.close) {
/* If this is not the last request before a close, we must
set the maximum download size to the size of the
expected document or else, we won't know when to stop
@@ -367,10 +371,18 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* If max download size is *zero* (nothing) we already
have nothing and can safely return ok now! */
if(0 == conn->maxdownload)
return CURLE_OK;
stop_reading = TRUE;
/* What to do if the size is *not* known? */
}
if(stop_reading) {
/* we make sure that this socket isn't read more now */
k->keepon &= ~KEEP_READ;
FD_ZERO(&k->rkeepfd);
return CURLE_OK;
}
break; /* exit header line loop */
}
@@ -588,7 +600,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* This is not an 'else if' since it may be a rest from the header
parsing, where the beginning of the buffer is headers and the end
is non-headers. */
if (k->str && !k->header && ((signed int)nread > 0)) {
if (k->str && !k->header && (nread > 0)) {
if(0 == k->bodywrites) {
/* These checks are only made the first time we are about to
@@ -669,7 +681,7 @@ CURLcode Curl_readwrite(struct connectdata *conn,
if((-1 != conn->maxdownload) &&
(k->bytecount + nread >= conn->maxdownload)) {
nread = conn->maxdownload - k->bytecount;
if((signed int)nread < 0 ) /* this should be unusual */
if(nread < 0 ) /* this should be unusual */
nread = 0;
k->keepon &= ~KEEP_READ; /* we're done reading */
@@ -696,53 +708,84 @@ CURLcode Curl_readwrite(struct connectdata *conn,
/* write */
int i, si;
size_t bytes_written;
ssize_t bytes_written;
if ((k->bytecount == 0) && (k->writebytecount == 0))
Curl_pgrsTime(data, TIMER_STARTTRANSFER);
didwhat |= KEEP_WRITE;
nread = data->set.fread(k->buf, 1, conn->upload_bufsize,
data->set.in);
/* only read more data if there's no upload data already
present in the upload buffer */
if(0 == conn->upload_present) {
/* init the "upload from here" pointer */
conn->upload_fromhere = k->uploadbuf;
/* the signed int typecase of nread of for systems that has
unsigned size_t */
if ((signed int)nread<=0) {
/* done */
k->keepon &= ~KEEP_WRITE; /* we're done writing */
FD_ZERO(&k->wkeepfd);
break;
}
k->writebytecount += nread;
Curl_pgrsSetUploadCounter(data, (double)k->writebytecount);
nread = data->set.fread(conn->upload_fromhere, 1,
conn->upload_bufsize,
data->set.in);
/* convert LF to CRLF if so asked */
if (data->set.crlf) {
for(i = 0, si = 0; i < (int)nread; i++, si++) {
if (k->buf[i] == 0x0a) {
data->state.scratch[si++] = 0x0d;
data->state.scratch[si] = 0x0a;
}
else {
data->state.scratch[si] = k->buf[i];
}
/* the signed int typecase of nread of for systems that has
unsigned size_t */
if (nread<=0) {
/* done */
k->keepon &= ~KEEP_WRITE; /* we're done writing */
FD_ZERO(&k->wkeepfd);
break;
}
nread = si;
k->buf = data->state.scratch; /* point to the new buffer */
/* store number of bytes available for upload */
conn->upload_present = nread;
/* convert LF to CRLF if so asked */
if (data->set.crlf) {
for(i = 0, si = 0; i < nread; i++, si++) {
if (k->buf[i] == 0x0a) {
data->state.scratch[si++] = 0x0d;
data->state.scratch[si] = 0x0a;
}
else {
data->state.scratch[si] = k->uploadbuf[i];
}
}
nread = si;
k->buf = data->state.scratch; /* point to the new buffer */
}
}
else {
/* We have a partial buffer left from a previous "round". Use
that instead of reading more data */
}
/* write to socket */
result = Curl_write(conn, conn->writesockfd, k->buf, nread,
result = Curl_write(conn,
conn->writesockfd,
conn->upload_fromhere,
conn->upload_present,
&bytes_written);
if(result)
return result;
else if(nread != (int)bytes_written) {
failf(data, "Failed uploading data");
return CURLE_WRITE_ERROR;
else if(conn->upload_present != bytes_written) {
/* we only wrote a part of the buffer (if anything), deal with it! */
/* store the amount of bytes left in the buffer to write */
conn->upload_present -= bytes_written;
/* advance the pointer where to find the buffer when the next send
is to happen */
conn->upload_fromhere += bytes_written;
}
else if(data->set.crlf)
k->buf = data->state.buffer; /* put it back on the buffer */
else {
/* we've uploaded that buffer now */
conn->upload_fromhere = k->uploadbuf;
conn->upload_present = 0; /* no more bytes left */
}
k->writebytecount += nread;
Curl_pgrsSetUploadCounter(data, (double)k->writebytecount);
}
@@ -835,6 +878,7 @@ CURLcode Curl_readwrite_init(struct connectdata *conn)
data = conn->data; /* there's the root struct */
k->buf = data->state.buffer;
k->uploadbuf = data->state.uploadbuffer;
k->maxfd = (conn->sockfd>conn->writesockfd?
conn->sockfd:conn->writesockfd)+1;
k->hbufp = data->state.headerbuff;

View File

@@ -83,7 +83,7 @@
#include "http_chunks.h" /* for the structs and enum stuff */
/* Download buffer size, keep it fairly big for speed reasons */
#define BUFSIZE (1024*50)
#define BUFSIZE (1024*20)
/* Defaul upload buffer size, keep it smallish to get faster progress meter
updates. This is just default, it is dynamic and adjusts to the upload
@@ -251,6 +251,7 @@ struct Curl_transfer_keeper {
struct SessionHandle *data;
struct connectdata *conn;
char *buf;
char *uploadbuf;
int maxfd;
/* the file descriptors to play with */
@@ -409,6 +410,16 @@ struct connectdata {
/* This struct is inited when needed */
struct Curl_transfer_keeper keep;
/* 'upload_present' is used to keep a byte counter of how much data there is
still left in the buffer, aimed for upload. */
int upload_present;
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
buffer, so the next read should read from where this pointer points to,
and the 'upload_present' contains the number of bytes available at this
position */
char *upload_fromhere;
};
/*
@@ -495,8 +506,8 @@ struct UrlState {
char *headerbuff; /* allocated buffer to store headers in */
int headersize; /* size of the allocation */
char buffer[BUFSIZE+1]; /* buffer with size BUFSIZE */
char buffer[BUFSIZE+1]; /* download buffer */
char uploadbuffer[BUFSIZE+1]; /* upload buffer */
double current_speed; /* the ProgressShow() funcion sets this */
bool this_is_a_follow; /* this is a followed Location: request */

View File

@@ -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.
@@ -38,20 +38,28 @@ char *curl_version(void)
#ifdef USE_SSLEAY
#if (SSLEAY_VERSION_NUMBER >= 0x906000)
#if (SSLEAY_VERSION_NUMBER >= 0x905000)
{
char sub[2];
unsigned long ssleay_value;
sub[1]='\0';
if(SSLEAY_VERSION_NUMBER&0xff0) {
sub[0]=((SSLEAY_VERSION_NUMBER>>4)&0xff) + 'a' -1;
}
else
ssleay_value=SSLeay();
if(ssleay_value < 0x906000) {
ssleay_value=SSLEAY_VERSION_NUMBER;
sub[0]='\0';
}
else {
if(ssleay_value&0xff0) {
sub[0]=((ssleay_value>>4)&0xff) + 'a' -1;
}
else
sub[0]='\0';
}
sprintf(ptr, " (OpenSSL %lx.%lx.%lx%s)",
(SSLEAY_VERSION_NUMBER>>28)&0xf,
(SSLEAY_VERSION_NUMBER>>20)&0xff,
(SSLEAY_VERSION_NUMBER>>12)&0xff,
(ssleay_value>>28)&0xf,
(ssleay_value>>20)&0xff,
(ssleay_value>>12)&0xff,
sub);
}

View File

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

View File

@@ -14,8 +14,10 @@ specified, that will be checked/used if specified. This document includes all
the subsections currently supported.
<reply>
<data>
data to sent to the client on its request
<data [nocheck=1]>
data to sent to the client on its request and later verified that it arrived
safely. Set the nocheck=1 to prevent the test script to verify the arrival
of this data.
</data>
<datacheck>
if the data is sent but this is what should be checked afterwards
@@ -30,16 +32,20 @@ reply is sent
<postcmd>
special purpose server-command to control its behavior *after* the
reply is sent
</oistcmd>
</postcmd>
</reply>
<client>
<name>
test case description
</name>
<command>
<command [option=no-output]>
command line to run, there's a bunch of %variables that get replaced
accordingly. more about them elsewhere
Set 'option=no-output' to prevent the test script to slap on the --output
argument that directs the output to a file. The --output is also not added if
the client/stdout section is used.
</command>
<file name="log/filename">
this creates the named file with this content before the test case is run
@@ -59,6 +65,9 @@ changing protocol data such as port numbers or user-agent strings.
<protocol>
the protocol dump curl should transmit
</protocol>
<stdout>
This verfies that this data was passed to stdout.
</stdout>
<file name="log/filename">
the file's contents must be identical to this
</file>

View File

@@ -13,5 +13,5 @@ test102 test111 test120 test16 test21 test30 test400 test7 \
test103 test112 test121 test17 test22 test300 test401 test8 \
test104 test113 test122 test18 test23 test301 test402 test9 \
test105 test114 test123 test19 test24 test302 test43 \
test106 test115 test124 test190 test25 test303 test44 \
test106 test115 test124 test190 test25 test303 test44 test38 \
test107 test116 test125 test2 test26 test33 test45 test126

49
tests/data/test38 Normal file
View File

@@ -0,0 +1,49 @@
# Server-side
<reply>
<data nocheck=1>
HTTP/1.0 200 Mooo
Date: Mon, 13 Nov 2000 13:41:09 GMT
Server: myown/1.0
Connection: close
todelooooo lalalala yada yada, we know nothing about ranges ;-)
</data>
</reply>
# Client-side
<client>
<name>
HTTP resume request without server supporting it
</name>
<command option="no-output">
http://%HOSTIP:%HOSTPORT/want/38 -C - -i -o log/fewl.txt
</command>
<file name="log/fewl.txt">
This text is here to simulate a partly downloaded file to resume
download on.
</file>
</client>
# Verify data after the test has been "shot"
<verify>
<errorcode>
33
</errorcode>
<strip>
^User-Agent:.*
</strip>
<protocol>
GET /want/38 HTTP/1.1
Range: bytes=78-
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
</protocol>
# the download target file must remain untouched
<file name="log/fewl.txt">
This text is here to simulate a partly downloaded file to resume
download on.
</file>
</verify>

View File

@@ -3,6 +3,9 @@
my @xml;
my $warning=0;
my $trace=0;
sub getpartattr {
my ($section, $part)=@_;
@@ -63,12 +66,21 @@ sub getpart {
$inside--;
}
elsif((1==$inside) && ($_ =~ /^ *\<\/$section/)) {
if($trace) {
print STDERR "*** getpart.pm: $section/$part returned data!\n";
}
if(!@this && $warning) {
print STDERR "*** getpart.pm: $section/$part returned empty!\n";
}
return @this;
}
elsif(2==$inside) {
push @this, $_;
}
}
if($warning) {
print STDERR "*** getpart.pm: $section/$part returned empty!\n";
}
return @this; #empty!
}

View File

@@ -483,9 +483,17 @@ sub singletest {
writearray($filename, \@inputfile);
}
my %cmdhash = getpartattr("client", "command");
my $out="";
if (!@validstdout) {
$out="--output $CURLOUT ";
if($cmdhash{'option'} eq "no-output") {
#print "*** We don't slap on --output\n";
}
else {
if (!@validstdout) {
$out="--output $CURLOUT ";
}
}
# run curl, add -v for debug information output
@@ -832,7 +840,9 @@ if($testthis[0] ne "") {
# Output curl version and host info being tested
#
displaydata();
if(!$listonly) {
displaydata();
}
#######################################################################
# clear and create logging directory: