Compare commits

...

33 Commits

Author SHA1 Message Date
Daniel Stenberg
b4f70aa2c8 version 7.7-beta1 2001-03-08 12:35:51 +00:00
Daniel Stenberg
f54a282ccc persistant adjusts 2001-03-08 12:32:03 +00:00
Daniel Stenberg
2a11bdc216 HTTP HEAD tests 2001-03-08 10:39:36 +00:00
Daniel Stenberg
5cd4c3ed24 return from transfer when all headers have been received and nobody is set,
as is the case when doing HEAD requests
2001-03-08 10:32:27 +00:00
Daniel Stenberg
147a673063 updated for persistant connections 2001-03-08 09:25:09 +00:00
Daniel Stenberg
9ce5827fc1 made it split the version number on - too to make 7.7-blabla make a better
version number define in the header file
2001-03-08 09:23:11 +00:00
Daniel Stenberg
97f1c93674 added lots of numbers for the error codes as they're often printed
and used
2001-03-08 09:04:43 +00:00
Daniel Stenberg
e61ceaf1bd clarified the 0001-files use a bit, I couldn't understand it myself! :-) 2001-03-08 08:33:17 +00:00
Daniel Stenberg
1118612249 Added test #34 - HTTP GET with chunked Transfer-Encoding 2001-03-08 08:30:35 +00:00
Daniel Stenberg
a23db7b7c7 "Transfer-Encoding: chunked" support added 2001-03-07 23:51:41 +00:00
Daniel Stenberg
f6b6dff46a added the http_chunks files 2001-03-07 23:50:00 +00:00
Daniel Stenberg
55b8ceac18 chunked transfer encoding support 2001-03-07 23:28:22 +00:00
Daniel Stenberg
bcf448ee32 connection timeout is in for 7.7 2001-03-07 23:24:23 +00:00
Daniel Stenberg
91e4da7ddb initial chunked transfer-encoding support 2001-03-07 17:12:12 +00:00
Daniel Stenberg
2873c18132 removed compiler warning if HAVE_RAND_STATUS is false 2001-03-07 17:08:20 +00:00
Daniel Stenberg
5dd0a8a63e Added persistant connections blurb even if it doesn't really work yet... 2001-03-06 14:37:37 +00:00
Daniel Stenberg
2103dc41f5 cleaned up for the 7.7 fixes 2001-03-06 12:50:42 +00:00
Daniel Stenberg
2ef13230cb new seeding stuff as mentioned by Albert Chin 2001-03-06 00:04:58 +00:00
Daniel Stenberg
9479ac6dda Added a persistant connection example 2001-03-05 16:56:10 +00:00
Daniel Stenberg
4e878eae79 updated to libcurl 7.7 conditions 2001-03-05 15:51:34 +00:00
Daniel Stenberg
1e8e90a220 mucho updated with new 7.7 concepts 2001-03-05 15:38:06 +00:00
Daniel Stenberg
fe95c7dc34 removed an incorrect comment 2001-03-05 14:52:23 +00:00
Daniel Stenberg
6dae34d5da all test cases run OK now (again) 2001-03-05 14:13:15 +00:00
Daniel Stenberg
36c621c9df more details on debugging with the test suite 2001-03-05 14:08:22 +00:00
Daniel Stenberg
1717963e3d show the ftp server invoke line when -d is used 2001-03-05 14:03:48 +00:00
Daniel Stenberg
4646a1ffa9 talks more on verbose 2001-03-05 14:03:20 +00:00
Daniel Stenberg
0cb4eba002 free the struct on done 2001-03-05 14:01:13 +00:00
Daniel Stenberg
5eba359b5d telnet without any static variables 2001-03-05 13:59:43 +00:00
Daniel Stenberg
07ce7539a8 set download size properly for HTTP downloads 2001-03-05 13:40:31 +00:00
Daniel Stenberg
c21f848c1c enable persistant connections by default 2001-03-05 13:40:08 +00:00
Daniel Stenberg
84e94fda8b remade FILE:// support to look more as the other protocols 2001-03-05 13:39:01 +00:00
Daniel Stenberg
ebd6897b10 runtests -g explained 2001-03-04 18:11:25 +00:00
Daniel Stenberg
5ab8a9d32f persistant support protocol updates 2001-03-04 18:07:13 +00:00
93 changed files with 1185 additions and 489 deletions

21
CHANGES
View File

@@ -6,7 +6,26 @@
History of Changes History of Changes
** curl 7.7 DOES NOT currently WORK. **
Daniel (8 March 2001)
- "Transfer-Encoding: chunked" is no longer any trouble for libcurl. I've
added two source files and I've run some test downloads that look fine.
Daniel (5 March 2001)
- The current 57 test cases now pass OK. It would suggest that libcurl works
using the old-style with one connection per handle. The test suite doesn't
handle multiple connections yet so there are no test cases for this.
- I patched the telnet.c heavily to not use any global variables anymore. It
should make it a lot nicer library-wise.
- The file:// support was modified slightly to use the internal connect-first-
then-do approach.
Daniel (4 March 2001)
- More bugs erased.
Version 7.7-alpha2
Daniel (4 March 2001) Daniel (4 March 2001)
- Now, there's even a basic check that a re-used connection is still alive - Now, there's even a basic check that a re-used connection is still alive

View File

@@ -43,3 +43,8 @@
/* Define this to 'int' if ssize_t is not an available typedefed type */ /* Define this to 'int' if ssize_t is not an available typedefed type */
#undef ssize_t #undef ssize_t
/* Define this as a suitable file to read random data from */
#undef RANDOM_FILE
/* Define this to your Entropy Gathering Daemon socket pathname */
#undef EGD_SOCKET

View File

@@ -391,6 +391,36 @@ AC_CHECK_FUNC(gethostname, , AC_CHECK_LIB(ucb, gethostname))
dnl dl lib? dnl dl lib?
AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen)) AC_CHECK_FUNC(dlopen, , AC_CHECK_LIB(dl, dlopen))
dnl **********************************************************************
dnl Check for the random seed preferences
dnl **********************************************************************
AC_ARG_WITH(egd-socket,
[ --with-egd-socket=FILE Entropy Gathering Daemon socket pathname],
[ EGD_SOCKET="$withval" ]
)
if test -n "$EGD_SOCKET" ; then
AC_DEFINE_UNQUOTED(EGD_SOCKET, "$EGD_SOCKET")
fi
dnl Check for user-specified random device
AC_ARG_WITH(random,
[ --with-random=FILE read randomness from FILE (default=/dev/urandom)],
[ RANDOM_FILE="$withval" ],
[
dnl Check for random device
AC_CHECK_FILE("/dev/urandom",
[
RANDOM_FILE="/dev/urandom";
]
)
]
)
if test -n "$RANDOM_FILE" ; then
AC_SUBST(RANDOM_FILE)
AC_DEFINE_UNQUOTED(RANDOM_FILE, "$RANDOM_FILE")
fi
dnl ********************************************************************** dnl **********************************************************************
dnl Check for the presence of Kerberos4 libraries and headers dnl Check for the presence of Kerberos4 libraries and headers
dnl ********************************************************************** dnl **********************************************************************
@@ -545,7 +575,8 @@ else
dnl these can only exist if openssl exists dnl these can only exist if openssl exists
AC_CHECK_FUNCS( RAND_status \ AC_CHECK_FUNCS( RAND_status \
RAND_screen ) RAND_screen \
RAND_egd )
fi fi

View File

@@ -1,4 +1,4 @@
Updated: February 16, 2001 (http://curl.haxx.se/docs/faq.shtml) Updated: March 6, 2001 (http://curl.haxx.se/docs/faq.shtml)
_ _ ____ _ _ _ ____ _
___| | | | _ \| | ___| | | | _ \| |
/ __| | | | |_) | | / __| | | | |_) | |
@@ -31,7 +31,7 @@ FAQ
3.7 Can I use curl to delete/rename a file through FTP? 3.7 Can I use curl to delete/rename a file through FTP?
3.8 How do I tell curl to follow HTTP redirects? 3.8 How do I tell curl to follow HTTP redirects?
3.9 How do I use curl in PHP? 3.9 How do I use curl in PHP?
3.10 What about SOAP, WEBDAV, XML-RPC or similar protocols over HTTP? 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP?
4. Running Problems 4. Running Problems
4.1 Problems connecting to SSL servers. 4.1 Problems connecting to SSL servers.
@@ -292,7 +292,7 @@ FAQ
invoke the curl tool using a command line. This is the way to use curl if invoke the curl tool using a command line. This is the way to use curl if
you're using PHP3 or PHP4 built without curl module support. you're using PHP3 or PHP4 built without curl module support.
3.10 What about SOAP, WEBDAV, XML-RPC or similar protocols over HTTP? 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP?
Curl adheres to the HTTP spec, which basically means you can play with *any* Curl adheres to the HTTP spec, which basically means you can play with *any*
protocol that is built ontop of HTTP. Protocols such as SOAP, WEBDAV and protocol that is built ontop of HTTP. Protocols such as SOAP, WEBDAV and
@@ -486,6 +486,9 @@ FAQ
5.3 How do I fetch multiple files with libcurl? 5.3 How do I fetch multiple files with libcurl?
Starting with version 7.7, curl and libcurl will have excellent support for
transferring multiple files.
The easy interface of libcurl does not support multiple requests using the The easy interface of libcurl does not support multiple requests using the
same connection. The only available way to do multiple requests is to same connection. The only available way to do multiple requests is to
init/perform/cleanup for each request. init/perform/cleanup for each request.
@@ -512,6 +515,9 @@ FAQ
5.6 What about Keep-Alive or persistant connections? 5.6 What about Keep-Alive or persistant connections?
Starting with version 7.7, curl and libcurl will have excellent support for
persistant connections when transferring several files from the same server.
This is closely related to issue 5.3. Since libcurl has no real support This is closely related to issue 5.3. Since libcurl has no real support
for doing multiple file transfers, there's no support for Keep-Alive or for doing multiple file transfers, there's no support for Keep-Alive or
persistant connections either. persistant connections either.

View File

@@ -4,58 +4,84 @@
| | | |_) | (__| |_| | | | | | | | |_) | (__| |_| | | | |
|_|_|_.__/ \___|\__,_|_| |_| |_|_|_.__/ \___|\__,_|_| |_|
How To Use Libcurl In Your C/C++ Program
How To Use Libcurl In Your Program [ libcurl can be used directly from within your PHP or Perl programs as well,
look elsewhere for documentation on this ]
Interfaces The interface is meant to be very simple for applictions/programmers, hence
the name "easy". We have therefore minimized the number of entries.
libcurl currently offers two different interfaces to the URL transfer
engine. They can be seen as one low-level and one high-level, in the sense
that the low-level one will allow you to deal with a lot more details but on
the other hand not offer as many fancy features (such as Location:
following). The high-level interface is supposed to be a built-in
implementation of the low-level interface. You will not be able to mix
function calls from the different layers.
As we currently ONLY support the high-level interface, the so called easy
interface, I will not attempt to describe any low-level functions at this
point.
Function descriptions
The interface is meant to be very simple for very simple
implementations. Thus, we have minimized the number of entries.
The Easy Interface The Easy Interface
When using the easy interface, you init your easy-session and get a handle, When using the easy interface, you init your session and get a handle, which
which you use as input to the following interface functions you use. you use as input to the following interface functions you use. Use
curl_easy_init() to get the handle.
You continue by setting all the options you want in the upcoming transfer, You continue by setting all the options you want in the upcoming transfer,
most important among them is the URL itself. You might want to set some most important among them is the URL itself (you can't transfer anything
callbacks as well that will be called from the library when data is available without a specified URL as you may have figured out yourself). You might want
etc. to set some callbacks as well that will be called from the library when data
is available etc. curl_easy_setopt() is there for this.
When all is setup, you tell libcurl to perform the transfer. It will then do When all is setup, you tell libcurl to perform the transfer using
the entire operation and won't return until it is done or failed. curl_easy_perform(). It will then do the entire operation and won't return
until it is done or failed.
After the transfer has been made, you cleanup the easy-session's handle and After the transfer has been made, you cleanup the session with
libcurl is entirely off the hook! curl_easy_cleanup() and libcurl is entirely off the hook! If you want
persistant connections, you don't cleanup immediately, but instead run ahead
and perform other transfers. See the chapter below for Persistant
Connections.
curl_easy_init() While the above mentioned four functions are the main functions to use in the
curl_easy_setopt() easy interface, there is a series of other helpful functions to use. They
curl_easy_perform() are:
curl_easy_cleanup()
While the above four functions are the main functions to use in the easy curl_version() - displays the libcurl version
interface, there is a series of helpful functions to use. They are: curl_getdate() - converts a date string to time_t
curl_getenv() - portable environment variable reader
curl_easy_getinfo() - get information about a performed transfer
curl_formparse() - helps building a HTTP form POST
curl_formfree() - free a list built with curl_formparse()
curl_slist_append() - builds a linked list
curl_slist_free_all() - frees a whole curl_slist
curl_version() - displays the libcurl version For details on these, read the separate man pages.
curl_getdate() - converts a date string to time_t
curl_getenv() - portable environment variable reader
curl_formparse() - helps building a HTTP form POST
curl_slist_append() - builds a linked list
curl_slist_free_all() - frees a whole curl_slist
Read the separate man pages for these functions for details! Portability
libcurl works *exactly* the same, on any of the platforms it compiles and
builds on.
There's only one caution, and that is the win32 platform that may(*) require
you to init the winsock stuff before you use the libcurl functions. Details
on this are noted on the curl_easy_init() man page.
(*) = it appears users of the cygwin environment gets this done
automatically.
Persistant Connections
With libcurl 7.7, persistant connections were added. Persistant connections
means that libcurl can re-use the same connection for several transfers, if
the conditions are right.
libcurl will *always* attempt to use persistant connections. Whenever you use
curl_easy_perform(), libcurl will attempt to use an existing connection to do
the transfer, and if none exists it'll open a new one that will be subject
for re-use on a possible following call to curl_easy_perform().
To allow libcurl to take full advantage of persistant connections, you should
do as many of your file transfers as possible using the same curl
handle. When you call curl_easy_cleanup(), all the possibly open connections
held by libcurl will be closed and forgotten.
Note that the options set with curl_easy_setopt() will be used in on every
repeat curl_easy_perform() call
Compatibility with older libcurls
Repeated curl_easy_perform() calls on the same handle were not supported in
pre-7.7 versions, and caused confusion and defined behaviour.

View File

@@ -6,22 +6,28 @@
TODO TODO
For the future Things to do in project cURL. Please tell me what you think, contribute and
send me patches that improve things!
Ok, this is what I wanna do with Curl. Please tell me what you think, and To do for the 7.7 release:
please don't hesitate to contribute and send me patches that improve this
product! (Yes, you may add things not mentioned here, these are just a * Fix the random seeding. Add --egd-socket and --random-file options to the
few teasers...) curl client and libcurl curl_easy_setopt() interface.
* Support persistant connections (fully detailed elsewhere)
* Add a special connection-timeout that only goes for the connection phase.
To do for the 7.8 release:
* Make SSL session ids get used if multiple HTTPS documents from the same * Make SSL session ids get used if multiple HTTPS documents from the same
host is requested. host is requested.
* Make the curl tool support URLs that start with @ that would then mean that To do in a future release:
the following is a plain list with URLs to download. Thus @filename.txt
reads a list of URLs from a local file. A fancy option would then be to * Extend the test suite to include telnet and https. The telnet could just do
support @http://whatever.com that would first load a list and then get the ftp or http operations (for which we have test servers) and the https would
URLs mentioned in the list. I figure -O or something would have to be probably work against/with some of the openssl tools.
implied by such an action.
* Add a command line option that allows the output file to get the same time * Add a command line option that allows the output file to get the same time
stamp as the remote file. libcurl already is capable of fetching the remote stamp as the remote file. libcurl already is capable of fetching the remote
@@ -31,16 +37,11 @@ For the future
an alternative to OpenSSL: an alternative to OpenSSL:
http://www.mozilla.org/projects/security/pki/nss/ http://www.mozilla.org/projects/security/pki/nss/
* Make sure the low-level interface works. highlevel.c should basically be
possible to write using that interface. Document the low-level interface
* Make the easy-interface support multiple file transfers. If they're done
to the same host, they should use persistant connections or similar.
Figure out a nice design for this.
* Add asynchronous name resolving, as this enables full timeout support for * Add asynchronous name resolving, as this enables full timeout support for
fork() systems. fork() systems.
* Non-blocking connect(), also to make timeouts work on windows.
* Move non-URL related functions that are used by both the lib and the curl * Move non-URL related functions that are used by both the lib and the curl
application to a separate "portability lib". application to a separate "portability lib".
@@ -48,14 +49,13 @@ For the future
something being worked on in this area) and perl (we have seen the first something being worked on in this area) and perl (we have seen the first
versions of this!) comes to mind. Python anyone? versions of this!) comes to mind. Python anyone?
* "Content-Encoding: compress/gzip/zlib" * "Content-Encoding: compress/gzip/zlib" HTTP 1.1 clearly defines how to get
and decode compressed documents. There is the zlib that is pretty good at
decompressing stuff. This work was started in October 1999 but halted again
since it proved more work than we thought. It is still a good idea to
implement though.
HTTP 1.1 clearly defines how to get and decode compressed documents. There * Authentication: NTLM. Support for that MS crap called NTLM
is the zlib that is pretty good at decompressing stuff. This work was
started in October 1999 but halted again since it proved more work than we
thought. It is still a good idea to implement though.
* Authentication: NTLM. It would be to support that MS crap called NTLM
authentication. MS proxies and servers sometime require that. Since that authentication. MS proxies and servers sometime require that. Since that
protocol is a proprietary one, it involves reverse engineering and network protocol is a proprietary one, it involves reverse engineering and network
sniffing. This should however be a library-based functionality. There are a sniffing. This should however be a library-based functionality. There are a
@@ -67,33 +67,22 @@ For the future
* RFC2617 compliance, "Digest Access Authentication" * RFC2617 compliance, "Digest Access Authentication"
A valid test page seem to exist at: A valid test page seem to exist at:
http://hopf.math.nwu.edu/testpage/digest/ http://hopf.math.nwu.edu/testpage/digest/
And some friendly person's server source code is available at And some friendly person's server source code is available at
http://hopf.math.nwu.edu/digestauth/index.html http://hopf.math.nwu.edu/digestauth/index.html
Then there's the Apache mod_digest source code too of course. It seems as 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 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 a lot better authentication method than the more common "Basic". Basic
sends the password in cleartext over the network, this "Digest" method uses sends the password in cleartext over the network, this "Digest" method uses
a challange-response protocol which increases security quite a lot. a challange-response protocol which increases security quite a lot.
* Multiple Proxies?
Is there anyone that actually uses serial-proxies? I mean, send CONNECT to
the first proxy to connect to the second proxy to which you send CONNECT to
connect to the remote host (or even more iterations). Is there anyone
wanting curl to support it? (Not that it would be hard, just confusing...)
* Other proxies * Other proxies
Ftp-kind proxy, Socks5, whatever kind of proxies are there? Ftp-kind proxy, Socks5, whatever kind of proxies are there?
* IPv6 Awareness and support * IPv6 Awareness and support. (This is partly done.) RFC 2428 "FTP
Where ever it would fit. configure search for v6-versions of a few Extensions for IPv6 and NATs" is interesting. PORT should be replaced with
functions and then use them instead is of course the first thing to do... EPRT for IPv6 (done), and EPSV instead of PASV. HTTP proxies are left to
RFC 2428 "FTP Extensions for IPv6 and NATs" will be interesting. PORT add support for.
should be replaced with EPRT for IPv6, and EPSV instead of PASV.
* SSL for more protocols, like SSL-FTP... * SSL for more protocols, like SSL-FTP...
(http://search.ietf.org/internet-drafts/draft-murray-auth-ftp-ssl-05.txt) (http://search.ietf.org/internet-drafts/draft-murray-auth-ftp-ssl-05.txt)
* HTTP POST resume using Range:

View File

@@ -2,13 +2,13 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_easy_cleanup 3 "22 May 2000" "Curl 7.0" "libcurl Manual" .TH curl_easy_cleanup 3 "5 March 2001" "libcurl 7.7" "libcurl Manual"
.SH NAME .SH NAME
curl_easy_cleanup - End a libcurl "easy" session curl_easy_cleanup - End a libcurl session
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "curl_easy_cleanup(CURL *" handle "); .BI "curl_easy_cleanup(CURL *" handle ");"
.ad .ad
.SH DESCRIPTION .SH DESCRIPTION
This function must be the last function to call for a curl session. It is the This function must be the last function to call for a curl session. It is the
@@ -17,6 +17,10 @@ opposite of the
function and must be called with the same function and must be called with the same
.I handle .I handle
as input as the curl_easy_init call returned. as input as the curl_easy_init call returned.
This will effectively close all connections libcurl has been used and possibly
has kept open until now. Don't call this function if you intend to transfer
more files (libcurl 7.7 or later).
.SH RETURN VALUE .SH RETURN VALUE
None None
.SH "SEE ALSO" .SH "SEE ALSO"

View File

@@ -2,11 +2,11 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_easy_init 3 "4 February 2001" "Curl 7.6.1" "libcurl Manual" .TH curl_easy_init 3 "5 March 2001" "libcurl 7.6.1" "libcurl Manual"
.SH NAME .SH NAME
curl_easy_getinfo - Extract information from a curl session (added in 7.4) curl_easy_getinfo - Extract information from a curl session (added in 7.4)
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... );" .BI "CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ... );"
.ad .ad
@@ -83,8 +83,8 @@ verification that was requested (using the CURLOPT_SSL_VERIFYPEER option to
curl_easy_setopt). (Added in 7.4.2) curl_easy_setopt). (Added in 7.4.2)
.TP .TP
.B CURLINFO_CONTENT_LENGTH_DOWNLOAD .B CURLINFO_CONTENT_LENGTH_DOWNLOAD
Pass a pointer to a double to receive the content-length of the download. Pass a pointer to a double to receive the content-length of the download. This
(Added in 7.6.1) is the value read from the Content-Length: field. (Added in 7.6.1)
.TP .TP
.B CURLINFO_CONTENT_LENGTH_UPLOAD .B CURLINFO_CONTENT_LENGTH_UPLOAD
Pass a pointer to a double to receive the specified size of the upload. Pass a pointer to a double to receive the specified size of the upload.

View File

@@ -2,11 +2,11 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_easy_init 3 "26 September 2000" "Curl 7.0" "libcurl Manual" .TH curl_easy_init 3 "5 March 2001" "libcurl 7.7" "libcurl Manual"
.SH NAME .SH NAME
curl_easy_init - Start a libcurl "easy" session curl_easy_init - Start a libcurl session
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "CURL *curl_easy_init( );" .BI "CURL *curl_easy_init( );"
.ad .ad
@@ -19,6 +19,10 @@ when the operation is complete.
On win32 systems, you need to init the winsock stuff manually, libcurl will On win32 systems, you need to init the winsock stuff manually, libcurl will
not do that for you. WSAStartup() and WSACleanup() should be used accordingly. not do that for you. WSAStartup() and WSACleanup() should be used accordingly.
Using libcurl 7.7 and later, you should perform all your sequential file
transfers using the same curl handle. This enables libcurl to use persistant
connections where possible.
.SH RETURN VALUE .SH RETURN VALUE
If this function returns NULL, something went wrong and you cannot use the If this function returns NULL, something went wrong and you cannot use the
other curl functions. other curl functions.

View File

@@ -2,11 +2,11 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_easy_perform 3 "1 Mar 2001" "Curl 7.0" "libcurl Manual" .TH curl_easy_perform 3 "5 Mar 2001" "libcurl 7.7" "libcurl Manual"
.SH NAME .SH NAME
curl_easy_perform - Do the actual transfer in a "easy" session curl_easy_perform - Perform a file transfer
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "CURLcode curl_easy_perform(CURL *" handle "); .BI "CURLcode curl_easy_perform(CURL *" handle ");
.ad .ad
@@ -17,9 +17,22 @@ It must be called with the same
.I handle .I handle
as input as the curl_easy_init call returned. as input as the curl_easy_init call returned.
You are only allowed to call this function once using the same handle. If you libcurl version 7.7 or later (for older versions see below): You can do any
want to do repeated calls, you must call curl_easy_cleanup and curl_easy_init amount of calls to curl_easy_perform() while using the same handle. If you
again first. intend to transfer more than one file, you are even encouraged to do
so. libcurl will then attempt to re-use the same connection for the following
transfers, thus making the operations faster, less CPU intense and using less
network resources. Just note that you will have to use
.I curl_easy_setopt
between the invokes to set options for the following curl_easy_perform.
You must never call this function simultaneously from two places using the
same handle. Let the function return first before invoking it another time. If
you want parallel transfers, you must use several curl handles.
Before libcurl version 7.7: You are only allowed to call this function once
using the same handle. If you want to do repeated calls, you must call
curl_easy_cleanup and curl_easy_init again first.
.SH RETURN VALUE .SH RETURN VALUE
0 means everything was ok, non-zero means an error occurred as 0 means everything was ok, non-zero means an error occurred as
.I <curl/curl.h> .I <curl/curl.h>

View File

@@ -2,11 +2,11 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_easy_setopt 3 "2 February 2001" "Curl 7.5" "libcurl Manual" .TH curl_easy_setopt 3 "6 March 2001" "libcurl 7.5" "libcurl Manual"
.SH NAME .SH NAME
curl_easy_setopt - Set curl easy-session options curl_easy_setopt - Set curl easy-session options
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "CURLcode curl_easy_setopt(CURL *" handle ", CURLoption "option ", ...); .BI "CURLcode curl_easy_setopt(CURL *" handle ", CURLoption "option ", ...);
.ad .ad
@@ -20,7 +20,11 @@ followed by a parameter. That parameter can be a long, a function pointer or
an object pointer, all depending on what the option in question expects. Read an object pointer, all depending on what the option in question expects. Read
this manual carefully as bad input values may cause libcurl to behave badly! this manual carefully as bad input values may cause libcurl to behave badly!
You can only set one option in each function call. A typical application uses You can only set one option in each function call. A typical application uses
many calls in the setup phase. many curl_easy_setopt() calls in the setup phase.
NOTE: strings passed to libcurl as 'char *' arguments, will not be copied by
the library. Instead you should keep them available until libcurl no longer
needs them. Failing to do so will cause very odd behaviour or even crashes.
The The
.I "handle" .I "handle"
@@ -86,14 +90,16 @@ libcurl what the expected size of the infile is.
.TP .TP
.B CURLOPT_URL .B CURLOPT_URL
The actual URL to deal with. The parameter should be a char * to a zero The actual URL to deal with. The parameter should be a char * to a zero
terminated string. NOTE: this option is currently required! terminated string. The string must remain present until curl no longer needs
it, as it doesn't copy the string. NOTE: this option is required to be set
before curl_easy_perform() is called.
.TP .TP
.B CURLOPT_PROXY .B CURLOPT_PROXY
If you need libcurl to use a http proxy to access the outside world, set the If you need libcurl to use a http proxy to access the outside world, set the
proxy string with this option. The parameter should be a char * to a zero proxy string with this option. The parameter should be a char * to a zero
terminated string. To specify port number in this string, append":[port]" to terminated string. To specify port number in this string, append :[port] to
the end of the host name. The proxy string may be prefixed with the end of the host name. The proxy string may be prefixed with
"[protocol]://" since any such prefix will be ignored. [protocol]:// since any such prefix will be ignored.
.TP .TP
.B CURLOPT_PROXYPORT .B CURLOPT_PROXYPORT
Set this long with this option to set the proxy port to use unless it is Set this long with this option to set the proxy port to use unless it is
@@ -189,9 +195,11 @@ prompted for it.
.TP .TP
.B CURLOPT_RANGE .B CURLOPT_RANGE
Pass a char * as parameter, which should contain the specified range you Pass a char * as parameter, which should contain the specified range you
want. It should be in the format "X-Y", where X or Y may be left out. The HTTP want. It should be in the format "X-Y", where X or Y may be left out. HTTP
transfers also support several intervals, separated with commas as in transfers also support several intervals, separated with commas as in
.I "X-Y,N-M". .I "X-Y,N-M"
. Using this kind of multiple intervals will cause the HTTP server to send the
response document in pieces.
.TP .TP
.B CURLOPT_ERRORBUFFER .B CURLOPT_ERRORBUFFER
Pass a char * to a buffer that the libcurl may store human readable error Pass a char * to a buffer that the libcurl may store human readable error
@@ -202,7 +210,8 @@ library. The buffer must be at least CURL_ERROR_SIZE big.
Pass a long as parameter containing the maximum time in seconds that you allow Pass a long as parameter containing the maximum time in seconds that you allow
the libcurl transfer operation to take. Do note that normally, name lookups the libcurl transfer operation to take. Do note that normally, name lookups
maky take a considerable time and that limiting the operation to less than a maky take a considerable time and that limiting the operation to less than a
few minutes risk aborting perfectly normal operations. few minutes risk aborting perfectly normal operations. This option will cause
curl to use the SIGALRM to enable timeouting system calls.
.TP .TP
.B CURLOPT_POSTFIELDS .B CURLOPT_POSTFIELDS
Pass a char * as parameter, which should be the full data to post in a HTTP Pass a char * as parameter, which should be the full data to post in a HTTP

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_formfree 3 "17 November 2000" "Curl 7.5" "libcurl Manual" .TH curl_formfree 3 "5 March 2001" "libcurl 7.5" "libcurl Manual"
.SH NAME .SH NAME
curl_formfree - free a previously build multipart/formdata HTTP POST chain curl_formfree - free a previously build multipart/formdata HTTP POST chain
.SH SYNOPSIS .SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_formparse 3 "22 February 2001" "Curl 7.0" "libcurl Manual" .TH curl_formparse 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_formparse - add a section to a multipart/formdata HTTP POST curl_formparse - add a section to a multipart/formdata HTTP POST
.SH SYNOPSIS .SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_getdate 3 "2 June 2000" "Curl 7.0" "libcurl Manual" .TH curl_getdate 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_getdate - Convert an date in a ASCII string to number of seconds since curl_getdate - Convert an date in a ASCII string to number of seconds since
January 1, 1970 January 1, 1970

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_getenv 3 "2 June 2000" "Curl 7.0" "libcurl Manual" .TH curl_getenv 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_getenv - return value for environment name curl_getenv - return value for environment name
.SH SYNOPSIS .SH SYNOPSIS

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_slist_append 3 "1 Mar 2001" "Curl 7.7" "libcurl Manual" .TH curl_slist_append 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_slist_append - add a string to an slist curl_slist_append - add a string to an slist
.SH SYNOPSIS .SH SYNOPSIS

View File

@@ -2,13 +2,13 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_slist_free_all 3 "2 June 2000" "Curl 7.0" "libcurl Manual" .TH curl_slist_free_all 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_slist_free_all - free an entire curl_slist list curl_slist_free_all - free an entire curl_slist list
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/curl.h> .B #include <curl/curl.h>
.sp .sp
.BI "void curl_slist_free_all(struct curl_slit *" list); .BI "void curl_slist_free_all(struct curl_slist *" list);
.ad .ad
.SH DESCRIPTION .SH DESCRIPTION
curl_slist_free_all() removes all traces of a previously built curl_slist curl_slist_free_all() removes all traces of a previously built curl_slist

View File

@@ -2,11 +2,11 @@
.\" nroff -man [file] .\" nroff -man [file]
.\" Written by daniel@haxx.se .\" Written by daniel@haxx.se
.\" .\"
.TH curl_version 3 "2 June 2000" "Curl 7.0" "libcurl Manual" .TH curl_version 3 "5 March 2001" "libcurl 7.0" "libcurl Manual"
.SH NAME .SH NAME
curl_version - returns the libcurl version string curl_version - returns the libcurl version string
.SH SYNOPSIS .SH SYNOPSIS
.B #include <curl/easy.h> .B #include <curl/curl.h>
.sp .sp
.BI "char *curl_version( );" .BI "char *curl_version( );"
.ad .ad
@@ -14,9 +14,9 @@ curl_version - returns the libcurl version string
Returns a human readable string with the version number of libcurl and some of Returns a human readable string with the version number of libcurl and some of
its important components (like OpenSSL version). its important components (like OpenSSL version).
Do note that this returns the actual running lib's version, you might have Note: this returns the actual running lib's version, you might have installed
installed a newer lib's include files in your system which may turn your a newer lib's include files in your system which may turn your LIBCURL_VERSION
LIBCURL_VERSION #define value to differ from this result. #define value to differ from this result.
.SH RETURN VALUE .SH RETURN VALUE
A pointer to a zero terminated string. A pointer to a zero terminated string.
.SH "SEE ALSO" .SH "SEE ALSO"

View File

@@ -6,7 +6,7 @@ AUTOMAKE_OPTIONS = foreign no-dependencies
EXTRA_DIST = EXTRA_DIST =
README curlgtk.c sepheaders.c simple.c postit.c \ README curlgtk.c sepheaders.c simple.c postit.c \
win32sockets.c \ win32sockets.c persistant.c \
getpageinvar.php simpleget.php simplepost.php getpageinvar.php simpleget.php simplepost.php
all: all:

View File

@@ -0,0 +1,53 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*/
#include <stdio.h>
#include <unistd.h>
#include <curl/curl.h>
/* to make this work under windows, use the win32-functions from the
docs/examples/win32socket.c file as well */
/* This example REQUIRES libcurl 7.7 or later */
#if (LIBCURL_VERSION_NUM < 0x070700)
#error Too old libcurl version, upgrade or stay away.
#endif
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
#ifdef MALLOCDEBUG
/* this sends all memory debug messages to a specified logfile */
curl_memdebug("memdump");
#endif
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
/* get the first document */
curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/");
res = curl_easy_perform(curl);
/* get another document from the same server using the same
connection */
curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/docs/");
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}

View File

@@ -97,71 +97,57 @@ typedef int (*curl_passwd_callback)(void *clientp,
typedef enum { typedef enum {
CURLE_OK = 0, CURLE_OK = 0,
CURLE_UNSUPPORTED_PROTOCOL, CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
CURLE_FAILED_INIT, CURLE_FAILED_INIT, /* 2 */
CURLE_URL_MALFORMAT, CURLE_URL_MALFORMAT, /* 3 */
CURLE_URL_MALFORMAT_USER, CURLE_URL_MALFORMAT_USER, /* 4 */
CURLE_COULDNT_RESOLVE_PROXY, CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
CURLE_COULDNT_RESOLVE_HOST, CURLE_COULDNT_RESOLVE_HOST, /* 6 */
CURLE_COULDNT_CONNECT, CURLE_COULDNT_CONNECT, /* 7 */
CURLE_FTP_WEIRD_SERVER_REPLY, CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */
CURLE_FTP_ACCESS_DENIED, CURLE_FTP_ACCESS_DENIED, /* 9 */
CURLE_FTP_USER_PASSWORD_INCORRECT, CURLE_FTP_USER_PASSWORD_INCORRECT, /* 10 */
CURLE_FTP_WEIRD_PASS_REPLY, CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
CURLE_FTP_WEIRD_USER_REPLY, CURLE_FTP_WEIRD_USER_REPLY, /* 12 */
CURLE_FTP_WEIRD_PASV_REPLY, CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
CURLE_FTP_WEIRD_227_FORMAT, CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
CURLE_FTP_CANT_GET_HOST, CURLE_FTP_CANT_GET_HOST, /* 15 */
CURLE_FTP_CANT_RECONNECT, CURLE_FTP_CANT_RECONNECT, /* 16 */
CURLE_FTP_COULDNT_SET_BINARY, CURLE_FTP_COULDNT_SET_BINARY, /* 17 */
CURLE_PARTIAL_FILE, CURLE_PARTIAL_FILE, /* 18 */
CURLE_FTP_COULDNT_RETR_FILE, CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
CURLE_FTP_WRITE_ERROR, CURLE_FTP_WRITE_ERROR, /* 20 */
CURLE_FTP_QUOTE_ERROR, CURLE_FTP_QUOTE_ERROR, /* 21 */
CURLE_HTTP_NOT_FOUND, CURLE_HTTP_NOT_FOUND, /* 22 */
CURLE_WRITE_ERROR, CURLE_WRITE_ERROR, /* 23 */
CURLE_MALFORMAT_USER, /* 24 - user name is illegally specified */
CURLE_FTP_COULDNT_STOR_FILE, /* 25 - failed FTP upload */
CURLE_READ_ERROR, /* 26 - could open/read from file */
CURLE_OUT_OF_MEMORY, /* 27 */
CURLE_OPERATION_TIMEOUTED, /* 28 - the timeout time was reached */
CURLE_FTP_COULDNT_SET_ASCII, /* 29 - TYPE A failed */
CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
CURLE_FTP_COULDNT_GET_SIZE, /* 32 - the SIZE command failed */
CURLE_HTTP_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
CURLE_HTTP_POST_ERROR, /* 34 */
CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
CURLE_FTP_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
CURLE_FILE_COULDNT_READ_FILE, /* 37 */
CURLE_LDAP_CANNOT_BIND, /* 38 */
CURLE_LDAP_SEARCH_FAILED, /* 39 */
CURLE_LIBRARY_NOT_FOUND, /* 40 */
CURLE_FUNCTION_NOT_FOUND, /* 41 */
CURLE_ABORTED_BY_CALLBACK, /* 42 */
CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
CURLE_BAD_CALLING_ORDER, /* 44 */
CURLE_HTTP_PORT_FAILED, /* 45 - HTTP Interface operation failed */
CURLE_BAD_PASSWORD_ENTERED, /* 46 - my_getpass() returns fail */
CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */
CURLE_UNKNOWN_TELNET_OPTION, /* 48 - User specified an unknown option */
CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */
CURLE_MALFORMAT_USER, /* the user name is illegally specified */ CURL_LAST /* never use! */
CURLE_FTP_COULDNT_STOR_FILE, /* failed FTP upload */
CURLE_READ_ERROR, /* could open/read from file */
CURLE_OUT_OF_MEMORY,
CURLE_OPERATION_TIMEOUTED, /* the timeout time was reached */
CURLE_FTP_COULDNT_SET_ASCII, /* TYPE A failed */
CURLE_FTP_PORT_FAILED, /* FTP PORT operation failed */
CURLE_FTP_COULDNT_USE_REST, /* the REST command failed */
CURLE_FTP_COULDNT_GET_SIZE, /* the SIZE command failed */
CURLE_HTTP_RANGE_ERROR, /* The RANGE "command" didn't seem to work */
CURLE_HTTP_POST_ERROR,
CURLE_SSL_CONNECT_ERROR, /* something was wrong when connecting with SSL */
CURLE_FTP_BAD_DOWNLOAD_RESUME, /* couldn't resume download */
CURLE_FILE_COULDNT_READ_FILE,
CURLE_LDAP_CANNOT_BIND,
CURLE_LDAP_SEARCH_FAILED,
CURLE_LIBRARY_NOT_FOUND,
CURLE_FUNCTION_NOT_FOUND,
CURLE_ABORTED_BY_CALLBACK,
CURLE_BAD_FUNCTION_ARGUMENT,
CURLE_BAD_CALLING_ORDER,
CURLE_HTTP_PORT_FAILED, /* HTTP Interface operation failed */
CURLE_BAD_PASSWORD_ENTERED, /* when the my_getpass() returns fail */
CURLE_TOO_MANY_REDIRECTS , /* catch endless re-direct loops */
CURLE_UNKNOWN_TELNET_OPTION , /* User specified an unknown option */
CURLE_TELNET_OPTION_SYNTAX , /* Malformed telnet option */
CURL_LAST
} CURLcode; } CURLcode;
/* This is just to make older programs not break: */ /* This is just to make older programs not break: */
@@ -458,8 +444,8 @@ char *curl_getenv(char *variable);
char *curl_version(void); char *curl_version(void);
/* This is the version number */ /* This is the version number */
#define LIBCURL_VERSION "7.7-alpha2" #define LIBCURL_VERSION "7.7-beta1"
#define LIBCURL_VERSION_NUM 0x070000 #define LIBCURL_VERSION_NUM 0x070700
/* linked-list structure for the CURLOPT_QUOTE option (and other) */ /* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist { struct curl_slist {

View File

@@ -58,7 +58,8 @@ getenv.c ldap.h ssluse.h \
escape.c mprintf.c telnet.c \ escape.c mprintf.c telnet.c \
escape.h getpass.c netrc.c telnet.h \ escape.h getpass.c netrc.c telnet.h \
getinfo.c transfer.c strequal.c strequal.h easy.c \ getinfo.c transfer.c strequal.c strequal.h easy.c \
security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h \
http_chunks.c http_chunks.h
noinst_HEADERS = setup.h transfer.h noinst_HEADERS = setup.h transfer.h

View File

@@ -91,25 +91,19 @@
#include "memdebug.h" #include "memdebug.h"
#endif #endif
CURLcode file(struct connectdata *conn) /* Emulate a connect-then-transfer protocol. We connect to the file here */
CURLcode Curl_file_connect(struct connectdata *conn)
{ {
/* This implementation ignores the host name in conformance with char *actual_path = curl_unescape(conn->path, 0);
RFC 1738. Only local files (reachable via the standard file system) struct FILE *file;
are supported. This means that files on remotely mounted directories
(via NFS, Samba, NT sharing) can be accessed through a file:// URL
*/
CURLcode res = CURLE_OK;
char *path = conn->path;
struct stat statbuf;
size_t expected_size=-1;
size_t nread;
struct UrlData *data = conn->data;
char *buf = data->buffer;
int bytecount = 0;
struct timeval start = Curl_tvnow();
struct timeval now = start;
int fd; int fd;
char *actual_path = curl_unescape(path, 0);
file = (struct FILE *)malloc(sizeof(struct FILE));
if(!file)
return CURLE_OUT_OF_MEMORY;
memset(file, 0, sizeof(struct FILE));
conn->proto.file = file;
#if defined(WIN32) || defined(__EMX__) #if defined(WIN32) || defined(__EMX__)
int i; int i;
@@ -126,9 +120,37 @@ CURLcode file(struct connectdata *conn)
free(actual_path); free(actual_path);
if(fd == -1) { if(fd == -1) {
failf(data, "Couldn't open file %s", path); failf(conn->data, "Couldn't open file %s", conn->path);
return CURLE_FILE_COULDNT_READ_FILE; return CURLE_FILE_COULDNT_READ_FILE;
} }
file->fd = fd;
return CURLE_OK;
}
/* This is the do-phase, separated from the connect-phase above */
CURLcode Curl_file(struct connectdata *conn)
{
/* This implementation ignores the host name in conformance with
RFC 1738. Only local files (reachable via the standard file system)
are supported. This means that files on remotely mounted directories
(via NFS, Samba, NT sharing) can be accessed through a file:// URL
*/
CURLcode res = CURLE_OK;
struct stat statbuf;
size_t expected_size=-1;
size_t nread;
struct UrlData *data = conn->data;
char *buf = data->buffer;
int bytecount = 0;
struct timeval start = Curl_tvnow();
struct timeval now = start;
int fd;
/* get the fd from the connection phase */
fd = conn->proto.file->fd;
if( -1 != fstat(fd, &statbuf)) { if( -1 != fstat(fd, &statbuf)) {
/* we could stat it, then read out the size */ /* we could stat it, then read out the size */
expected_size = statbuf.st_size; expected_size = statbuf.st_size;

View File

@@ -23,6 +23,6 @@
* *
* $Id$ * $Id$
*****************************************************************************/ *****************************************************************************/
CURLcode file(struct connectdata *conn); CURLcode Curl_file(struct connectdata *conn);
CURLcode Curl_file_connect(struct connectdata *conn);
#endif #endif

View File

@@ -296,6 +296,9 @@ CURLcode Curl_ftp_connect(struct connectdata *conn)
memset(ftp, 0, sizeof(struct FTP)); memset(ftp, 0, sizeof(struct FTP));
conn->proto.ftp = ftp; conn->proto.ftp = ftp;
/* We always support persistant connections on ftp */
conn->bits.close = FALSE;
/* get some initial data into the ftp struct */ /* get some initial data into the ftp struct */
ftp->bytecountp = &conn->bytecount; ftp->bytecountp = &conn->bytecount;

View File

@@ -104,6 +104,7 @@
#include "memdebug.h" #include "memdebug.h"
#endif #endif
/* ------------------------------------------------------------------------- */
/* /*
* The add_buffer series of functions are used to build one large memory chunk * The add_buffer series of functions are used to build one large memory chunk
* from repeated function invokes. Used so that the entire HTTP request can * from repeated function invokes. Used so that the entire HTTP request can
@@ -205,7 +206,7 @@ CURLcode add_buffer(send_buffer *in, void *inptr, size_t size)
} }
/* end of the add_buffer functions */ /* end of the add_buffer functions */
/*****************************************************************************/ /* ------------------------------------------------------------------------- */
/* /*
* Read everything until a newline. * Read everything until a newline.
@@ -309,6 +310,9 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
return CURLE_OK; return CURLE_OK;
} }
/*
* HTTP stuff to do at connect-time.
*/
CURLcode Curl_http_connect(struct connectdata *conn) CURLcode Curl_http_connect(struct connectdata *conn)
{ {
struct UrlData *data; struct UrlData *data;
@@ -402,6 +406,9 @@ CURLcode Curl_http(struct connectdata *conn)
else else
http = conn->proto.http; http = conn->proto.http;
/* We default to persistant connections */
conn->bits.close = FALSE;
if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) && if ( (conn->protocol&(PROT_HTTP|PROT_FTP)) &&
data->bits.upload) { data->bits.upload) {
data->bits.http_put=1; data->bits.http_put=1;

View File

@@ -35,4 +35,9 @@ CURLcode Curl_http_done(struct connectdata *conn);
CURLcode Curl_http_connect(struct connectdata *conn); CURLcode Curl_http_connect(struct connectdata *conn);
CURLcode Curl_http_close(struct connectdata *conn); CURLcode Curl_http_close(struct connectdata *conn);
/* The following functions are defined in http_chunks.c */
void Curl_httpchunk_init(struct connectdata *conn);
CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
ssize_t length, ssize_t *wrote);
#endif #endif

191
lib/http_chunks.c Normal file
View File

@@ -0,0 +1,191 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include "setup.h"
/* -- WIN32 approved -- */
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <stdlib.h>
#include <ctype.h>
#include "urldata.h" /* it includes http_chunks.h */
#include "sendf.h" /* for the client write stuff */
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
/* The last #include file should be: */
#ifdef MALLOCDEBUG
#include "memdebug.h"
#endif
/*
* Chunk format (simplified):
*
* <HEX SIZE>[ chunk extension ] CRLF
* <DATA>
*
* Highlights from RFC2616 section 3.6 say:
The chunked encoding modifies the body of a message in order to
transfer it as a series of chunks, each with its own size indicator,
followed by an OPTIONAL trailer containing entity-header fields. This
allows dynamically produced content to be transferred along with the
information necessary for the recipient to verify that it has
received the full message.
Chunked-Body = *chunk
last-chunk
trailer
CRLF
chunk = chunk-size [ chunk-extension ] CRLF
chunk-data CRLF
chunk-size = 1*HEX
last-chunk = 1*("0") [ chunk-extension ] CRLF
chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
chunk-ext-name = token
chunk-ext-val = token | quoted-string
chunk-data = chunk-size(OCTET)
trailer = *(entity-header CRLF)
The chunk-size field is a string of hex digits indicating the size of
the chunk. The chunked encoding is ended by any chunk whose size is
zero, followed by the trailer, which is terminated by an empty line.
*/
void Curl_httpchunk_init(struct connectdata *conn)
{
struct Curl_chunker *chunk = &conn->proto.http->chunk;
chunk->hexindex=0; /* start at 0 */
chunk->dataleft=0; /* no data left yet! */
chunk->state = CHUNK_HEX; /* we get hex first! */
}
/*
* chunk_read() returns a OK for normal operations, or a positive return code
* for errors. STOP means this sequence of chunks is complete. The 'wrote'
* argument is set to tell the caller how many bytes we actually passed to the
* client (for byte-counting and whatever).
*
* The states and the state-machine is further explained in the header file.
*/
CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
char *datap,
ssize_t length,
ssize_t *wrote)
{
CURLcode result;
struct Curl_chunker *ch = &conn->proto.http->chunk;
int piece;
*wrote = 0; /* nothing yet */
while(length) {
switch(ch->state) {
case CHUNK_HEX:
if(isxdigit((int)*datap)) {
if(ch->hexindex < MAXNUM_SIZE) {
ch->hexbuffer[ch->hexindex] = *datap;
datap++;
length--;
ch->hexindex++;
}
else {
return 1; /* longer hex than we support */
}
}
else {
/* length and datap are unmodified */
ch->hexbuffer[ch->hexindex]=0;
ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
ch->state = CHUNK_POSTHEX;
}
break;
case CHUNK_POSTHEX:
/* just a lame state waiting for CRLF to arrive */
if(*datap == '\r')
ch->state = CHUNK_CR;
length--;
datap++;
break;
case CHUNK_CR:
/* waiting for the LF */
if(*datap == '\n') {
/* we're now expecting data to come, unless size was zero! */
if(0 == ch->datasize) {
ch->state = CHUNK_STOP; /* stop reading! */
if(1 == length) {
/* This was the final byte, return right now */
return CHUNKE_STOP;
}
}
else
ch->state = CHUNK_DATA;
}
else
/* previously we got a fake CR, go back to CR waiting! */
ch->state = CHUNK_CR;
datap++;
length--;
break;
case CHUNK_DATA:
/* we get pure and fine data
We expect another 'datasize' of data. We have 'length' right now,
it can be more or less than 'datasize'. Get the smallest piece.
*/
piece = (ch->datasize >= length)?length:ch->datasize;
/* Write the data portion available */
result = Curl_client_write(conn->data, CLIENTWRITE_BODY, datap, piece);
if(result)
return CHUNKE_WRITE_ERROR;
*wrote += piece;
ch->datasize -= piece; /* decrease amount left to expect */
datap += piece; /* move read pointer forward */
length -= piece; /* decrease space left in this round */
if(0 == ch->datasize)
/* end of data this round, go back to get a new size */
Curl_httpchunk_init(conn);
break;
case CHUNK_STOP:
/* If we arrive here, there is data left in the end of the buffer
even if there's no more chunks to read */
ch->dataleft = length;
return CHUNKE_STOP; /* return stop */
default:
return CHUNKE_STATE_ERROR;
}
}
return CHUNKE_OK;
}

78
lib/http_chunks.h Normal file
View File

@@ -0,0 +1,78 @@
#ifndef __HTTP_CHUNKS_H
#define __HTTP_CHUNKS_H
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
/*
* The longest possible hexadecimal number we support in a chunked transfer.
* Weird enoug, RFC2616 doesn't set a maximum size! Since we use strtoul()
* to convert it, we "only" support 2^32 bytes chunk data.
*/
#define MAXNUM_SIZE 16
typedef enum {
CHUNK_LOST, /* never use */
/* In this we await and buffer all hexadecimal digits until we get one
that isn't a hexadecimal digit. When done, we go POSTHEX */
CHUNK_HEX,
/* We have received the hexadecimal digit and we eat all characters until
we get a CRLF pair. When we see a CR we go to the CR state. */
CHUNK_POSTHEX,
/* A single CR has been found and we should get a LF right away in this
state or we go back to POSTHEX. When LF is received, we go to DATA.
If the size given was zero, we set state to STOP and return. */
CHUNK_CR,
/* We eat the amount of data specified. When done, we move back to the
HEX state. */
CHUNK_DATA,
/* This is mainly used to really mark that we're out of the game.
NOTE: that there's a 'dataleft' field in the struct that will tell how
many bytes that were not passed to the client in the end of the last
buffer! */
CHUNK_STOP,
CHUNK_LAST /* never use */
} ChunkyState;
typedef enum {
CHUNKE_STOP = -1,
CHUNKE_OK = 0,
CHUNKE_TOO_LONG_HEX = 1,
CHUNKE_WRITE_ERROR,
CHUNKE_STATE_ERROR,
CHUNKE_LAST
} CHUNKcode;
struct Curl_chunker {
char hexbuffer[ MAXNUM_SIZE + 1];
int hexindex;
ChunkyState state;
size_t datasize;
size_t dataleft; /* untouched data amount at the end of the last buffer */
};
#endif

View File

@@ -35,6 +35,7 @@
#include "formdata.h" /* for the boundary function */ #include "formdata.h" /* for the boundary function */
#ifdef USE_SSLEAY #ifdef USE_SSLEAY
#include <openssl/rand.h>
static char global_passwd[64]; static char global_passwd[64];
@@ -58,16 +59,93 @@ static int passwd_callback(char *buf, int num, int verify
return 0; return 0;
} }
/* This function is *highly* inspired by (and parts are directly stolen static
* from) source from the SSLeay package written by Eric Young bool seed_enough(struct connectdata *conn, /* unused for now */
* (eay@cryptsoft.com). */ int nread)
{
#ifdef HAVE_RAND_STATUS
/* only available in OpenSSL 0.9.5a and later */
if(RAND_status())
return TRUE;
#else
if(nread > 500)
/* this is a very silly decision to make */
return TRUE;
#endif
return FALSE; /* not enough */
}
static static
int cert_stuff(struct UrlData *data, int random_the_seed(struct connectdata *conn)
struct connectdata *conn, {
char *buf = conn->data->buffer; /* point to the big buffer */
int nread=0;
/* Q: should we add support for a random file name as a libcurl option?
A: Yes */
#if 0
/* something like this */
nread += RAND_load_file(filename, number_of_bytes);
#endif
/* generates a default path for the random seed file */
buf[0]=0; /* blank it first */
RAND_file_name(buf, BUFSIZE);
if ( buf[0] ) {
/* we got a file name to try */
nread += RAND_load_file(buf, 16384);
if(seed_enough(conn, nread))
return nread;
}
#ifdef RANDOM_FILE
nread += RAND_load_file(RANDOM_FILE, 16384);
if(seed_enough(conn, nread))
return nread;
#endif
#if defined(HAVE_RAND_EGD) && defined(EGD_SOCKET)
/* only available in OpenSSL 0.9.5 and later */
/* EGD_SOCKET is set at configure time */
{
int ret = RAND_egd(EGD_SOCKET);
if(-1 != ret) {
nread += ret;
if(seed_enough(conn, nread))
return nread;
}
}
#endif
/* If we get here, it means we need to seed the PRNG using a "silly"
approach! */
#ifdef HAVE_RAND_SCREEN
/* This one gets a random value by reading the currently shown screen */
RAND_screen();
nread = 100; /* just a value */
#else
{
int len;
char *area = Curl_FormBoundary();
if(!area)
return 3; /* out of memory */
len = strlen(area);
RAND_seed(area, len);
free(area); /* now remove the random junk */
#endif
}
infof(conn->data, "Your connection is using a weak random seed!\n");
return nread;
}
static
int cert_stuff(struct connectdata *conn,
char *cert_file, char *cert_file,
char *key_file) char *key_file)
{ {
struct UrlData *data = conn->data;
if (cert_file != NULL) { if (cert_file != NULL) {
SSL *ssl; SSL *ssl;
X509 *x509; X509 *x509;
@@ -123,9 +201,6 @@ int cert_stuff(struct UrlData *data,
return(1); return(1);
} }
#endif
#ifdef USE_SSLEAY
static static
int cert_verify_callback(int ok, X509_STORE_CTX *ctx) int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
{ {
@@ -156,28 +231,8 @@ Curl_SSLConnect(struct connectdata *conn)
/* Lets get nice error messages */ /* Lets get nice error messages */
SSL_load_error_strings(); SSL_load_error_strings();
#ifdef HAVE_RAND_STATUS /* Make funny stuff to get random input */
/* RAND_status() was introduced in OpenSSL 0.9.5 */ random_the_seed(conn);
if(0 == RAND_status())
#endif
{
/* We need to seed the PRNG properly! */
#ifdef HAVE_RAND_SCREEN
/* This one gets a random value by reading the currently shown screen */
RAND_screen();
#else
int len;
char *area = Curl_FormBoundary();
if(!area)
return 3; /* out of memory */
len = strlen(area);
RAND_seed(area, len);
free(area); /* now remove the random junk */
#endif
}
/* Setup all the global SSL stuff */ /* Setup all the global SSL stuff */
SSLeay_add_ssl_algorithms(); SSLeay_add_ssl_algorithms();
@@ -202,7 +257,7 @@ Curl_SSLConnect(struct connectdata *conn)
} }
if(data->cert) { if(data->cert) {
if (!cert_stuff(data, conn, data->cert, data->cert)) { if (!cert_stuff(conn, data->cert, data->cert)) {
failf(data, "couldn't use certificate!\n"); failf(data, "couldn't use certificate!\n");
return 2; return 2;
} }

View File

@@ -84,16 +84,16 @@
#define SUBBUFSIZE 512 #define SUBBUFSIZE 512
#define SB_CLEAR() subpointer = subbuffer; #define SB_CLEAR(x) x->subpointer = x->subbuffer;
#define SB_TERM() { subend = subpointer; SB_CLEAR(); } #define SB_TERM(x) { x->subend = x->subpointer; SB_CLEAR(x); }
#define SB_ACCUM(c) if (subpointer < (subbuffer+sizeof subbuffer)) { \ #define SB_ACCUM(x,c) if (x->subpointer < (x->subbuffer+sizeof x->subbuffer)) { \
*subpointer++ = (c); \ *x->subpointer++ = (c); \
} }
#define SB_GET() ((*subpointer++)&0xff) #define SB_GET(x) ((*x->subpointer++)&0xff)
#define SB_PEEK() ((*subpointer)&0xff) #define SB_PEEK(x) ((*x->subpointer)&0xff)
#define SB_EOF() (subpointer >= subend) #define SB_EOF(x) (x->subpointer >= x->subend)
#define SB_LEN() (subend - subpointer) #define SB_LEN(x) (x->subend - x->subpointer)
static static
void telrcv(struct connectdata *, void telrcv(struct connectdata *,
@@ -113,14 +113,19 @@ static void printsub(struct UrlData *data,
int direction, unsigned char *pointer, int length); int direction, unsigned char *pointer, int length);
static void suboption(struct connectdata *); static void suboption(struct connectdata *);
/* suboptions */ /* For negotiation compliant to RFC 1143 */
static char subbuffer[SUBBUFSIZE]; #define NO 0
static char *subpointer, *subend; /* buffer for sub-options */ #define YES 1
#define WANTYES 2
#define WANTNO 3
#define EMPTY 0
#define OPPOSITE 1
/* /*
* Telnet receiver states for fsm * Telnet receiver states for fsm
*/ */
static enum typedef enum
{ {
TS_DATA = 0, TS_DATA = 0,
TS_IAC, TS_IAC,
@@ -131,63 +136,76 @@ static enum
TS_CR, TS_CR,
TS_SB, /* sub-option collection */ TS_SB, /* sub-option collection */
TS_SE /* looking for sub-option end */ TS_SE /* looking for sub-option end */
} telrcv_state; } TelnetReceive;
/* For negotiation compliant to RFC 1143 */ struct TELNET {
#define NO 0 int please_negotiate;
#define YES 1 int already_negotiated;
#define WANTYES 2 int us[256];
#define WANTNO 3 int usq[256];
int us_preferred[256];
int him[256];
int himq[256];
int him_preferred[256];
char *subopt_ttype; /* Set with suboption TTYPE */
char *subopt_xdisploc; /* Set with suboption XDISPLOC */
struct curl_slist *telnet_vars; /* Environment variables */
#define EMPTY 0 /* suboptions */
#define OPPOSITE 1 char subbuffer[SUBBUFSIZE];
char *subpointer, *subend; /* buffer for sub-options */
static int please_negotiate = 0;
static int already_negotiated = 0; TelnetReceive telrcv_state;
static int us[256]; };
static int usq[256];
static int us_preferred[256];
static int him[256];
static int himq[256];
static int him_preferred[256];
static char *subopt_ttype = NULL; /* Set with suboption TTYPE */
static char *subopt_xdisploc = NULL; /* Set with suboption XDISPLOC */
static struct curl_slist *telnet_vars = NULL; /* Environment variables */
static static
void init_telnet(struct connectdata *conn) CURLcode init_telnet(struct connectdata *conn)
{ {
telrcv_state = TS_DATA; struct TELNET *tn;
tn = (struct TELNET *)malloc(sizeof(struct TELNET));
if(!tn)
return CURLE_OUT_OF_MEMORY;
conn->proto.telnet = (void *)tn; /* make us known */
memset(tn, 0, sizeof(struct TELNET));
tn->telrcv_state = TS_DATA;
/* Init suboptions */ /* Init suboptions */
SB_CLEAR(); SB_CLEAR(tn);
/* Set all options to NO */ /* Set all options to NO */
memset(us, NO, 256); #if 0
memset(usq, NO, 256); /* NO is zero => default fill pattern */
memset(us_preferred, NO, 256); memset(tn->us, NO, 256);
memset(him, NO, 256); memset(tn->usq, NO, 256);
memset(himq, NO, 256); memset(tn->us_preferred, NO, 256);
memset(him_preferred, NO, 256); memset(tn->him, NO, 256);
memset(tn->himq, NO, 256);
memset(tn->him_preferred, NO, 256);
#endif
/* Set the options we want by default */ /* Set the options we want by default */
us_preferred[TELOPT_BINARY] = YES; tn->us_preferred[TELOPT_BINARY] = YES;
us_preferred[TELOPT_SGA] = YES; tn->us_preferred[TELOPT_SGA] = YES;
him_preferred[TELOPT_BINARY] = YES; tn->him_preferred[TELOPT_BINARY] = YES;
him_preferred[TELOPT_SGA] = YES; tn->him_preferred[TELOPT_SGA] = YES;
return CURLE_OK;
} }
static void negotiate(struct connectdata *conn) static void negotiate(struct connectdata *conn)
{ {
int i; int i;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
for(i = 0;i < NTELOPTS;i++) for(i = 0;i < NTELOPTS;i++)
{ {
if(us_preferred[i] == YES) if(tn->us_preferred[i] == YES)
set_local_option(conn, i, YES); set_local_option(conn, i, YES);
if(him_preferred[i] == YES) if(tn->him_preferred[i] == YES)
set_remote_option(conn, i, YES); set_remote_option(conn, i, YES);
} }
} }
@@ -247,12 +265,13 @@ static void send_negotiation(struct connectdata *conn, int cmd, int option)
static static
void set_remote_option(struct connectdata *conn, int option, int newstate) void set_remote_option(struct connectdata *conn, int option, int newstate)
{ {
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
if(newstate == YES) if(newstate == YES)
{ {
switch(him[option]) switch(tn->him[option])
{ {
case NO: case NO:
him[option] = WANTYES; tn->him[option] = WANTYES;
send_negotiation(conn, DO, option); send_negotiation(conn, DO, option);
break; break;
@@ -261,11 +280,11 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
break; break;
case WANTNO: case WANTNO:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
/* Already negotiating for YES, queue the request */ /* Already negotiating for YES, queue the request */
himq[option] = OPPOSITE; tn->himq[option] = OPPOSITE;
break; break;
case OPPOSITE: case OPPOSITE:
/* Error: already queued an enable request */ /* Error: already queued an enable request */
@@ -274,13 +293,13 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
break; break;
case WANTYES: case WANTYES:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
/* Error: already negotiating for enable */ /* Error: already negotiating for enable */
break; break;
case OPPOSITE: case OPPOSITE:
himq[option] = EMPTY; tn->himq[option] = EMPTY;
break; break;
} }
break; break;
@@ -288,34 +307,34 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
} }
else /* NO */ else /* NO */
{ {
switch(him[option]) switch(tn->him[option])
{ {
case NO: case NO:
/* Already disabled */ /* Already disabled */
break; break;
case YES: case YES:
him[option] = WANTNO; tn->him[option] = WANTNO;
send_negotiation(conn, DONT, option); send_negotiation(conn, DONT, option);
break; break;
case WANTNO: case WANTNO:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
/* Already negotiating for NO */ /* Already negotiating for NO */
break; break;
case OPPOSITE: case OPPOSITE:
himq[option] = EMPTY; tn->himq[option] = EMPTY;
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
himq[option] = OPPOSITE; tn->himq[option] = OPPOSITE;
break; break;
case OPPOSITE: case OPPOSITE:
break; break;
@@ -328,12 +347,13 @@ void set_remote_option(struct connectdata *conn, int option, int newstate)
static static
void rec_will(struct connectdata *conn, int option) void rec_will(struct connectdata *conn, int option)
{ {
switch(him[option]) struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
{ {
case NO: case NO:
if(him_preferred[option] == YES) if(tn->him_preferred[option] == YES)
{ {
him[option] = YES; tn->him[option] = YES;
send_negotiation(conn, DO, option); send_negotiation(conn, DO, option);
} }
else else
@@ -347,29 +367,29 @@ void rec_will(struct connectdata *conn, int option)
break; break;
case WANTNO: case WANTNO:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
/* Error: DONT answered by WILL */ /* Error: DONT answered by WILL */
him[option] = NO; tn->him[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
/* Error: DONT answered by WILL */ /* Error: DONT answered by WILL */
him[option] = YES; tn->him[option] = YES;
himq[option] = EMPTY; tn->himq[option] = EMPTY;
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
him[option] = YES; tn->him[option] = YES;
break; break;
case OPPOSITE: case OPPOSITE:
him[option] = WANTNO; tn->him[option] = WANTNO;
himq[option] = EMPTY; tn->himq[option] = EMPTY;
send_negotiation(conn, DONT, option); send_negotiation(conn, DONT, option);
break; break;
} }
@@ -380,41 +400,42 @@ void rec_will(struct connectdata *conn, int option)
static static
void rec_wont(struct connectdata *conn, int option) void rec_wont(struct connectdata *conn, int option)
{ {
switch(him[option]) struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->him[option])
{ {
case NO: case NO:
/* Already disabled */ /* Already disabled */
break; break;
case YES: case YES:
him[option] = NO; tn->him[option] = NO;
send_negotiation(conn, DONT, option); send_negotiation(conn, DONT, option);
break; break;
case WANTNO: case WANTNO:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
him[option] = NO; tn->him[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
him[option] = WANTYES; tn->him[option] = WANTYES;
himq[option] = EMPTY; tn->himq[option] = EMPTY;
send_negotiation(conn, DO, option); send_negotiation(conn, DO, option);
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(himq[option]) switch(tn->himq[option])
{ {
case EMPTY: case EMPTY:
him[option] = NO; tn->him[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
him[option] = NO; tn->him[option] = NO;
himq[option] = EMPTY; tn->himq[option] = EMPTY;
break; break;
} }
break; break;
@@ -423,12 +444,13 @@ void rec_wont(struct connectdata *conn, int option)
void set_local_option(struct connectdata *conn, int option, int newstate) void set_local_option(struct connectdata *conn, int option, int newstate)
{ {
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
if(newstate == YES) if(newstate == YES)
{ {
switch(us[option]) switch(tn->us[option])
{ {
case NO: case NO:
us[option] = WANTYES; tn->us[option] = WANTYES;
send_negotiation(conn, WILL, option); send_negotiation(conn, WILL, option);
break; break;
@@ -437,11 +459,11 @@ void set_local_option(struct connectdata *conn, int option, int newstate)
break; break;
case WANTNO: case WANTNO:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
/* Already negotiating for YES, queue the request */ /* Already negotiating for YES, queue the request */
usq[option] = OPPOSITE; tn->usq[option] = OPPOSITE;
break; break;
case OPPOSITE: case OPPOSITE:
/* Error: already queued an enable request */ /* Error: already queued an enable request */
@@ -450,13 +472,13 @@ void set_local_option(struct connectdata *conn, int option, int newstate)
break; break;
case WANTYES: case WANTYES:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
/* Error: already negotiating for enable */ /* Error: already negotiating for enable */
break; break;
case OPPOSITE: case OPPOSITE:
usq[option] = EMPTY; tn->usq[option] = EMPTY;
break; break;
} }
break; break;
@@ -464,34 +486,34 @@ void set_local_option(struct connectdata *conn, int option, int newstate)
} }
else /* NO */ else /* NO */
{ {
switch(us[option]) switch(tn->us[option])
{ {
case NO: case NO:
/* Already disabled */ /* Already disabled */
break; break;
case YES: case YES:
us[option] = WANTNO; tn->us[option] = WANTNO;
send_negotiation(conn, WONT, option); send_negotiation(conn, WONT, option);
break; break;
case WANTNO: case WANTNO:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
/* Already negotiating for NO */ /* Already negotiating for NO */
break; break;
case OPPOSITE: case OPPOSITE:
usq[option] = EMPTY; tn->usq[option] = EMPTY;
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
usq[option] = OPPOSITE; tn->usq[option] = OPPOSITE;
break; break;
case OPPOSITE: case OPPOSITE:
break; break;
@@ -504,12 +526,13 @@ void set_local_option(struct connectdata *conn, int option, int newstate)
static static
void rec_do(struct connectdata *conn, int option) void rec_do(struct connectdata *conn, int option)
{ {
switch(us[option]) struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
{ {
case NO: case NO:
if(us_preferred[option] == YES) if(tn->us_preferred[option] == YES)
{ {
us[option] = YES; tn->us[option] = YES;
send_negotiation(conn, WILL, option); send_negotiation(conn, WILL, option);
} }
else else
@@ -523,29 +546,29 @@ void rec_do(struct connectdata *conn, int option)
break; break;
case WANTNO: case WANTNO:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
/* Error: DONT answered by WILL */ /* Error: DONT answered by WILL */
us[option] = NO; tn->us[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
/* Error: DONT answered by WILL */ /* Error: DONT answered by WILL */
us[option] = YES; tn->us[option] = YES;
usq[option] = EMPTY; tn->usq[option] = EMPTY;
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
us[option] = YES; tn->us[option] = YES;
break; break;
case OPPOSITE: case OPPOSITE:
us[option] = WANTNO; tn->us[option] = WANTNO;
himq[option] = EMPTY; tn->himq[option] = EMPTY;
send_negotiation(conn, WONT, option); send_negotiation(conn, WONT, option);
break; break;
} }
@@ -556,41 +579,42 @@ void rec_do(struct connectdata *conn, int option)
static static
void rec_dont(struct connectdata *conn, int option) void rec_dont(struct connectdata *conn, int option)
{ {
switch(us[option]) struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
switch(tn->us[option])
{ {
case NO: case NO:
/* Already disabled */ /* Already disabled */
break; break;
case YES: case YES:
us[option] = NO; tn->us[option] = NO;
send_negotiation(conn, WONT, option); send_negotiation(conn, WONT, option);
break; break;
case WANTNO: case WANTNO:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
us[option] = NO; tn->us[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
us[option] = WANTYES; tn->us[option] = WANTYES;
usq[option] = EMPTY; tn->usq[option] = EMPTY;
send_negotiation(conn, WILL, option); send_negotiation(conn, WILL, option);
break; break;
} }
break; break;
case WANTYES: case WANTYES:
switch(usq[option]) switch(tn->usq[option])
{ {
case EMPTY: case EMPTY:
us[option] = NO; tn->us[option] = NO;
break; break;
case OPPOSITE: case OPPOSITE:
us[option] = NO; tn->us[option] = NO;
usq[option] = EMPTY; tn->usq[option] = EMPTY;
break; break;
} }
break; break;
@@ -717,6 +741,7 @@ static int check_telnet_options(struct connectdata *conn)
char option_arg[256]; char option_arg[256];
char *buf; char *buf;
struct UrlData *data = conn->data; struct UrlData *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
/* Add the user name as an environment variable if it /* Add the user name as an environment variable if it
was given on the command line */ was given on the command line */
@@ -724,9 +749,9 @@ static int check_telnet_options(struct connectdata *conn)
{ {
char *buf = malloc(256); char *buf = malloc(256);
sprintf(buf, "USER,%s", data->user); sprintf(buf, "USER,%s", data->user);
telnet_vars = curl_slist_append(telnet_vars, buf); tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
us_preferred[TELOPT_NEW_ENVIRON] = YES; tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
} }
for(head = data->telnet_options; head; head=head->next) { for(head = data->telnet_options; head; head=head->next) {
@@ -735,15 +760,15 @@ static int check_telnet_options(struct connectdata *conn)
/* Terminal type */ /* Terminal type */
if(strequal(option_keyword, "TTYPE")) { if(strequal(option_keyword, "TTYPE")) {
subopt_ttype = option_arg; tn->subopt_ttype = option_arg;
us_preferred[TELOPT_TTYPE] = YES; tn->us_preferred[TELOPT_TTYPE] = YES;
continue; continue;
} }
/* Display variable */ /* Display variable */
if(strequal(option_keyword, "XDISPLOC")) { if(strequal(option_keyword, "XDISPLOC")) {
subopt_xdisploc = option_arg; tn->subopt_xdisploc = option_arg;
us_preferred[TELOPT_XDISPLOC] = YES; tn->us_preferred[TELOPT_XDISPLOC] = YES;
continue; continue;
} }
@@ -752,8 +777,8 @@ static int check_telnet_options(struct connectdata *conn)
buf = strdup(option_arg); buf = strdup(option_arg);
if(!buf) if(!buf)
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
telnet_vars = curl_slist_append(telnet_vars, buf); tn->telnet_vars = curl_slist_append(tn->telnet_vars, buf);
us_preferred[TELOPT_NEW_ENVIRON] = YES; tn->us_preferred[TELOPT_NEW_ENVIRON] = YES;
continue; continue;
} }
@@ -773,7 +798,6 @@ static int check_telnet_options(struct connectdata *conn)
* *
* Look at the sub-option buffer, and try to be helpful to the other * Look at the sub-option buffer, and try to be helpful to the other
* side. * side.
* No suboptions are supported yet.
*/ */
static void suboption(struct connectdata *conn) static void suboption(struct connectdata *conn)
@@ -786,22 +810,23 @@ static void suboption(struct connectdata *conn)
char varname[128]; char varname[128];
char varval[128]; char varval[128];
struct UrlData *data = conn->data; struct UrlData *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
printsub(data, '<', (unsigned char *)subbuffer, SB_LEN()+2); printsub(data, '<', (unsigned char *)tn->subbuffer, SB_LEN(tn)+2);
switch (subchar = SB_GET()) { switch (subchar = SB_GET(tn)) {
case TELOPT_TTYPE: case TELOPT_TTYPE:
len = strlen(subopt_ttype) + 4 + 2; len = strlen(tn->subopt_ttype) + 4 + 2;
snprintf((char *)temp, sizeof(temp), snprintf((char *)temp, sizeof(temp),
"%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_TTYPE,
TELQUAL_IS, subopt_ttype, IAC, SE); TELQUAL_IS, tn->subopt_ttype, IAC, SE);
swrite(conn->firstsocket, temp, len); swrite(conn->firstsocket, temp, len);
printsub(data, '>', &temp[2], len-2); printsub(data, '>', &temp[2], len-2);
break; break;
case TELOPT_XDISPLOC: case TELOPT_XDISPLOC:
len = strlen(subopt_xdisploc) + 4 + 2; len = strlen(tn->subopt_xdisploc) + 4 + 2;
snprintf((char *)temp, sizeof(temp), snprintf((char *)temp, sizeof(temp),
"%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC, "%c%c%c%c%s%c%c", IAC, SB, TELOPT_XDISPLOC,
TELQUAL_IS, subopt_xdisploc, IAC, SE); TELQUAL_IS, tn->subopt_xdisploc, IAC, SE);
swrite(conn->firstsocket, temp, len); swrite(conn->firstsocket, temp, len);
printsub(data, '>', &temp[2], len-2); printsub(data, '>', &temp[2], len-2);
break; break;
@@ -810,7 +835,7 @@ static void suboption(struct connectdata *conn)
"%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS); "%c%c%c%c", IAC, SB, TELOPT_NEW_ENVIRON, TELQUAL_IS);
len = 4; len = 4;
for(v = telnet_vars;v;v = v->next) { for(v = tn->telnet_vars;v;v = v->next) {
tmplen = (strlen(v->data) + 1); tmplen = (strlen(v->data) + 1);
/* Add the variable only if it fits */ /* Add the variable only if it fits */
if(len + tmplen < sizeof(temp)-6) { if(len + tmplen < sizeof(temp)-6) {
@@ -839,15 +864,16 @@ void telrcv(struct connectdata *conn,
unsigned char c; unsigned char c;
int index = 0; int index = 0;
struct UrlData *data = conn->data; struct UrlData *data = conn->data;
struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
while(count--) while(count--)
{ {
c = inbuf[index++]; c = inbuf[index++];
switch (telrcv_state) switch (tn->telrcv_state)
{ {
case TS_CR: case TS_CR:
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
if (c == '\0') if (c == '\0')
{ {
break; /* Ignore \0 after CR */ break; /* Ignore \0 after CR */
@@ -859,12 +885,12 @@ void telrcv(struct connectdata *conn,
case TS_DATA: case TS_DATA:
if (c == IAC) if (c == IAC)
{ {
telrcv_state = TS_IAC; tn->telrcv_state = TS_IAC;
break; break;
} }
else if(c == '\r') else if(c == '\r')
{ {
telrcv_state = TS_CR; tn->telrcv_state = TS_CR;
} }
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
@@ -875,20 +901,20 @@ void telrcv(struct connectdata *conn,
switch (c) switch (c)
{ {
case WILL: case WILL:
telrcv_state = TS_WILL; tn->telrcv_state = TS_WILL;
continue; continue;
case WONT: case WONT:
telrcv_state = TS_WONT; tn->telrcv_state = TS_WONT;
continue; continue;
case DO: case DO:
telrcv_state = TS_DO; tn->telrcv_state = TS_DO;
continue; continue;
case DONT: case DONT:
telrcv_state = TS_DONT; tn->telrcv_state = TS_DONT;
continue; continue;
case SB: case SB:
SB_CLEAR(); SB_CLEAR(tn);
telrcv_state = TS_SB; tn->telrcv_state = TS_SB;
continue; continue;
case IAC: case IAC:
Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1); Curl_client_write(data, CLIENTWRITE_BODY, (char *)&c, 1);
@@ -900,45 +926,45 @@ void telrcv(struct connectdata *conn,
printoption(data, "RCVD", IAC, c); printoption(data, "RCVD", IAC, c);
break; break;
} }
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
continue; continue;
case TS_WILL: case TS_WILL:
printoption(data, "RCVD", WILL, c); printoption(data, "RCVD", WILL, c);
please_negotiate = 1; tn->please_negotiate = 1;
rec_will(conn, c); rec_will(conn, c);
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
continue; continue;
case TS_WONT: case TS_WONT:
printoption(data, "RCVD", WONT, c); printoption(data, "RCVD", WONT, c);
please_negotiate = 1; tn->please_negotiate = 1;
rec_wont(conn, c); rec_wont(conn, c);
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
continue; continue;
case TS_DO: case TS_DO:
printoption(data, "RCVD", DO, c); printoption(data, "RCVD", DO, c);
please_negotiate = 1; tn->please_negotiate = 1;
rec_do(conn, c); rec_do(conn, c);
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
continue; continue;
case TS_DONT: case TS_DONT:
printoption(data, "RCVD", DONT, c); printoption(data, "RCVD", DONT, c);
please_negotiate = 1; tn->please_negotiate = 1;
rec_dont(conn, c); rec_dont(conn, c);
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
continue; continue;
case TS_SB: case TS_SB:
if (c == IAC) if (c == IAC)
{ {
telrcv_state = TS_SE; tn->telrcv_state = TS_SE;
} }
else else
{ {
SB_ACCUM(c); SB_ACCUM(tn,c);
} }
continue; continue;
@@ -959,27 +985,27 @@ void telrcv(struct connectdata *conn,
* we terminate the suboption, and process the * we terminate the suboption, and process the
* partial suboption if we can. * partial suboption if we can.
*/ */
SB_ACCUM((unsigned char)IAC); SB_ACCUM(tn, (unsigned char)IAC);
SB_ACCUM(c); SB_ACCUM(tn, c);
subpointer -= 2; tn->subpointer -= 2;
SB_TERM(); SB_TERM(tn);
printoption(data, "In SUBOPTION processing, RCVD", IAC, c); printoption(data, "In SUBOPTION processing, RCVD", IAC, c);
suboption(conn); /* handle sub-option */ suboption(conn); /* handle sub-option */
telrcv_state = TS_IAC; tn->telrcv_state = TS_IAC;
goto process_iac; goto process_iac;
} }
SB_ACCUM(c); SB_ACCUM(tn,c);
telrcv_state = TS_SB; tn->telrcv_state = TS_SB;
} }
else else
{ {
SB_ACCUM((unsigned char)IAC); SB_ACCUM(tn, (unsigned char)IAC);
SB_ACCUM((unsigned char)SE); SB_ACCUM(tn, (unsigned char)SE);
subpointer -= 2; tn->subpointer -= 2;
SB_TERM(); SB_TERM(tn);
suboption(conn); /* handle sub-option */ suboption(conn); /* handle sub-option */
telrcv_state = TS_DATA; tn->telrcv_state = TS_DATA;
} }
break; break;
} }
@@ -988,7 +1014,12 @@ void telrcv(struct connectdata *conn,
CURLcode Curl_telnet_done(struct connectdata *conn) CURLcode Curl_telnet_done(struct connectdata *conn)
{ {
curl_slist_free_all(telnet_vars); struct TELNET *tn = (struct TELNET *)conn->proto.telnet;
curl_slist_free_all(tn->telnet_vars);
free(conn->proto.telnet);
conn->proto.telnet = NULL;
return CURLE_OK; return CURLE_OK;
} }
@@ -1003,9 +1034,14 @@ CURLcode Curl_telnet(struct connectdata *conn)
bool keepon = TRUE; bool keepon = TRUE;
char *buf = data->buffer; char *buf = data->buffer;
ssize_t nread; ssize_t nread;
struct TELNET *tn;
code = init_telnet(conn);
if(code)
return code;
tn = (struct TELNET *)conn->proto.telnet;
init_telnet(conn);
code = check_telnet_options(conn); code = check_telnet_options(conn);
if(code) if(code)
return code; return code;
@@ -1060,9 +1096,9 @@ CURLcode Curl_telnet(struct connectdata *conn)
/* Negotiate if the peer has started negotiating, /* Negotiate if the peer has started negotiating,
otherwise don't. We don't want to speak telnet with otherwise don't. We don't want to speak telnet with
non-telnet servers, like POP or SMTP. */ non-telnet servers, like POP or SMTP. */
if(please_negotiate && !already_negotiated) { if(tn->please_negotiate && !tn->already_negotiated) {
negotiate(conn); negotiate(conn);
already_negotiated = 1; tn->already_negotiated = 1;
} }
} }
} }

View File

@@ -89,6 +89,7 @@
#include "getpass.h" #include "getpass.h"
#include "progress.h" #include "progress.h"
#include "getdate.h" #include "getdate.h"
#include "http.h"
#define _MPRINTF_REPLACE /* use our functions only */ #define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h> #include <curl/mprintf.h>
@@ -337,6 +338,18 @@ _Transfer(struct connectdata *c_conn)
return urg; return urg;
data->header_size += p - data->headerbuff; data->header_size += p - data->headerbuff;
/*
* end-of-headers.
*
* If we requested a "no body" and this isn't a "close"
* connection, this is a good time to get out and return
* home.
*/
if(!conn->bits.close && data->bits.no_body)
return CURLE_OK;
break; /* exit header line loop */ break; /* exit header line loop */
} }
@@ -365,8 +378,10 @@ _Transfer(struct connectdata *c_conn)
} }
/* check for Content-Length: header lines to get size */ /* check for Content-Length: header lines to get size */
if (strnequal("Content-Length", p, 14) && if (strnequal("Content-Length", p, 14) &&
sscanf (p+14, ": %ld", &contentlength)) sscanf (p+14, ": %ld", &contentlength)) {
conn->size = contentlength; conn->size = contentlength;
Curl_pgrsSetDownloadSize(data, contentlength);
}
else if (strnequal("Connection: close", p, else if (strnequal("Connection: close", p,
strlen("Connection: close"))) { strlen("Connection: close"))) {
/* /*
@@ -377,10 +392,25 @@ _Transfer(struct connectdata *c_conn)
*/ */
conn->bits.close = TRUE; /* close when done */ conn->bits.close = TRUE; /* close when done */
} }
else if (strnequal("Transfer-Encoding: chunked", p,
strlen("Transfer-Encoding: chunked"))) {
/*
* [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
* means that the server will send a series of "chunks". Each
* chunk starts with line with info (including size of the
* coming block) (terminated with CRLF), then a block of data
* with the previously mentioned size. There can be any amount
* of chunks, and a chunk-data set to zero signals the
* end-of-chunks. */
conn->bits.chunk = TRUE; /* chunks coming our way */
/* init our chunky engine */
Curl_httpchunk_init(conn);
}
else if (strnequal("Content-Range", p, 13)) { else if (strnequal("Content-Range", p, 13)) {
if (sscanf (p+13, ": bytes %d-", &offset) || if (sscanf (p+13, ": bytes %d-", &offset) ||
sscanf (p+13, ": bytes: %d-", &offset)) { sscanf (p+13, ": bytes: %d-", &offset)) {
/* This second format was added August 1st by Igor /* This second format was added August 1st 2000 by Igor
Khristophorov since Sun's webserver JavaWebServer/1.1.1 Khristophorov since Sun's webserver JavaWebServer/1.1.1
obviously sends the header this way! :-( */ obviously sends the header this way! :-( */
if (data->resume_from == offset) { if (data->resume_from == offset) {
@@ -457,7 +487,7 @@ _Transfer(struct connectdata *c_conn)
if(0 == bodywrites) { if(0 == bodywrites) {
/* These checks are only made the first time we are about to /* These checks are only made the first time we are about to
write a chunk of the body */ write a piece of the body */
if(conn->protocol&PROT_HTTP) { if(conn->protocol&PROT_HTTP) {
/* HTTP-only checks */ /* HTTP-only checks */
if (data->newurl) { if (data->newurl) {
@@ -514,6 +544,29 @@ _Transfer(struct connectdata *c_conn)
} /* this is the first time we write a body part */ } /* this is the first time we write a body part */
bodywrites++; bodywrites++;
if(conn->bits.chunk) {
/*
* Bless me father for I have sinned. Here comes a chunked
* transfer flying and we need to decode this properly. While
* the name says read, this function both reads and writes away
* the data. The returned 'nread' holds the number of actual
* data it wrote to the client. */
CHUNKcode res =
Curl_httpchunk_read(conn, str, nread, &nread);
if(CHUNKE_OK < res)
return CURLE_READ_ERROR;
else if(CHUNKE_STOP == res) {
/* we're done reading chunks! */
keepon &= ~KEEP_READ; /* read no more */
/* There are now possibly bytes at the end of the str buffer
that weren't written to the client, but we don't care
about them right now. */
}
/* If it returned OK, we just keep going */
}
if(conn->maxdownload && if(conn->maxdownload &&
(bytecount + nread >= conn->maxdownload)) { (bytecount + nread >= conn->maxdownload)) {
nread = conn->maxdownload - bytecount; nread = conn->maxdownload - bytecount;
@@ -526,9 +579,12 @@ _Transfer(struct connectdata *c_conn)
Curl_pgrsSetDownloadCounter(data, (double)bytecount); Curl_pgrsSetDownloadCounter(data, (double)bytecount);
urg = Curl_client_write(data, CLIENTWRITE_BODY, str, nread); if(! conn->bits.chunk) {
if(urg) /* If this is chunky transfer, it was already written */
return urg; urg = Curl_client_write(data, CLIENTWRITE_BODY, str, nread);
if(urg)
return urg;
}
} /* if (! header and data to read ) */ } /* if (! header and data to read ) */
} /* if( read from socket ) */ } /* if( read from socket ) */
@@ -625,8 +681,6 @@ _Transfer(struct connectdata *c_conn)
return CURLE_OK; return CURLE_OK;
} }
typedef int (*func_T)(void);
CURLcode curl_transfer(CURL *curl) CURLcode curl_transfer(CURL *curl)
{ {
CURLcode res; CURLcode res;

View File

@@ -982,6 +982,11 @@ static CURLcode _connect(CURL *curl,
*in_connect = NULL; /* clear the pointer */ *in_connect = NULL; /* clear the pointer */
return CURLE_OUT_OF_MEMORY; return CURLE_OUT_OF_MEMORY;
} }
/* We must set the return variable as soon as possible, so that our
parent can cleanup any possible allocs we may have done before
any failure */
*in_connect = conn;
/* we have to init the struct */ /* we have to init the struct */
memset(conn, 0, sizeof(struct connectdata)); memset(conn, 0, sizeof(struct connectdata));
@@ -994,6 +999,12 @@ static CURLcode _connect(CURL *curl,
conn->secondarysocket = -1; /* no file descriptor */ conn->secondarysocket = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */ conn->connectindex = -1; /* no index */
/* Default protocol-indepent behaveiour doesn't support persistant
connections, so we set this to force-close. Protocols that support
this need to set this to FALSE in their "curl_do" functions. */
conn->bits.close = TRUE;
/*********************************************************** /***********************************************************
* We need to allocate memory to store the path in. We get the size of the * We need to allocate memory to store the path in. We get the size of the
* full URL to be sure, and we need to make it at least 256 bytes since * full URL to be sure, and we need to make it at least 256 bytes since
@@ -1425,13 +1436,20 @@ static CURLcode _connect(CURL *curl,
else if (strequal(conn->protostr, "FILE")) { else if (strequal(conn->protostr, "FILE")) {
conn->protocol |= PROT_FILE; conn->protocol |= PROT_FILE;
conn->curl_do = file; conn->curl_do = Curl_file;
/* no done() function */ /* no done() function */
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */ /* anyway, this is supposed to be the connect function so we better
-1, NULL); /* no upload */ at least check that the file is present here! */
result = Curl_file_connect(conn);
return CURLE_OK; /* Setup a "faked" transfer that'll do nothing */
if(CURLE_OK == result) {
result = Curl_Transfer(conn, -1, -1, FALSE, NULL, /* no download */
-1, NULL); /* no upload */
}
return result;
} }
else { else {
/* We fell through all checks and thus we don't support the specified /* We fell through all checks and thus we don't support the specified
@@ -1582,7 +1600,6 @@ static CURLcode _connect(CURL *curl,
*/ */
ConnectionStore(data, conn); ConnectionStore(data, conn);
} }
*in_connect = conn;
/************************************************************* /*************************************************************
* Resolve the name of the server or proxy * Resolve the name of the server or proxy
@@ -1779,30 +1796,15 @@ CURLcode curl_connect(CURL *curl, CURLconnect **in_connect,
if(CURLE_OK != code) { if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated /* We're not allowed to return failure with memory left allocated
in the connectdata struct, free those here */ in the connectdata struct, free those here */
struct UrlData *data;
int index;
conn = (struct connectdata *)*in_connect; conn = (struct connectdata *)*in_connect;
data = conn->data;
#if 0
if(conn) { if(conn) {
if(conn->path) struct UrlData *data;
free(conn->path); int index;
#ifdef ENABLE_IPV6 data = conn->data;
if(conn->hp) index = conn->connectindex; /* get the index */
freeaddrinfo(conn->hp); curl_disconnect(conn); /* close the connection */
#else data->connects[index]=NULL; /* clear the pointer */
if(conn->hostent_buf)
free(conn->hostent_buf);
#endif
free(conn);
*in_connect=NULL;
} }
#endif
index = conn->connectindex; /* get the index */
curl_disconnect(conn); /* close the connection */
data->connects[index]=NULL; /* clear the pointer */
} }
return code; return code;
} }

View File

@@ -79,6 +79,8 @@
#include <curl/curl.h> #include <curl/curl.h>
#include "http_chunks.h" /* for the structs and enum stuff */
/* Download buffer size, keep it fairly big for speed reasons */ /* Download buffer size, keep it fairly big for speed reasons */
#define BUFSIZE (1024*50) #define BUFSIZE (1024*50)
@@ -167,6 +169,8 @@ struct HTTP {
struct Form form; struct Form form;
size_t (*storefread)(char *, size_t , size_t , FILE *); size_t (*storefread)(char *, size_t , size_t , FILE *);
FILE *in; FILE *in;
struct Curl_chunker chunk;
}; };
/**************************************************************************** /****************************************************************************
@@ -183,12 +187,20 @@ struct FTP {
char *entrypath; /* the PWD reply when we logged on */ char *entrypath; /* the PWD reply when we logged on */
}; };
/****************************************************************************
* FILE unique setup
***************************************************************************/
struct FILE {
int fd; /* open file descriptor to read from! */
};
/* /*
* Boolean values that concerns this connection. * Boolean values that concerns this connection.
*/ */
struct ConnectBits { struct ConnectBits {
bool close; /* if set, we close the connection after this request */ bool close; /* if set, we close the connection after this request */
bool reuse; /* if set, this is a re-used connection */ bool reuse; /* if set, this is a re-used connection */
bool chunk; /* if set, this is a chunked transfer-encoding */
}; };
/* /*
@@ -318,9 +330,9 @@ struct connectdata {
struct HTTP *gopher; /* alias, just for the sake of being more readable */ struct HTTP *gopher; /* alias, just for the sake of being more readable */
struct HTTP *https; /* alias, just for the sake of being more readable */ struct HTTP *https; /* alias, just for the sake of being more readable */
struct FTP *ftp; struct FTP *ftp;
#if 0 /* no need for special ones for these: */
struct TELNET *telnet;
struct FILE *file; struct FILE *file;
void *telnet; /* private for telnet.c-eyes only */
#if 0 /* no need for special ones for these: */
struct LDAP *ldap; struct LDAP *ldap;
struct DICT *dict; struct DICT *dict;
#endif #endif

View File

@@ -11,7 +11,7 @@ libversion="$version"
# Now we have a section to get the major, minor and patch number from the # Now we have a section to get the major, minor and patch number from the
# full version string. We create a single hexadecimal number from it '0xMMmmpp' # full version string. We create a single hexadecimal number from it '0xMMmmpp'
# #
perl='$a=<STDIN>;@p=split("\\.",$a);for(0..2){printf STDOUT ("%02x",$p[0+$_]);}'; perl='$a=<STDIN>;@p=split("[\\.-]",$a);for(0..2){printf STDOUT ("%02x",$p[0+$_]);}';
numeric=`echo $libversion | perl -e "$perl"` numeric=`echo $libversion | perl -e "$perl"`

View File

@@ -1,3 +1,3 @@
#define CURL_NAME "curl" #define CURL_NAME "curl"
#define CURL_VERSION "7.7-alpha2" #define CURL_VERSION "7.7-beta1"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") " #define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

View File

@@ -7,7 +7,7 @@
The cURL Test Suite The cURL Test Suite
Requires: Requires:
perl perl (and a unix-style shell)
Run: Run:
'make test'. This invokes the 'runtests.pl' perl script. Edit the top 'make test'. This invokes the 'runtests.pl' perl script. Edit the top
@@ -15,7 +15,8 @@ Run:
The script breaks on the first test that doesn't do OK. Use -a to prevent The script breaks on the first test that doesn't do OK. Use -a to prevent
the script to abort on the first error. Run the script with -v for more the script to abort on the first error. Run the script with -v for more
verbose output. verbose output. Use -d to run the test servers with debug output enabled as
well.
Use -s fort shorter output, or pass a string with test numbers to run Use -s fort shorter output, or pass a string with test numbers to run
specific tests only (like ./runtests.pl "3 4" to test 3 and 4 only) specific tests only (like ./runtests.pl "3 4" to test 3 and 4 only)
@@ -26,9 +27,24 @@ Memory:
automatically detect if that is the case, and it will use the ../memanalyze automatically detect if that is the case, and it will use the ../memanalyze
script to analyze the memory debugging output. script to analyze the memory debugging output.
Debug:
If a test case fails, you can conveniently get the script to invoke the
debugger (gdb) for you with the server running and the exact same command
line parameters that failed. Just invoke 'runtests.pl <test number> -g' and
then just type 'run' in the debugger to perform the command through the
debugger.
If a test case causes a core dump, analyze it by running gdb like:
# gdb ../curl/src core
... and get a stack trace with the gdb command:
(gdb) where
Logs: Logs:
All logs are generated in the logs/ subdirctory (it is emtpied first All logs are generated in the logs/ subdirctory (it is emtpied first
in the runtests.sh script) in the runtests.pl script)
Data: Data:
All test-data are put in the data/ subdirctory. All test-data are put in the data/ subdirctory.
@@ -45,8 +61,10 @@ Data:
replyN.txt: the full dump the server should reply to curl for this test. replyN.txt: the full dump the server should reply to curl for this test.
If the final result that curl should've got is not in this If the final result that curl should've got is not in this
file, you can instead name the file replyN0001.txt. This enables file, you can instead name the file replyN0001.txt. This
you to fiddle more. ;-) enables you to fiddle more. ;-) Alas, the server sends the
replyN.txt file but checks the result after the test against
the *0001.txt file.
stdoutN.txt: if this file is present, curl's stdout is compared against stdoutN.txt: if this file is present, curl's stdout is compared against
this file to see that they're identical. If this is present, this file to see that they're identical. If this is present,
@@ -63,7 +81,7 @@ Data:
of the ftp server. It uses a simple syntax that is left to of the ftp server. It uses a simple syntax that is left to
describe here! describe here!
FIX: TODO:
* Make httpserver.pl work when we PUT without Content-Length: * Make httpserver.pl work when we PUT without Content-Length:
* Add persistant connection support and test cases

View File

@@ -62,4 +62,6 @@ command30.txt name29.txt prot29.txt reply29.txt \
command31.txt name32.txt reply31.txt reply32.txt \ command31.txt name32.txt reply31.txt reply32.txt \
command32.txt prot31.txt reply310001.txt reply320001.txt \ command32.txt prot31.txt reply310001.txt reply320001.txt \
name31.txt prot32.txt reply310002.txt reply320002.txt \ name31.txt prot32.txt reply310002.txt reply320002.txt \
command33.txt extra33.txt name33.txt prot33.txt reply33.txt command33.txt extra33.txt name33.txt prot33.txt reply33.txt \
command34.txt prot34.txt reply340001.txt name34.txt reply34.txt \
command35.txt name35.txt prot35.txt reply35.txt

1
tests/data/command34.txt Normal file
View File

@@ -0,0 +1 @@
http://%HOSTIP:%HOSTPORT/34

1
tests/data/command35.txt Normal file
View File

@@ -0,0 +1 @@
http://%HOSTIP:%HOSTPORT/want/35 --include --head

View File

@@ -1 +1 @@
HTTP HEAD HTTP HEAD with Connection: close

1
tests/data/name34.txt Normal file
View File

@@ -0,0 +1 @@
HTTP GET with chunked Transfer-Encoding

1
tests/data/name35.txt Normal file
View File

@@ -0,0 +1 @@
HTTP HEAD without Connection: close

View File

@@ -1,4 +1,4 @@
GET /1 HTTP/1.0 GET /1 HTTP/1.1
User-Agent: curl/7.4.2-pre3 (sparc-sun-solaris2.7) libcurl 7.4.2-pre3 (SSL 0.9.6) User-Agent: curl/7.4.2-pre3 (sparc-sun-solaris2.7) libcurl 7.4.2-pre3 (SSL 0.9.6)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
PUT /we/want/10 HTTP/1.0 PUT /we/want/10 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE A TYPE A
LIST LIST

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PORT 127,0,0,1,243,212 PORT 127,0,0,1,243,212
TYPE A TYPE A
LIST LIST

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
RETR 102 RETR 102

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
CWD a/path CWD a/path
PORT 127,0,0,1,246,33 PORT 127,0,0,1,246,33
TYPE I TYPE I

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
CWD a/path CWD a/path
MDTM 103 MDTM 103
TYPE I TYPE I

View File

@@ -1,5 +1,6 @@
USER userdude USER userdude
PASS passfellow PASS passfellow
PWD
PASV PASV
TYPE A TYPE A
RETR 103 RETR 103

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
CWD /path with spaces/and things2 CWD /path with spaces/and things2
PASV PASV
TYPE A TYPE A

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
STOR 107 STOR 107

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
CWD CWD/STOR/RETR CWD CWD/STOR/RETR
PORT 127,0,0,1,5,109 PORT 127,0,0,1,5,109
TYPE I TYPE I

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
APPE 109 APPE 109

View File

@@ -1,4 +1,4 @@
GET /want/data/110002.txt?coolsite=yes HTTP/1.0 GET /want/data/110002.txt?coolsite=yes HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
SIZE 110 SIZE 110

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
APPE 112 APPE 112

View File

@@ -1,4 +1,4 @@
GET /want/12 HTTP/1.0 GET /want/12 HTTP/1.1
Range: bytes=100-200 Range: bytes=100-200
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
PASV PASV
TYPE I TYPE I
RETR 106 RETR 106

View File

@@ -1,5 +1,6 @@
USER anonymous USER anonymous
PASS curl_by_daniel@haxx.se PASS curl_by_daniel@haxx.se
PWD
DELE before_transfer DELE before_transfer
PASV PASV
TYPE I TYPE I

View File

@@ -1,4 +1,4 @@
DELETE /want/13 HTTP/1.0 DELETE /want/13 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
HEAD /want/14 HTTP/1.0 HEAD /want/14 HTTP/1.1
User-Agent: curl/7.4.2-pre4 (sparc-sun-solaris2.7) libcurl 7.4.2-pre4 User-Agent: curl/7.4.2-pre4 (sparc-sun-solaris2.7) libcurl 7.4.2-pre4
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /want/15 HTTP/1.0 GET /want/15 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
GET http://we.want.that.site.com/2 HTTP/1.0 GET http://we.want.that.site.com/2 HTTP/1.1
Proxy-authorization: Basic ZmFrZUB1c2VyOqenp2xvb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28= Proxy-authorization: Basic ZmFrZUB1c2VyOqenp2xvb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb29vb28=
Host: we.want.that.site.com Host: we.want.that.site.com
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
MOOO /that.site.com/17 HTTP/1.0 MOOO /that.site.com/17 HTTP/1.1
User-Agent: agent007 license to drill User-Agent: agent007 license to drill
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /11 HTTP/1.0 GET /11 HTTP/1.1
User-Agent: curl/7.4.2 (sparc-sun-solaris2.7) libcurl 7.4.2 User-Agent: curl/7.4.2 (sparc-sun-solaris2.7) libcurl 7.4.2
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /2 HTTP/1.0 GET /2 HTTP/1.1
Authorization: Basic ZmFrZTp1c2Vy Authorization: Basic ZmFrZTp1c2Vy
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

File diff suppressed because one or more lines are too long

View File

@@ -1,4 +1,4 @@
GET /want/25 HTTP/1.0 GET /want/25 HTTP/1.1
User-Agent: curl/7.6-pre1 (sparc-sun-solaris2.7) libcurl 7.5.2 (SSL 0.9.6) (krb4 enabled) User-Agent: curl/7.6-pre1 (sparc-sun-solaris2.7) libcurl 7.5.2 (SSL 0.9.6) (krb4 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /want/22 HTTP/1.0 GET /want/22 HTTP/1.1
User-Agent: curl/7.6-pre1 (sparc-sun-solaris2.7) libcurl 7.6-pre1 (SSL 0.9.6) (krb4 enabled) User-Agent: curl/7.6-pre1 (sparc-sun-solaris2.7) libcurl 7.6-pre1 (SSL 0.9.6) (krb4 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /wantit/{}[]/28 HTTP/1.0 GET /wantit/{}[]/28 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
GET /29 HTTP/1.0 GET /29 HTTP/1.1
Range: bytes=200- Range: bytes=200-
User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled) User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999

View File

@@ -1,4 +1,4 @@
POST /3 HTTP/1.0 POST /3 HTTP/1.1
Authorization: Basic ZmFrZTotdXNlcg== Authorization: Basic ZmFrZTotdXNlcg==
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /30 HTTP/1.0 GET /30 HTTP/1.1
User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled) User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
POST /moo/moo/moo/310002 HTTP/1.0 POST /moo/moo/moo/310002 HTTP/1.1
User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled) User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /moo/moo/moo/320002 HTTP/1.0 GET /moo/moo/moo/320002 HTTP/1.1
User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled) User-Agent: curl/7.6 (i686-pc-linux-gnu) libcurl 7.6 (SSL 0.9.5) (ipv6 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
PUT /33 HTTP/1.0 PUT /33 HTTP/1.1
Content-Range: bytes 50-149/150 Content-Range: bytes 50-149/150
User-Agent: curl/7.6 (sparc-sun-solaris2.7) libcurl 7.6-pre4 (SSL 0.9.6) (krb4 enabled) User-Agent: curl/7.6 (sparc-sun-solaris2.7) libcurl 7.6-pre4 (SSL 0.9.6) (krb4 enabled)
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999

6
tests/data/prot34.txt Normal file
View File

@@ -0,0 +1,6 @@
GET /34 HTTP/1.1
User-Agent: curl/7.7-alpha2 (sparc-sun-solaris2.7) libcurl 7.7-alpha2 (SSL 0.9.6) (krb4 enabled)
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

6
tests/data/prot35.txt Normal file
View File

@@ -0,0 +1,6 @@
HEAD /want/35 HTTP/1.1
User-Agent: curl/7.7-alpha2 (sparc-sun-solaris2.7) libcurl 7.7-alpha2 (SSL 0.9.6) (krb4 enabled)
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
GET /4 HTTP/1.0 GET /4 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
extra-header: here extra-header: here

View File

@@ -1,4 +1,4 @@
GET http://127.0.0.1:8999/we/want/that/page/5 HTTP/1.0 GET http://127.0.0.1:8999/we/want/that/page/5 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
GET /we/want/that/page/6 HTTP/1.0 GET /we/want/that/page/6 HTTP/1.1
Cookie: name=contents;name2=content2 Cookie: name=contents;name2=content2
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache

View File

@@ -1,4 +1,4 @@
GET /we/want/7 HTTP/1.0 GET /we/want/7 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
GET /we/want/8 HTTP/1.0 GET /we/want/8 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,4 @@
POST /we/want/9 HTTP/1.0 POST /we/want/9 HTTP/1.1
Host: 127.0.0.1:8999 Host: 127.0.0.1:8999
Pragma: no-cache Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */* Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*

View File

@@ -1,4 +1,5 @@
HTTP/1.1 200 OK HTTP/1.1 200 OK
Server: thebest/1.0 Server: thebest/1.0
Connection: close
no? no?

13
tests/data/reply34.txt Normal file
View File

@@ -0,0 +1,13 @@
HTTP/1.1 200 funky chunky!
Server: fakeit/1.0
Transfer-Encoding: chunked
Connection: mooo
40
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
30
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
20;heresatest=moooo
ccccccccccccccccccccccccccccccc
0
muuu

View File

@@ -0,0 +1,8 @@
HTTP/1.1 200 funky chunky!
Server: fakeit/1.0
Transfer-Encoding: chunked
Connection: mooo
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
ccccccccccccccccccccccccccccccc

4
tests/data/reply35.txt Normal file
View File

@@ -0,0 +1,4 @@
HTTP/1.1 200 OK
Server: thebest/1.0
Silly-but-last-header: funny

View File

@@ -18,5 +18,6 @@ HTTP/1.1 301 This is a weirdo text message
Date: Thu, 09 Nov 2010 14:49:00 GMT Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake Server: test-server/fake
Location: data/110002.txt?coolsite=yes Location: data/110002.txt?coolsite=yes
Connection: close
This server reply is for testing a simple Location: following This server reply is for testing a simple Location: following

View File

@@ -350,6 +350,10 @@ for ( $waitedpid = 0;
&customize(); # read test control instructions &customize(); # read test control instructions
print @welcome; print @welcome;
if($verbose) {
print STDERR "OUT:\n";
print STDERR @welcome;
}
my $state="fresh"; my $state="fresh";
while(1) { while(1) {

View File

@@ -154,6 +154,10 @@ sub runftpserver {
if ($RUNNING != 1) { if ($RUNNING != 1) {
my $flag=$debugprotocol?"-v ":""; my $flag=$debugprotocol?"-v ":"";
if($debugprotocol) {
print "* Starts ftp server verbose:\n";
print "perl $srcdir/ftpserver.pl $flag $FTPPORT &\n";
}
system("perl $srcdir/ftpserver.pl $flag $FTPPORT &"); system("perl $srcdir/ftpserver.pl $flag $FTPPORT &");
sleep 1; # give it a little time to start sleep 1; # give it a little time to start
} }