Compare commits

..

52 Commits

Author SHA1 Message Date
Daniel Stenberg
26983053c4 take port numbers into account when finding a previous session from the
cache
2001-08-29 09:36:41 +00:00
Daniel Stenberg
8e0043165a added COOKIEJAR 2001-08-29 09:32:50 +00:00
Daniel Stenberg
c13dbf7bae uses the new cookie jar feature 2001-08-29 09:32:35 +00:00
Daniel Stenberg
a2b6ef3478 cookie jar adjustments 2001-08-29 09:32:18 +00:00
Daniel Stenberg
b6526af442 added ftpupload.c 2001-08-29 07:12:04 +00:00
Daniel Stenberg
4edba42c7c lots of crap 2001-08-28 09:02:33 +00:00
Daniel Stenberg
1180ef4b31 added the most recent one from automake 1.5, it complained on the former
one being "too old"
2001-08-28 09:01:50 +00:00
Daniel Stenberg
94bf462473 up'ed the version-info 2001-08-28 08:58:27 +00:00
Daniel Stenberg
233b3f718f curl_formadd() adjustments by Georg Huettenegger 2001-08-28 08:55:59 +00:00
Daniel Stenberg
0452fd8657 Georg Huettenegger's updates 2001-08-28 08:55:26 +00:00
Daniel Stenberg
613eafaf02 automake 1.5 complained on my SUFFIXES line! 2001-08-28 08:55:12 +00:00
Daniel Stenberg
725bd1dddf Georg Huettenegger's fixes and improvements to curl_formadd() 2001-08-28 08:54:33 +00:00
Daniel Stenberg
9835629801 Georg Huettenegger added code to deal with error 417 when doing form posts.
NOTE: we might do this for *ALL* errors when doing form posts.
2001-08-28 08:54:09 +00:00
Daniel Stenberg
3c52c53ddd Added SSL session ID caching, moved some SSL code from url.c to ssluse.c 2001-08-28 08:37:54 +00:00
Sterling Hughes
321ba15a82 we should be using start here. 2001-08-26 20:51:16 +00:00
Daniel Stenberg
9e5dfc15ac improved the test 2001-08-26 14:28:05 +00:00
Daniel Stenberg
8d52681e1d Added #include <string.h> and removed a silly mistakenly added , 2001-08-26 14:27:07 +00:00
Daniel Stenberg
56f6815d3d rewrite to work around BSD announcement license issues, this is also
somewhat easier to understand if I may say so. It is slightly slower.
2001-08-24 10:25:02 +00:00
Daniel Stenberg
ce07e79f3c cookies are stored in the reversed order now (which in turn means that
the order is _not_ actually reversed like it used to be)
2001-08-24 10:18:14 +00:00
Daniel Stenberg
723ced9336 T. Bharath's patch => linking with multithreaded versions of the c runtime
library for use in multithreaded apps
2001-08-24 07:45:16 +00:00
Daniel Stenberg
73417b59c7 T. Bharath's patch. It is kind of dirty, as it #pragma aways a whole bunch
of compiler warnings, but I guess they make the life somewhat easier to live
for a ms dude compiling this. For a rainy day: remove the pragmas and correct
the source code that cause the warnings!
2001-08-24 07:43:24 +00:00
Daniel Stenberg
f4e2774ab8 newly re-generated from the modified getdate.y 2001-08-24 07:41:51 +00:00
Daniel Stenberg
d5112c0dec include setup.h properly, not config.h 2001-08-24 07:39:50 +00:00
Daniel Stenberg
aace68c91b extern declarations no longer done on windows (T. Bharath's patch) 2001-08-24 07:39:15 +00:00
Daniel Stenberg
4034f31823 cleanups 2001-08-24 07:24:34 +00:00
Daniel Stenberg
5323340cae Kevin Roth's comments about -G have been addressed:
o -G -I works on the same command line and makes HEAD instead of GET
o -G with an already present question mark in the URL makes an ampersand get
  added as a separator instead
2001-08-24 07:01:09 +00:00
Daniel Stenberg
3aae2ec511 Tim Costello's bug report #454856 2001-08-24 06:31:34 +00:00
Daniel Stenberg
df09214c62 strcasecmp() is banned from our code, should be strequal() everywhere!
Tim Costello reported bug report #454858.
2001-08-24 06:20:47 +00:00
Daniel Stenberg
12acab9b86 When setting *_URL or *_PROXY in *_setopt(), it is important that we check
and possibly free the existing pointer first, and then clear the "allocated"
bit. We previously mistakenly could free the new pointer passed to us by
the friendly user...!
2001-08-23 14:06:38 +00:00
Daniel Stenberg
c9c2115088 started working on a function for writing (all) cookies, made it possible
to read multiple cookie files, no longer writes to the URL string passed
to the _add() function. The new stuff is now conditionally compiled on the
COOKIE define. Changed the _init() proto.
2001-08-23 14:05:25 +00:00
Daniel Stenberg
d73d28a75b added FTPS to the list of supported protocols 2001-08-23 11:12:07 +00:00
Daniel Stenberg
13bf964b78 item 4.6 is now an indication of a crash, not a timeout 2001-08-23 11:11:13 +00:00
Daniel Stenberg
3fb9c5727c As Steve Lhomme pointed out, this generates 'libcurl.dll' now instead of
the previous 'curl.dll'
2001-08-23 11:06:10 +00:00
Daniel Stenberg
b69f33ed44 Nico's update: "modified the build procedure to restore to the right current
directory where the build was started and it will autosense where is was run
from and set up the correct default directory at start of the script."
2001-08-23 10:56:48 +00:00
Daniel Stenberg
56e8d073bf curl_formadd() using example, the 7.9 style of building rfc1867 form posts 2001-08-23 08:45:20 +00:00
Daniel Stenberg
83a8786fe1 I want Sterling to be my friend, so I wasted some time on splitting up the
huge monster function _ftp() into more little functions. There are still
more that can be done, but this is at least improving readability and
maintainability... :-)
2001-08-23 06:10:01 +00:00
Daniel Stenberg
e3d7cc895b Georg Huettenegger's fixes, man pages converted to HTML pages and included
in release archive
2001-08-22 11:25:39 +00:00
Daniel Stenberg
0f425b01aa CURLOPT_FTPASCII is the old name, CURLOPT_TRANSFERTEXT is the new 2001-08-22 11:24:57 +00:00
Daniel Stenberg
c5a4b52d83 libcurl.3 has the info now 2001-08-22 11:23:53 +00:00
Daniel Stenberg
fc2d24105c CURLOPT_POST isn't needed these days 2001-08-22 11:23:07 +00:00
Daniel Stenberg
6704d44dd4 updated 2001-08-22 11:22:43 +00:00
Daniel Stenberg
3d9aeccc90 libcurl.3 is the man page 2001-08-22 11:22:28 +00:00
Daniel Stenberg
08655d8d5d Georg Huettenegger's patch curl-7.8.1-pre5-patch-20010819 2001-08-21 13:18:07 +00:00
Daniel Stenberg
3e5dbac7a2 added test44 formpost without Expect:, modified test9 2001-08-21 12:46:23 +00:00
Daniel Stenberg
05d9c9b849 run 'make clean' before 'make dist' to make sure the HTML files are up-to-date 2001-08-21 09:16:43 +00:00
Daniel Stenberg
4c2fb64e21 added a 'html' target that builds HTML versions from the man page sources.
It requires 'gnroff' and 'man2html' for now. 'make html' will be invoked by
the 'maketgz' script and the HTML files are included in release archives.
2001-08-21 09:16:09 +00:00
Daniel Stenberg
46a897f604 make html runs make html in the docs dir 2001-08-21 09:14:31 +00:00
Daniel Stenberg
d4b23198fa this is replaced with libcurl.3 2001-08-21 06:56:13 +00:00
Daniel Stenberg
6581663687 fflush the progress output, fixed configure.in for SSL without --with-ssl 2001-08-21 06:50:45 +00:00
Daniel Stenberg
4398151fd5 Troy Engel's fix for running configure without --with-ssl 2001-08-21 06:36:30 +00:00
Daniel Stenberg
d5fbfa3d0b As Andrs Garca reported we need to fflush() the data->err so that the
progress meter looks better on windows (and if the data->err is redirected
from stderr it also makes a point)
2001-08-21 06:29:56 +00:00
Daniel Stenberg
3a588fc9e7 added "4.5 FIGURE OUT WHAT A POST LOOKS LIKE"
added an online URL to this document
corrected a bad use of -t
2001-08-20 13:22:37 +00:00
54 changed files with 2154 additions and 546 deletions

72
CHANGES
View File

@@ -6,6 +6,78 @@
History of Changes
Daniel (28 August 2001)
- Georg Huettenegger modified the curl_formadd() functionality slightly, and
added support for error code 417 when doing form post and using the Expect:
header. Great work!
- Made some tests with cached SSL session IDs, and they seem to work. There
should be a significant speed improvement in the SSL connection phase, but
in my tiny tests it just isn't possible to notice any difference.
- Upgraded to automake 1.5 on my development/release machine.
Daniel (27 August 2001)
- Slowly started writing SSL session ID caching code
Daniel (24 August 2001)
- T. Bharath removed compiler warnings on windows and updated the MS project
files.
- Kevin Roth reported two kinds of command line constructs with the new -G that
curl didn't really deal with the way one would like.
- Tim Costello patched away a use of strcasecmp() in the SSL code. We have our
own portable version named strequal() that should be used!
- Tim also pointed out a problem in the lib/Makefile.vc6 file that made it mix
debug object modules causing confusions.
Daniel (23 August 2001)
- T. Bharath accurately found a libcurl bug that would happen when doing a
second invoke of curl_easy_perform() with a new URL when the previous invoke
followed a Location: header.
- Started the improvement work on the cookie engine:
- Now keeps cookies in the same order as the cookie file
- A write to the possibly static string was removed
- Added a function that can output all cookies
- Now supports reading multiple cookie files
- Steve Lhomme corrected a DLL naming issue in the MSVC++ project file.
- Split up the monster function in lib/ftp.c to use more smallish functions to
increase readability and maintainability.
Daniel (21 August 2001)
- Georg Huettenegger's big patch was applied. Now we have:
o "Expect: 100-continue" support. We will from now on send that header in
all rfc1867-posts, as that makes us abort much faster when the server
rejects our POST. Posting without the Expect: header is still possible in
the standard replace-internal-header style.
o curl_formadd() is a new formpost building function that is introduced to
replace the now deprecated curl_formparse() function. The latter function
will still hang around for a while, but the curl_formadd() is the new way
and correct way to build form posts.
o Documentation has been updated to reflect these changes
These changes are reason enough to name the next curl release 7.9...
- We now convert man pages to HTML pages and include them in the release
archive. For the pleasure of everyone without nroff within reach.
- Andr<64>s Garc<72>a's suggested flushing of the progress meter output stream was
added. It should make the progress meter look better on Windows.
- Troy Engel pointed out a mistake in the configure script that made it fail
on many Red Hat boxes!
Daniel (20 August 2001)
- We need an updated libtool to make a better build environment for OpenBSD
as well as FreeBSD
Version 7.8.1
Daniel (20 August 2001)
- Brad pointed out that we ship two extra libtool files in the tarballs that
we really don't need to! Removing them makes the gz-archive about 60K

View File

@@ -18,6 +18,9 @@ SUBDIRS = docs lib src include tests packages perl php
dist-hook:
cp $(srcdir)/Makefile.dist $(distdir)/Makefile
html:
cd docs; make html
check: test
test:

2
README
View File

@@ -12,7 +12,7 @@ README
document.
libcurl is a library that Curl is using to do its job. It is readily
available to be used by your software. Read the libcurl.5 man page to
available to be used by your software. Read the libcurl.3 man page to
find out how!
You find answers to the most frequent questions we get in the FAQ document.

Binary file not shown.

View File

@@ -101,6 +101,9 @@
/* Define if you have the <alloca.h> header file. */
/*#define HAVE_ALLOCA_H 1*/
/* Define if you have the malloc.h file. */
#define HAVE_MALLOC_H 1
/* Define if you have the <arpa/inet.h> header file. */
#define HAVE_ARPA_INET_H 1
@@ -185,3 +188,28 @@
#define HAVE_UNISTD_H 1
#endif
/**************************************************
*This is to eliminate the warnings when compiled *
* using MS VC++ compiler *
**************************************************/
#ifdef _MSC_VER
#pragma warning (disable: 4244) /* truncation from 'const int' to 'char' */
#pragma warning (disable: 4127) /* conditional expression is constant */
#pragma warning (disable: 4706) /* assignment within conditional expression */
#pragma warning (disable: 4761) /* integral size mismatch in argument */
#pragma warning (disable: 4101) /* unreferenced local variable */
#pragma warning (disable: 4131) /* uses old-style declarator */
#pragma warning (disable: 4057) /* const char *' differs in indirection to
slightly different base types from
'unsigned char [x] */
#pragma warning (disable: 4100) /* unreferenced formal parameter */
#pragma warning (disable: 4055) /* type cast' : from data pointer 'void *' to
function pointer
'void *(__cdecl *)(char *,int ) */
#pragma warning (disable: 4701) /* local variable may be used without having
been initialized */
#pragma warning (disable: 4715) /* ToHour' : not all control paths return a
value */
#endif

View File

@@ -305,6 +305,8 @@ else
case "$OPT_SSL" in
yes)
EXTRA_SSL=/usr/local/ssl ;;
off)
EXTRA_SSL= ;;
*)
dnl check the given spot right away!
EXTRA_SSL=$OPT_SSL

View File

@@ -1,4 +1,4 @@
Updated: August 7, 2001 (http://curl.haxx.se/docs/faq.shtml)
Updated: August 23, 2001 (http://curl.haxx.se/docs/faq.shtml)
_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
@@ -81,7 +81,7 @@ FAQ
fact it can also be pronounced 'see URL' also helped.
Curl supports a range of common Internet protocols, currently including
HTTP, HTTPS, FTP, GOPHER, LDAP, DICT, TELNET and FILE.
HTTP, HTTPS, FTP, FTPS, GOPHER, LDAP, DICT, TELNET and FILE.
We spell it cURL or just curl. We pronounce it with an initial k sound:
[kurl].
@@ -467,9 +467,9 @@ FAQ
4.6. Can you tell me what error code 142 means?
All error codes that are larger than the highest documented error code means
that curl has existed due to a timeout. There was no nice way for curl to
abort from such a condition and that's why it got this undocumented
error. This should not occur in releases after 7.4.1.
that curl has exited due to a crash. This is a serious error, and we
appriciate a detailed bug report from you that describes how we could go
ahead and repeat this!
4.7. How do I keep user names and passwords secret in Curl command lines?

View File

@@ -1,117 +0,0 @@
_ _ _ _
| (_) |__ ___ _ _ _ __| |
| | | '_ \ / __| | | | '__| |
| | | |_) | (__| |_| | | | |
|_|_|_.__/ \___|\__,_|_| |_|
How To Use Libcurl In Your C/C++ Program
[ libcurl can be used directly from within your Java, PHP, Perl, Ruby or Tcl
programs as well, look elsewhere for documentation on this ]
The interface is meant to be very simple for applictions/programmers, hence
the name "easy". We have therefore minimized the number of entries.
The Easy Interface
When using the easy interface, you init your session and get a handle, which
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,
most important among them is the URL itself (you can't transfer anything
without a specified URL as you may have figured out yourself). You might want
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 using
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 session with
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.
While the above mentioned four functions are the main functions to use in the
easy interface, there is a series of other helpful functions to use. They
are:
curl_version() - displays the libcurl version
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
For details on these, read the separate man pages.
Linking with libcurl
Staring with 7.7.2 (on unix-like machines), there's a tool named curl-config
that gets installed with the rest of the curl stuff when 'make install' is
performed.
curl-config is added to make it easier for applications to link with
libcurl and developers to learn about libcurl and how to use it.
Run 'curl-config --libs' to get the (additional) linker options you need to
link with the particular version of libcurl you've installed.
For details, see the curl-config.1 man page.
libcurl symbol names
All public functions in the libcurl interface are prefixed with 'curl_' (with
a lowercase c). You can find other functions in the library source code, but
other prefixes indicate the functions are private and may change without
further notice in the next release.
Only use documented functions and functionality!
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 as if users of the cygwin environment get this done
automatically.
Threads
Never *ever* call curl-functions simultaneously using the same handle from
several threads. libcurl is thread-safe and can be used in any number of
threads, but you must use separate curl handles if you want to use libcurl in
more than one thread simultaneously.
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

@@ -13,6 +13,7 @@ man_MANS = \
curl_easy_perform.3 \
curl_easy_setopt.3 \
curl_formparse.3 \
curl_formadd.3 \
curl_formfree.3 \
curl_getdate.3 \
curl_getenv.3 \
@@ -28,8 +29,46 @@ man_MANS = \
curl_global_cleanup.3 \
libcurl.3
SUBDIRS = examples
HTMLPAGES = \
curl.html \
curl-config.html \
curl_easy_cleanup.html \
curl_easy_getinfo.html \
curl_easy_init.html \
curl_easy_perform.html \
curl_easy_setopt.html \
curl_formadd.html \
curl_formparse.html \
curl_formfree.html \
curl_getdate.html \
curl_getenv.html \
curl_slist_append.html \
curl_slist_free_all.html \
curl_version.html \
curl_escape.html \
curl_unescape.html \
curl_strequal.html \
curl_strnequal.html \
curl_mprintf.html \
curl_global_init.html \
curl_global_cleanup.html \
libcurl.html
EXTRA_DIST = $(man_MANS) \
MANUAL BUGS CONTRIBUTE FAQ FEATURES INTERNALS \
LIBCURL README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS
README.win32 RESOURCES TODO TheArtOfHttpScripting THANKS \
$(HTMLPAGES)
SUBDIRS = examples
MAN2HTML= gnroff -man $< | man2html >$@
SUFFIXES = .1 .3 .html
html: $(HTMLPAGES)
.3.html:
$(MAN2HTML)
.1.html:
$(MAN2HTML)

View File

@@ -12,26 +12,15 @@ TODO
To do in a future release (random order):
* FTP ASCII upload does not follow RFC959 section 3.1.1.1:
"The sender converts the data from an internal character representation to
the standard 8-bit NVT-ASCII representation (see the Telnet
specification). The receiver will convert the data from the standard form
to his own internal form."
* Make the connect non-blocking so that timeouts work for connect in
multi-threaded programs
* Using FILE * in the libcurl API introduces a serious limitation since (at
least in the *nix falvours I know) you can fopen only the first 256
files. This means, that an application that first opens or fopens 256 files
has no chance to use libcurl. Using open and file descriptors instead of
FILE * would solve the problem. This implies a minor API
change/enhancement. ck1 <ck1@swissonline.ch>
* It would be nice to be able to use "-d" (or something similar) to attach
parameters of EITHER the GET or POST type... It would either require
another curl argument to specify "GET" (obviously the default should remain
POST), or it would require a new curl argument (perhaps -G/--get-data).
I know we're running out of letters, but it somehow feels a little
"cleaner" to just tag on each of your HTTP "parameters" (data-items) one by
one and let curl put them together, rather than having to put them together
myself and include them in the URL.
* Add an interface that enables a user to select prefered SSL ciphers to use.
* Make curl deal with cookies better. libcurl should be able to maintain a
@@ -52,6 +41,11 @@ To do in a future release (random order):
less copy of data and thus a faster operation.
http://curl.haxx.se/dev/no_copy_callbacks.txt
* An option to only download remote FTP files if they're newer than the local
one is a good idea, and it would fit right into the same syntax as the
already working http dito works. It of course requires that 'MDTM' works,
and it isn't a standard FTP command.
* Suggested on the mailing list: CURLOPT_FTP_MKDIR...!
* Add configure options that disables certain protocols in libcurl to

View File

@@ -1,6 +1,7 @@
Online: http://curl.haxx.se/docs/httpscripting.shtml
Author: Daniel Stenberg <daniel@haxx.se>
Date: September 15, 2000
Version: 0.3
Date: August 20, 2001
Version: 0.4
The Art Of Scripting HTTP Requests Using Curl
=============================================
@@ -174,6 +175,19 @@ Version: 0.3
curl -d "birthyear=1905&press=OK&person=daniel" [URL]
4.5 FIGURE OUT WHAT A POST LOOKS LIKE
When you're about fill in a form and send to a server by using curl instead
of a browser, you're of course very interested in sending a POST exactly the
way your browser does.
An easy way to get to see this, is to save the HTML page with the form on
your local disk, mofidy the 'method' to a GET, and press the submit button
(you could also change the action URL if you want to).
You will then clearly see the data get appended to the URL, separated with a
'?'-letter as GET forms are supposed to.
5. PUT
The perhaps best way to upload data to a HTTP server is to use PUT. Then
@@ -182,7 +196,7 @@ Version: 0.3
Put a file to a HTTP server with curl:
curl -t uploadfile www.uploadhttp.com/receive.cgi
curl -T uploadfile www.uploadhttp.com/receive.cgi
6. AUTHENTICATION
@@ -289,7 +303,6 @@ Version: 0.3
curl -b "name=Daniel" www.cookiesite.com
Cookies are sent as common HTTP headers. This is practical as it allows curl
to record cookies simply by recording headers. Record cookies with curl by
using the -D option like:
@@ -304,6 +317,14 @@ Version: 0.3
curl -b stored_cookies_in_file www.cookiesite.com
Curl's "cookie engine" gets enabled when you use the -b option. If you only
want curl to understand received cookies, use -b with a file that doesn't
exist. Example, if you want to let curl understand cookies from a page and
follow a location (and thus possibly send back cookies it received), you can
invoke it like:
curl -b nada -L www.cookiesite.com
11. HTTPS
There are a few ways to do secure HTTP transfers. The by far most common

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file]
.\" $Id$
.\"
.TH curl_easy_setopt 3 "20 August 2001" "libcurl 7.8.1" "libcurl Manual"
.TH curl_easy_setopt 3 "22 August 2001" "libcurl 7.8.1" "libcurl Manual"
.SH NAME
curl_easy_setopt - Set curl easy-session options
.SH SYNOPSIS
@@ -140,7 +140,9 @@ CURLOPT_INFILE and CURLOPT_INFILESIZE are also interesting for uploads.
A non-zero parameter tells the library to do a regular HTTP post. This is a
normal application/x-www-form-urlencoded kind, which is the most commonly used
one by HTML forms. See the CURLOPT_POSTFIELDS option for how to specify the
data to post and CURLOPT_POSTFIELDSIZE in how to set the data size.
data to post and CURLOPT_POSTFIELDSIZE in how to set the data size. Starting
with libcurl 7.8, this option is obsolete. Using the CURLOPT_POSTFIELDS option
will imply this option.
.TP
.B CURLOPT_FTPLISTONLY
A non-zero parameter tells the library to just list the names of an ftp
@@ -211,7 +213,8 @@ that this does not work in multi-threaded programs!
.TP
.B CURLOPT_POSTFIELDS
Pass a char * as parameter, which should be the full data to post in a HTTP
post operation. See also the CURLOPT_POST.
post operation. See also the CURLOPT_POST. Since 7.8, using CURLOPT_POSTFIELDS
implies CURLOPT_POST.
.TP
.B CURLOPT_POSTFIELDSIZE
If you want to post data to the server without letting libcurl do a strlen()
@@ -275,7 +278,7 @@ instruct what data to pass on to the server. Pass a pointer to a linked list
of HTTP post structs as parameter. The linked list should be a fully valid
list of 'struct HttpPost' structs properly filled in. The best and most
elegant way to do this, is to use
.I curl_formparse(3)
.I curl_formadd(3)
as documented. The data in this list must remained intact until you close this
curl handle again with curl_easy_cleanup().
.TP

121
docs/curl_formadd.3 Normal file
View File

@@ -0,0 +1,121 @@
.\" You can view this file with:
.\" nroff -man [file]
.\" $Id$
.\"
.TH curl_formadd 3 "27 August 2001" "libcurl 7.9" "libcurl Manual"
.SH NAME
curl_formadd - add a section to a multipart/formdata HTTP POST
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "CURLcode curl_formadd(struct HttpPost ** " firstitem,
.BI "struct HttpPost ** " lastitem, " ...);"
.ad
.SH DESCRIPTION
curl_formadd() is used to append sections when building a multipart/formdata
HTTP POST (sometimes refered to as rfc1867-style posts). Append one section at
a time until you've added all the sections you want included and then you pass
the \fIfirstitem\fP pointer as parameter to \fBCURLOPT_HTTPPOST\fP.
\fIlastitem\fP is set after each call and on repeated invokes it should be
left as set to allow repeated invokes to find the end of the list in a faster
way.
After \fIlastitem\fP follow the real arguments that constitute the
new section (if the following description confuses you jump directly
to the examples):
CURLFORM_COPYNAME or CURLFORM_PTRNAME followed by a string is used for
the name of the section. Optionally one may use CURLFORM_NAMELENGTH to
specify the length of the name (allowing null characters within the name).
The three options for providing values are: CURLFORM_COPYCONTENTS,
CURLFORM_PTRCONTENTS, or CURLFORM_FILE, followed by a char or void
pointer (allowed for PTRCONTENTS).
Other arguments may be CURLFORM_CONTENTTYPE if the
user wishes to specify one (for FILE if no type is given the library
tries to provide the correct one; for CONTENTS no Content-Type is sent
in this case)
For CURLFORM_PTRCONTENTS or CURLFORM_COPYNAME the user may also add
CURLFORM_CONTENTSLENGTH followed by the length as a long (if not given
the library will use strlen to determine the length).
For CURLFORM_FILE the user may send multiple files in one section by
providing multiple CURLFORM_FILE arguments each followed by the filename
(and each FILE is allowed to have a CONTENTTYPE).
The last argument always is CURLFORM_END.
The pointers \fI*firstitem\fP and \fI*lastitem\fP should both be pointing to
NULL in the first call to this function. All list-data will be allocated by
the function itself. You must call \fIcurl_formfree\fP after the form post has
been done to free the resources again.
This function will copy all input data except the data pointed to by
the arguments after CURLFORM_PTRNAME and CURLFORM_PTRCONTENTS and keep
its own version of it allocated until you call \fIcurl_formfree\fP. When
you've passed the pointer to \fIcurl_easy_setopt\fP, you must not free
the list until after you've called \fIcurl_easy_cleanup\fP for the
curl handle. If you provide a pointer as an arguments after
CURLFORM_PTRNAME or CURLFORM_PTRCONTENTS you must ensure that the pointer
stays valid until you call \fIcurl_form_free\fP and \fIcurl_easy_cleanup\fP.
See example below.
.SH RETURN VALUE
Returns non-zero if an error occurs.
.SH EXAMPLE
.nf
HttpPost* post = NULL;
HttpPost* last = NULL;
char namebuffer[] = "name buffer";
long namelength = strlen(namebuffer);
char buffer[] = "test buffer";
char htmlbuffer[] = "<HTML>test buffer</HTML>";
long htmlbufferlength = strlen(htmlbuffer);
/* add null character into htmlbuffer, to demonstrate that
transfers of buffers containing null characters actually work
*/
htmlbuffer[8] = '\\0';
/* Add simple name/content section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, "content", CURLFORM_END);
/* Add simple name/content/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "htmlcode",
CURLFORM_COPYCONTENTS, "<HTML></HTML>",
CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END);
/* Add name/ptrcontent section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "name_for_ptrcontent",
CURLFORM_PTRCONTENTS, buffer, CURLFORM_END);
/* Add ptrname/ptrcontent section */
curl_formadd(&post, &last, CURLFORM_PTRNAME, namebuffer,
CURLFORM_PTRCONTENTS, buffer, CURLFORM_NAMELENGTH,
namelength, CURLFORM_END);
/* Add name/ptrcontent/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "html_code_with_hole",
CURLFORM_PTRCONTENTS, htmlbuffer,
CURLFORM_CONTENTSLENGTH, htmlbufferlength,
CURLFORM_CONTENTTYPE, "text/html", CURLFORM_END);
/* Add simple file section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture",
CURLFORM_FILE, "my-face.jpg", CURLFORM_END);
/* Add file/contenttype section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "picture",
CURLFORM_FILE, "my-face.jpg",
CURLFORM_CONTENTTYPE, "image/jpeg", CURLFORM_END);
/* Add two file section */
curl_formadd(&post, &last, CURLFORM_COPYNAME, "pictures",
CURLFORM_FILE, "my-face.jpg",
CURLFORM_FILE, "your-face.jpg", CURLFORM_END);
/* Set the form info */
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
.SH "SEE ALSO"
.BR curl_easy_setopt "(3), "
.BR curl_formparse "(3) [deprecated], "
.BR curl_formfree "(3)
.SH BUGS
Surely there are some, you tell me!

View File

@@ -12,12 +12,14 @@ curl_formfree - free a previously build multipart/formdata HTTP POST chain
.ad
.SH DESCRIPTION
curl_formfree() is used to clean up data previously built/appended with
curl_formparse(). This must be called when the data has been used, which
typically means after the curl_easy_perform() has been called.
curl_formadd()/curl_formparse(). This must be called when the data has
been used, which typically means after the curl_easy_perform() has
been called.
.SH RETURN VALUE
None
.SH "SEE ALSO"
.BR curl_formparse "(3) "
.BR curl_formparse "(3) [deprecated], "
.BR curl_formadd "(3) "
.SH BUGS
libcurl 7.7.1 and earlier versions does not allow a NULL pointer to be used as
argument.

View File

@@ -4,7 +4,8 @@
.\"
.TH curl_formparse 3 "21 May 2001" "libcurl 7.7.4" "libcurl Manual"
.SH NAME
curl_formparse - add a section to a multipart/formdata HTTP POST
curl_formparse - add a section to a multipart/formdata HTTP POST:
deprecated (use curl_formadd instead)
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
@@ -79,6 +80,7 @@ Returns non-zero if an error occurs.
.SH "SEE ALSO"
.BR curl_easy_setopt "(3), "
.BR curl_formadd "(3), "
.BR curl_formfree "(3)
.SH BUGS
Surely there are some, you tell me!

View File

@@ -8,7 +8,7 @@ curl_slist_append - add a string to an slist
.SH SYNOPSIS
.B #include <curl/curl.h>
.sp
.BI "struct curl_slist *curl_slist_append(struct curl_slit *" list,
.BI "struct curl_slist *curl_slist_append(struct curl_slist *" list,
.BI "const char * "string ");"
.ad
.SH DESCRIPTION

View File

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

88
docs/examples/ftpupload.c Normal file
View File

@@ -0,0 +1,88 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*/
#include <stdio.h>
#include <curl/curl.h>
/*
* This example shows an FTP upload, with a rename of the file just after
* a successful upload.
*
* Example based on source code provided by Erick Nuwendam. Thanks!
*/
#define LOCAL_FILE "/tmp/uploadthis.txt"
#define UPLOAD_FILE_AS "while-uploading.txt"
#define REMOTE_URL "ftp://localhost/" UPLOAD_FILE_AS
#define RENAME_FILE_TO "renamed-and-fine.txt"
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
FILE *ftpfile;
FILE * hd_src ;
int hd ;
struct stat file_info;
struct curl_slist *headerlist=NULL;
char buf_1 [] = "RNFR " UPLOAD_FILE_AS;
char buf_2 [] = "RNTO " RENAME_FILE_TO;
/* get the file size of the local file */
hd = open(LOCAL_FILE, O_RDONLY) ;
fstat(hd, &file_info);
close(hd) ;
/* get a FILE * of the same file, could also be made with
fdopen() from the previous descriptor, but hey this is just
an example! */
hd_src = fopen(LOCAL_FILE, "rb");
/* In windows, this will init the winsock stuff */
curl_global_init(CURL_GLOBAL_ALL);
/* get a curl handle */
curl = curl_easy_init();
if(curl) {
/* build a list of commands to pass to libcurl */
headerlist = curl_slist_append(headerlist, buf_1);
headerlist = curl_slist_append(headerlist, buf_2);
/* enable uploading */
curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
/* specify target */
curl_easy_setopt(curl,CURLOPT_URL, REMOTE_URL);
/* pass in that last of FTP commands to run after the transfer */
curl_easy_setopt(curl, CURLOPT_POSTQUOTE, headerlist);
/* now specify which file to upload */
curl_easy_setopt(curl, CURLOPT_INFILE, hd_src);
/* and give the size of the upload (optional) */
curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_info.st_size);
/* Now run off and do what you've been told! */
res = curl_easy_perform(curl);
/* clean up the FTP commands list */
curl_slist_free_all (headerlist);
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(hd_src); /* close the local file */
curl_global_cleanup();
return 0;
}

92
docs/examples/postit2.c Normal file
View File

@@ -0,0 +1,92 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*
* Example code that uploads a file name 'foo' to a remote script that accepts
* "HTML form based" (as described in RFC1738) uploads using HTTP POST.
*
* The imaginary form we'll fill in looks like:
*
* <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
* Enter file: <input type="file" name="sendfile" size="40">
* Enter file name: <input type="text" name="filename" size="30">
* <input type="submit" value="send" name="submit">
* </form>
*
* This exact source code has not been verified to work.
*/
/* to make this work under windows, use the win32-functions from the
win32socket.c file as well */
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
#if LIBCURL_VERSION_NUM < 0x070900
#error "curl_formadd() is not introduced until libcurl 7.9 and later"
#endif
int main(int argc, char *argv[])
{
CURL *curl;
CURLcode res;
struct HttpPost *formpost=NULL;
struct HttpPost *lastptr=NULL;
struct curl_slist *headerlist=NULL;
char buf[] = "Expect:";
/* Fill in the file upload field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "sendfile",
CURLFORM_FILE, "postit2.c",
CURLFORM_END);
/* Fill in the filename field */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "filename",
CURLFORM_COPYCONTENTS, "postit2.c",
CURLFORM_END);
/* Fill in the submit field too, even if this is rarely needed */
curl_formadd(&formpost,
&lastptr,
CURLFORM_COPYNAME, "submit",
CURLFORM_COPYCONTENTS, "send",
CURLFORM_END);
curl = curl_easy_init();
/* initalize custom header list (stating that Expect: 100-continue is not
wanted */
headerlist = curl_slist_append(headerlist, buf);
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi");
if ( (argc == 2) && (!strcmp(argv[1], "noexpectheader")) )
/* only disable 100-continue header if explicitly requested */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
/* free slist */
curl_slist_free_all (headerlist);
}
return 0;
}

View File

@@ -53,11 +53,14 @@ portable environment variable reader
.B curl_easy_getinfo()
get information about a performed transfer
.TP
.B curl_formparse()
.B curl_formadd()
helps building a HTTP form POST
.TP
.B curl_formparse()
helps building a HTTP form POST (deprecated since 7.9 use curl_formadd()!)
.TP
.B curl_formfree()
free a list built with curl_formparse()
free a list built with curl_formparse()/curl_formadd()
.TP
.B curl_slist_append()
builds a linked list

View File

@@ -58,13 +58,19 @@ extern "C" {
struct HttpPost {
struct HttpPost *next; /* next entry in the list */
char *name; /* pointer to allocated name */
long namelength; /* length of name length */
char *contents; /* pointer to allocated data contents */
long contentslength; /* length of contents field */
char *contenttype; /* Content-Type */
struct HttpPost *more; /* if one field name has more than one file, this
link should link to following files */
long flags; /* as defined below */
#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
do not free in formfree */
#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
do not free in formfree */
};
typedef int (*curl_progress_callback)(void *clientp,
@@ -447,6 +453,10 @@ typedef enum {
* handshake, set 1 to check existence, 2 to ensure that it matches the
* provided hostname. */
CINIT(SSL_VERIFYHOST, LONG, 81),
/* Specify which file name to write all known cookies in after completed
operation. Set file name to "-" (dash) to make it go to stdout. */
CINIT(COOKIEJAR, OBJECTPOINT, 82),
CURLOPT_LASTENTRY /* the last unusued */
} CURLoption;
@@ -483,6 +493,34 @@ int curl_formparse(char *string,
struct HttpPost **httppost,
struct HttpPost **last_post);
/* name is uppercase CURLFORM_<name> */
#ifdef CFINIT
#undef CFINIT
#endif
#define CFINIT(name) CURLFORM_ ## name
typedef enum {
CFINIT(NOTHING), /********* the first one is unused ************/
/* */
CFINIT(COPYNAME),
CFINIT(PTRNAME),
CFINIT(NAMELENGTH),
CFINIT(COPYCONTENTS),
CFINIT(PTRCONTENTS),
CFINIT(CONTENTSLENGTH),
CFINIT(FILE),
CFINIT(CONTENTTYPE),
CFINIT(END),
CURLFORM_LASTENTRY /* the last unusued */
} CURLformoption;
/* new external form function */
int curl_formadd(struct HttpPost **httppost,
struct HttpPost **last_post,
...);
/* cleanup a form: */
void curl_formfree(struct HttpPost *form);
@@ -495,8 +533,8 @@ char *curl_version(void);
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
char *curl_escape(char *string, int length);
char *curl_unescape(char *string, int length);
char *curl_escape(const char *string, int length);
char *curl_unescape(const char *string, int length);
/* curl_global_init() should be invoked exactly once for each application that
uses libcurl */
@@ -507,8 +545,8 @@ CURLcode curl_global_init(long flags);
void curl_global_cleanup(void);
/* This is the version number */
#define LIBCURL_VERSION "7.8.1"
#define LIBCURL_VERSION_NUM 0x070801
#define LIBCURL_VERSION "7.8.2-pre1"
#define LIBCURL_VERSION_NUM 0x070802
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist {

View File

@@ -16,7 +16,7 @@ lib_LTLIBRARIES = libcurl.la
INCLUDES = -I$(top_srcdir)/include
libcurl_la_LDFLAGS = -version-info 2:1:0
libcurl_la_LDFLAGS = -version-info 2:2:0
# This flag accepts an argument of the form current[:revision[:age]]. So,
# passing -version-info 3:12:1 sets current to 3, revision to 12, and age to
# 1.

View File

@@ -1,11 +1,10 @@
#############################################################
# $Id: Makefile.am,v 1.20 2001/08/08 07:46:44 bagder Exp $
#
## Makefile for building libcurl.lib with MSVC6
## Use: nmake -f makefile.vc6 [release | release-ssl | debug]
## (default is release)
##
## Comments to: Troy Engel <tengel@sonic.net>
## Originally written by: Troy Engel <tengel@sonic.net>
## Updated by: Craig Davison <cd@securityfocus.com>
## Updated by: SM <sm@technologist.com>
@@ -127,7 +126,7 @@ RELEASE_SSL_OBJS= \
versionrs.obj \
easyrs.obj \
strequalrs.obj \
strtokd.obj
strtokrs.obj
LINK_OBJS= \
base64.obj \
@@ -310,7 +309,7 @@ formdatars.obj: formdata.c
ftprs.obj: ftp.c
$(CCRS) $(CFLAGS) ftp.c
httprs.obj: http.c
$(CCR) $(CFLAGS) http.c
$(CCRS) $(CFLAGS) http.c
http_chunksrs.obj: http_chunks.c
$(CCRS) $(CFLAGS) http_chunks.c
ldaprs.obj: ldap.c

View File

@@ -32,9 +32,8 @@
* This code will break if int is smaller than 32 bits
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include "setup.h"
#include <stdlib.h>
#include <string.h>

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* 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.
@@ -95,7 +95,7 @@ Example set of cookies:
/****************************************************************************
*
* cookie_add()
* Curl_cookie_add()
*
* Add a single cookie line to the cookie keeping object.
*
@@ -112,6 +112,7 @@ Curl_cookie_add(struct CookieInfo *c,
char *ptr;
char *semiptr;
struct Cookie *co;
struct Cookie *lastc=NULL;
time_t now = time(NULL);
bool replace_old = FALSE;
@@ -129,13 +130,11 @@ Curl_cookie_add(struct CookieInfo *c,
semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
ptr = lineptr;
do {
if(semiptr)
*semiptr='\0'; /* zero terminate for a while */
/* we have a <what>=<this> pair or a 'secure' word here */
if(strchr(ptr, '=')) {
name[0]=what[0]=0; /* init the buffers */
if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^=]=%"
MAX_COOKIE_LINE_TXT "[^\r\n]",
MAX_COOKIE_LINE_TXT "[^;\r\n]",
name, what)) {
/* this is a legal <what>=<this> pair */
if(strequal("path", name)) {
@@ -178,7 +177,7 @@ Curl_cookie_add(struct CookieInfo *c,
}
}
else {
if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^\r\n]",
if(sscanf(ptr, "%" MAX_COOKIE_LINE_TXT "[^;\r\n]",
what)) {
if(strequal("secure", what))
co->secure = TRUE;
@@ -190,7 +189,6 @@ Curl_cookie_add(struct CookieInfo *c,
if(!semiptr)
continue; /* we already know there are no more cookies */
*semiptr=';'; /* put the semicolon back */
ptr=semiptr+1;
while(ptr && *ptr && isspace((int)*ptr))
ptr++;
@@ -245,6 +243,7 @@ Curl_cookie_add(struct CookieInfo *c,
We don't currently take advantage of this knowledge.
*/
co->field1=strequal(ptr, "TRUE")+1; /* store information */
break;
case 2:
/* It turns out, that sometimes the file format allows the path
@@ -293,6 +292,8 @@ Curl_cookie_add(struct CookieInfo *c,
}
co->livecookie = c->running;
/* now, we have parsed the incoming line, we must now check if this
superceeds an already existing cookie, which it may if the previous have
the same domain and path as this */
@@ -327,6 +328,26 @@ Curl_cookie_add(struct CookieInfo *c,
}
if(replace_old && !co->livecookie && clist->livecookie) {
/* Both cookies matched fine, except that the already present
cookie is "live", which means it was set from a header, while
the new one isn't "live" and thus only read from a file. We let
live cookies stay alive */
/* Free the newcomer and get out of here! */
if(co->domain)
free(co->domain);
if(co->path)
free(co->path);
if(co->name)
free(co->name);
if(co->value)
free(co->value);
free(co);
return NULL;
}
if(replace_old) {
co->next = clist->next; /* get the next-pointer first */
@@ -351,39 +372,51 @@ Curl_cookie_add(struct CookieInfo *c,
}
}
lastc = clist;
clist = clist->next;
}
if(!replace_old) {
/* first, point to our "next" */
co->next = c->cookies;
/* then make ourselves first in the list */
c->cookies = co;
/* then make the last item point on this new one */
if(lastc)
lastc->next = co;
else
c->cookies = co;
}
c->numcookies++; /* one more cookie in the jar */
return co;
}
/*****************************************************************************
*
* cookie_init()
* Curl_cookie_init()
*
* Inits a cookie struct to read data from a local file. This is always
* called before any cookies are set. File may be NULL.
*
****************************************************************************/
struct CookieInfo *Curl_cookie_init(char *file)
struct CookieInfo *Curl_cookie_init(char *file, struct CookieInfo *inc)
{
char line[MAX_COOKIE_LINE];
struct CookieInfo *c;
FILE *fp;
bool fromfile=TRUE;
c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
if(!c)
return NULL; /* failed to get memory */
memset(c, 0, sizeof(struct CookieInfo));
c->filename = strdup(file?file:"none"); /* copy the name just in case */
if(NULL == inc) {
/* we didn't get a struct, create one */
c = (struct CookieInfo *)malloc(sizeof(struct CookieInfo));
if(!c)
return NULL; /* failed to get memory */
memset(c, 0, sizeof(struct CookieInfo));
c->filename = strdup(file?file:"none"); /* copy the name just in case */
}
else {
/* we got an already existing one, use that */
c = inc;
}
c->running = FALSE; /* this is not running, this is init */
if(strequal(file, "-")) {
fp = stdin;
@@ -393,34 +426,35 @@ struct CookieInfo *Curl_cookie_init(char *file)
fp = file?fopen(file, "r"):NULL;
if(fp) {
char *lineptr;
bool headerline;
while(fgets(line, MAX_COOKIE_LINE, fp)) {
if(strnequal("Set-Cookie:", line, 11)) {
/* This is a cookie line, get it! */
char *lineptr=&line[11];
while(*lineptr && isspace((int)*lineptr))
lineptr++;
Curl_cookie_add(c, TRUE, lineptr);
lineptr=&line[11];
headerline=TRUE;
}
else {
/* This might be a netscape cookie-file line, get it! */
char *lineptr=line;
while(*lineptr && isspace((int)*lineptr))
lineptr++;
Curl_cookie_add(c, FALSE, lineptr);
lineptr=line;
headerline=FALSE;
}
while(*lineptr && isspace((int)*lineptr))
lineptr++;
Curl_cookie_add(c, headerline, lineptr);
}
if(fromfile)
fclose(fp);
}
c->running = TRUE; /* now, we're running */
return c;
}
/*****************************************************************************
*
* cookie_getlist()
* Curl_cookie_getlist()
*
* For a given host and path, return a linked list of cookies that the
* client should send to the server if used now. The secure boolean informs
@@ -492,9 +526,9 @@ struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
/*****************************************************************************
*
* cookie_freelist()
* Curl_cookie_freelist()
*
* Free a list previously returned by cookie_getlist();
* Free a list of cookies previously returned by Curl_cookie_getlist();
*
****************************************************************************/
@@ -513,7 +547,7 @@ void Curl_cookie_freelist(struct Cookie *co)
/*****************************************************************************
*
* cookie_cleanup()
* Curl_cookie_cleanup()
*
* Free a "cookie object" previous created with cookie_init().
*
@@ -552,3 +586,93 @@ void Curl_cookie_cleanup(struct CookieInfo *c)
}
}
/*
* Curl_cookie_output()
*
* Writes all internally known cookies to the specified file. Specify
* "-" as file name to write to stdout.
*
* The function returns non-zero on write failure.
*/
int Curl_cookie_output(struct CookieInfo *c, char *dumphere)
{
struct Cookie *co;
FILE *out;
bool use_stdout=FALSE;
if(0 == c->numcookies)
/* If there are no known cookies, we don't write or even create any
destination file */
return 0;
if(strequal("-", dumphere)) {
/* use stdout */
out = stdout;
use_stdout=TRUE;
}
else {
out = fopen(dumphere, "w");
if(!out)
return 1; /* failure */
}
if(c) {
fputs("# Netscape HTTP Cookie File\n"
"# http://www.netscape.com/newsref/std/cookie_spec.html\n"
"# This is generated by libcurl! Edit on your own risk.\n\n",
out);
co = c->cookies;
while(co) {
fprintf(out,
"%s\t" /* domain */
"%s\t" /* field1 */
"%s\t" /* path */
"%s\t" /* secure */
"%u\t" /* expires */
"%s\t" /* name */
"%s\n", /* value */
co->domain,
co->field1==2?"TRUE":"FALSE",
co->path,
co->secure?"TRUE":"FALSE",
(unsigned int)co->expires,
co->name,
co->value);
co=co->next;
}
}
if(!use_stdout)
fclose(out);
return 0;
}
#ifdef CURL_COOKIE_DEBUG
/*
* On my Solaris box, this command line builds this test program:
*
* gcc -g -o cooktest -DCURL_COOKIE_DEBUG -DHAVE_CONFIG_H -I.. -I../include cookie.c strequal.o getdate.o memdebug.o mprintf.o strtok.o -lnsl -lsocket
*
*/
int main(int argc, char **argv)
{
struct CookieInfo *c=NULL;
if(argc>1) {
c = Curl_cookie_init(argv[1], c);
Curl_cookie_add(c, TRUE, "PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/ftgw; secure");
Curl_cookie_add(c, TRUE, "foobar=yes; domain=.haxx.se; path=/looser;");
c = Curl_cookie_init(argv[1], c);
Curl_cookie_output(c);
Curl_cookie_cleanup(c);
return 0;
}
return 1;
}
#endif

View File

@@ -40,19 +40,24 @@ struct Cookie {
char *domain; /* domain = <this> */
time_t expires; /* expires = <this> */
char *expirestr; /* the plain text version */
char field1; /* read from a cookie file, 1 => FALSE, 2=> TRUE */
/* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
char *version; /* Version = <value> */
char *maxage; /* Max-Age = <value> */
bool secure; /* whether the 'secure' keyword was used */
bool livecookie; /* updated from a server, not a stored file */
};
struct CookieInfo {
/* linked list of cookies we know of */
struct Cookie *cookies;
/* linked list of cookies we know of */
struct Cookie *cookies;
char *filename; /* file we read from/write to */
char *filename; /* file we read from/write to */
bool running; /* state info, for cookie adding information */
long numcookies; /* number of cookies in the "jar" */
};
/* This is the maximum line length we accept for a cookie line */
@@ -64,9 +69,10 @@ struct CookieInfo {
#define MAX_NAME_TXT "255"
struct Cookie *Curl_cookie_add(struct CookieInfo *, bool, char *);
struct CookieInfo *Curl_cookie_init(char *);
struct CookieInfo *Curl_cookie_init(char *, struct CookieInfo *);
struct Cookie *Curl_cookie_getlist(struct CookieInfo *, char *, char *, bool);
void Curl_cookie_freelist(struct Cookie *);
void Curl_cookie_cleanup(struct CookieInfo *);
int Curl_cookie_output(struct CookieInfo *, char *);
#endif

View File

@@ -43,7 +43,8 @@ RSC=rc.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /YX /FD /c
# ADD CPP /nologo /MD /W3 /GX /Zi /O2 /I "..\include" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /FR /FD /c
# SUBTRACT CPP /YX
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "NDEBUG"
@@ -53,7 +54,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
# ADD LINK32 kernel32.lib wsock32.lib /nologo /dll /machine:I386 /out:"Release/curl.dll"
# ADD LINK32 kernel32.lib wsock32.lib /nologo /dll /map /debug /machine:I386 /out:"Release/libcurl.dll"
!ELSEIF "$(CFG)" == "curllib - Win32 Debug"
@@ -69,7 +70,8 @@ LINK32=link.exe
# PROP Ignore_Export_Lib 0
# PROP Target_Dir ""
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /YX /FD /GZ /c
# ADD CPP /nologo /MDd /W3 /Gm /GX /Zi /Od /I "..\include" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "CURLLIB_EXPORTS" /FR /FD /GZ /c
# SUBTRACT CPP /WX /YX
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
# ADD BASE RSC /l 0x409 /d "_DEBUG"
@@ -79,7 +81,7 @@ BSC32=bscmake.exe
# ADD BSC32 /nologo
LINK32=link.exe
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
# ADD LINK32 kernel32.lib wsock32.lib /nologo /dll /debug /machine:I386 /out:"Debug/curl.dll" /pdbtype:sept
# ADD LINK32 kernel32.lib wsock32.lib /nologo /dll /incremental:no /map /debug /machine:I386 /out:"Debug/libcurl.dll" /pdbtype:sept
# SUBTRACT LINK32 /nodefaultlib
!ENDIF

View File

@@ -37,7 +37,7 @@
#include "memdebug.h"
#endif
char *curl_escape(char *string, int length)
char *curl_escape(const char *string, int length)
{
int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc);
@@ -75,7 +75,7 @@ char *curl_escape(char *string, int length)
return ns;
}
char *curl_unescape(char *string, int length)
char *curl_unescape(const char *string, int length)
{
int alloc = (length?length:(int)strlen(string))+1;
char *ns = malloc(alloc);

View File

@@ -26,7 +26,7 @@
/* Escape and unescape URL encoding in strings. The functions return a new
* allocated string or NULL if an error occurred. */
char *curl_escape(char *string, int length);
char *curl_unescape(char *string, int length);
char *curl_escape(const char *string, int length);
char *curl_unescape(const char *string, int length);
#endif

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* 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.
@@ -24,7 +24,65 @@
/*
Debug the form generator stand-alone by compiling this source file with:
gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c
gcc -DHAVE_CONFIG_H -I../ -g -D_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
run the 'formdata' executable the output should end with:
All Tests seem to have worked ...
and the following parts should be there:
Content-Disposition: form-data; name="simple_COPYCONTENTS"
value for simple COPYCONTENTS
Content-Disposition: form-data; name="COPYCONTENTS_+_CONTENTTYPE"
Content-Type: image/gif
value for COPYCONTENTS + CONTENTTYPE
Content-Disposition: form-data; name="PRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH"
vlue for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH
(or you might see P^@RNAME and v^@lue at the start)
Content-Disposition: form-data; name="simple_PTRCONTENTS"
value for simple PTRCONTENTS
Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH"
vlue for PTRCONTENTS + CONTENTSLENGTH
(or you might see v^@lue at the start)
Content-Disposition: form-data; name="PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE"
Content-Type: text/plain
vlue for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE
(or you might see v^@lue at the start)
Content-Disposition: form-data; name="FILE1_+_CONTENTTYPE"; filename="inet_ntoa_r.h"
Content-Type: text/html
...
Content-Disposition: form-data; name="FILE1_+_FILE2"
Content-Type: multipart/mixed, boundary=curlz1s0dkticx49MV1KGcYP5cvfSsz
...
Content-Disposition: attachment; filename="inet_ntoa_r.h"
Content-Type: text/plain
...
Content-Disposition: attachment; filename="Makefile.b32.resp"
Content-Type: text/plain
...
Content-Disposition: form-data; name="FILE1_+_FILE2_+_FILE3"
Content-Type: multipart/mixed, boundary=curlirkYPmPwu6FrJ1vJ1u1BmtIufh1
...
Content-Disposition: attachment; filename="inet_ntoa_r.h"
Content-Type: text/plain
...
Content-Disposition: attachment; filename="Makefile.b32.resp"
Content-Type: text/plain
...
Content-Disposition: attachment; filename="inet_ntoa_r.h"
Content-Type: text/plain
...
For the old FormParse used by curl_formparse use:
gcc -DHAVE_CONFIG_H -I../ -g -D_OLD_FORM_DEBUG -o formdata -I../include formdata.c strequal.c
run the 'formdata' executable and make sure the output is ok!
@@ -64,7 +122,7 @@
/* This is a silly duplicate of the function in main.c to enable this source
to compile stand-alone for better debugging */
static void GetStr(char **string,
char *value)
const char *value)
{
if(*string)
free(*string);
@@ -227,6 +285,7 @@ int FormParse(char *input,
memset(post, 0, sizeof(struct HttpPost));
GetStr(&post->name, name); /* get the name */
GetStr(&post->contents, contp); /* get the contents */
post->contentslength = 0;
post->flags = flags;
if(type) {
GetStr(&post->contenttype, (char *)type); /* get type */
@@ -250,6 +309,7 @@ int FormParse(char *input,
memset(subpost, 0, sizeof(struct HttpPost));
GetStr(&subpost->name, name); /* get the name */
GetStr(&subpost->contents, contp); /* get the contents */
subpost->contentslength = 0;
subpost->flags = flags;
if(type) {
GetStr(&subpost->contenttype, (char *)type); /* get type */
@@ -272,10 +332,12 @@ int FormParse(char *input,
GetStr(&post->name, name); /* get the name */
if( contp[0]=='<' ) {
GetStr(&post->contents, contp+1); /* get the contents */
post->contentslength = 0;
post->flags = HTTPPOST_READFILE;
}
else {
GetStr(&post->contents, contp); /* get the contents */
post->contentslength = 0;
post->flags = 0;
}
@@ -307,6 +369,428 @@ int curl_formparse(char *input,
return FormParse(input, httppost, last_post);
}
/***************************************************************************
*
* AddHttpPost()
*
* Adds a HttpPost structure to the list, if parent_post is given becomes
* a subpost of parent_post instead of a direct list element.
*
* Returns newly allocated HttpPost on success and NULL if malloc failed.
*
***************************************************************************/
static struct HttpPost * AddHttpPost (char * name,
long namelength,
char * value,
long contentslength,
char *contenttype,
long flags,
struct HttpPost *parent_post,
struct HttpPost **httppost,
struct HttpPost **last_post)
{
struct HttpPost *post;
post = (struct HttpPost *)malloc(sizeof(struct HttpPost));
if(post) {
memset(post, 0, sizeof(struct HttpPost));
post->name = name;
post->namelength = namelength;
post->contents = value;
post->contentslength = contentslength;
post->contenttype = contenttype;
post->flags = flags;
}
else
return NULL;
if (parent_post) {
/* now, point our 'more' to the original 'more' */
post->more = parent_post->more;
/* then move the original 'more' to point to ourselves */
parent_post->more = post;
}
else {
/* make the previous point to this */
if(*last_post)
(*last_post)->next = post;
else
(*httppost) = post;
(*last_post) = post;
}
return post;
}
/***************************************************************************
*
* AddFormInfo()
*
* Adds a FormInfo structure to the list presented by parent_form_info.
*
* Returns newly allocated FormInfo on success and NULL if malloc failed/
* parent_form_info is NULL.
*
***************************************************************************/
static FormInfo * AddFormInfo (char *value,
char *contenttype,
FormInfo *parent_form_info)
{
FormInfo *form_info;
form_info = (FormInfo *)malloc(sizeof(FormInfo));
if(form_info) {
memset(form_info, 0, sizeof(FormInfo));
if (value)
form_info->value = value;
if (contenttype)
form_info->contenttype = contenttype;
form_info->flags = HTTPPOST_FILENAME;
}
else
return NULL;
if (parent_form_info) {
/* now, point our 'more' to the original 'more' */
form_info->more = parent_form_info->more;
/* then move the original 'more' to point to ourselves */
parent_form_info->more = form_info;
}
else
return NULL;
return form_info;
}
/***************************************************************************
*
* ContentTypeForFilename()
*
* Provides content type for filename if one of the known types (else
* (either the prevtype or the default is returned).
*
* Returns some valid contenttype for filename.
*
***************************************************************************/
static const char * ContentTypeForFilename (char *filename,
const char *prevtype)
{
const char *contenttype = NULL;
unsigned int i;
/*
* No type was specified, we scan through a few well-known
* extensions and pick the first we match!
*/
struct ContentType {
const char *extension;
const char *type;
};
static struct ContentType ctts[]={
{".gif", "image/gif"},
{".jpg", "image/jpeg"},
{".jpeg", "image/jpeg"},
{".txt", "text/plain"},
{".html", "text/plain"}
};
if(prevtype)
/* default to the previously set/used! */
contenttype = prevtype;
else
/* It seems RFC1867 defines no Content-Type to default to
text/plain so we don't actually need to set this: */
contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
if(strlen(filename) >= strlen(ctts[i].extension)) {
if(strequal(filename +
strlen(filename) - strlen(ctts[i].extension),
ctts[i].extension)) {
contenttype = ctts[i].type;
break;
}
}
}
/* we have a contenttype by now */
return contenttype;
}
/***************************************************************************
*
* AllocAndCopy()
*
* Copies the data currently available under *buffer using newly allocated
* buffer (that becomes *buffer). Uses buffer_length if not null, else
* uses strlen to determine the length of the buffer to be copied
*
* Returns 0 on success and 1 if the malloc failed.
*
***************************************************************************/
static int AllocAndCopy (char **buffer, int buffer_length)
{
char *src = *buffer;
int length;
if (buffer_length)
length = buffer_length;
else
length = strlen(*buffer);
*buffer = (char*)malloc(length);
if (!*buffer)
return 1;
memcpy(*buffer, src, length);
return 0;
}
/***************************************************************************
*
* FormAdd()
*
* Stores a 'name=value' formpost parameter and builds the appropriate
* linked list.
*
* Has two principal functionalities: using files and byte arrays as
* post parts. Byte arrays are either copied or just the pointer is stored
* (as the user requests) while for files only the filename and not the
* content is stored.
*
* While you may have only one byte array for each name, multiple filenames
* are allowed (and because of this feature CURLFORM_END is needed after
* using CURLFORM_FILE).
*
* Examples:
*
* Simple name/value pair with copied contents:
* curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_COPYCONTENTS, "value");
*
* name/value pair where only the content pointer is remembered:
* curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10);
* (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
*
* storing a filename (CONTENTTYPE is optional!):
* curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
* CURLFORM_END);
*
* storing multiple filenames:
* curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
* CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
*
* Returns 0 on success, 1 if the FormInfo allocation fails, 2 if one
* option is given twice for one Form, 3 if a null pointer was given for
* a char *, 4 if the allocation of a FormInfo struct failed, 5 if an
* unknown option was used, 6 if the some FormInfo is not complete (or
* has an error), 7 if a HttpPost struct cannot be allocated, and 8
* if some allocation for string copying failed.
*
***************************************************************************/
static
int FormAdd(struct HttpPost **httppost,
struct HttpPost **last_post,
va_list params)
{
FormInfo *first_form_info, *current_form_info, *form_info;
int return_value = 0;
const char *prevtype = NULL;
struct HttpPost *post = NULL;
CURLformoption next_option;
first_form_info = (FormInfo *)malloc(sizeof(struct FormInfo));
if(first_form_info) {
memset(first_form_info, 0, sizeof(FormInfo));
current_form_info = first_form_info;
}
else
return 1;
/** TODO: first check whether char * is not NULL
TODO: transfer.c
*/
while ( ((next_option = va_arg(params, CURLformoption)) != CURLFORM_END) &&
(return_value == 0) )
{
switch (next_option)
{
case CURLFORM_PTRNAME:
current_form_info->flags |= HTTPPOST_PTRNAME; /* fall through */
case CURLFORM_COPYNAME:
if (current_form_info->name)
return_value = 2;
else {
if (next_option == CURLFORM_PTRNAME)
current_form_info->name = va_arg(params, char *);
else {
char *name = va_arg(params, char *);
if (name)
current_form_info->name = name; /* store for the moment */
else
return_value = 3;
}
}
break;
case CURLFORM_NAMELENGTH:
if (current_form_info->namelength)
return_value = 2;
else
current_form_info->namelength = va_arg(params, long);
break;
case CURLFORM_PTRCONTENTS:
current_form_info->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
case CURLFORM_COPYCONTENTS:
if (current_form_info->value)
return_value = 2;
else {
if (next_option == CURLFORM_PTRCONTENTS)
current_form_info->value = va_arg(params, char *);
else {
char *value = va_arg(params, char *);
if (value)
current_form_info->value = value; /* store for the moment */
else
return_value = 3;
}
}
break;
case CURLFORM_CONTENTSLENGTH:
if (current_form_info->contentslength)
return_value = 2;
else
current_form_info->contentslength = va_arg(params, long);
break;
case CURLFORM_FILE: {
char *filename = va_arg(params, char *);
if (current_form_info->value) {
if (current_form_info->flags & HTTPPOST_FILENAME) {
if (filename) {
if (!(current_form_info = AddFormInfo (strdup(filename),
NULL, current_form_info)))
return_value = 4;
}
else
return_value = 3;
}
else
return_value = 2;
}
else {
if (filename)
current_form_info->value = strdup(filename);
else
return_value = 3;
current_form_info->flags |= HTTPPOST_FILENAME;
}
break;
}
case CURLFORM_CONTENTTYPE: {
char *contenttype = va_arg(params, char *);
if (current_form_info->contenttype) {
if (current_form_info->flags & HTTPPOST_FILENAME) {
if (contenttype) {
if (!(current_form_info = AddFormInfo (NULL,
strdup(contenttype),
current_form_info)))
return_value = 4;
}
else
return_value = 3;
}
else
return_value = 2;
}
else {
if (contenttype)
current_form_info->contenttype = strdup(contenttype);
else
return_value = 3;
}
break;
}
default:
fprintf (stderr, "got unknown CURLFORM_OPTION: %d\n", next_option);
return_value = 5;
};
};
/* go through the list, check for copleteness and if everything is
* alright add the HttpPost item otherwise set return_value accordingly */
form_info = first_form_info;
while (form_info != NULL)
{
if ( (!first_form_info->name) ||
(!form_info->value) ||
( (!form_info->namelength) &&
(form_info->flags & HTTPPOST_PTRNAME) ) ||
( (form_info->contentslength) &&
(form_info->flags & HTTPPOST_FILENAME) ) ||
( (form_info->flags & HTTPPOST_FILENAME) &&
(form_info->flags & HTTPPOST_PTRCONTENTS) )
) {
return_value = 6;
break;
}
else {
if ( (form_info->flags & HTTPPOST_FILENAME) &&
(!form_info->contenttype) ) {
/* our contenttype is missing */
form_info->contenttype
= strdup(ContentTypeForFilename(form_info->value, prevtype));
}
if ( !(form_info->flags & HTTPPOST_PTRNAME) &&
(form_info == first_form_info) ) {
/* copy name (without strdup; possibly contains null characters) */
if (AllocAndCopy(&form_info->name, form_info->namelength)) {
return_value = 8;
break;
}
}
if ( !(form_info->flags & HTTPPOST_FILENAME) &&
!(form_info->flags & HTTPPOST_PTRCONTENTS) ) {
/* copy value (without strdup; possibly contains null characters) */
if (AllocAndCopy(&form_info->value, form_info->contentslength)) {
return_value = 8;
break;
}
}
if ( (post = AddHttpPost (form_info->name, form_info->namelength,
form_info->value, form_info->contentslength,
form_info->contenttype, form_info->flags,
post, httppost,
last_post)) == NULL) {
return_value = 7;
}
if (form_info->contenttype)
prevtype = form_info->contenttype;
}
form_info = form_info->more;
};
/* and finally delete the allocated memory */
form_info = first_form_info;
while (form_info != NULL) {
FormInfo *delete_form_info;
delete_form_info = form_info;
form_info = form_info->more;
free (delete_form_info);
};
return return_value;
}
int curl_formadd(struct HttpPost **httppost,
struct HttpPost **last_post,
...)
{
va_list arg;
int result;
va_start(arg, last_post);
result = FormAdd(httppost, last_post, arg);
va_end(arg);
return result;
}
static int AddFormData(struct FormData **formp,
const void *line,
long length)
@@ -404,9 +888,9 @@ void curl_formfree(struct HttpPost *form)
if(form->more)
curl_formfree(form->more);
if(form->name)
if( !(form->flags & HTTPPOST_PTRNAME) && form->name)
free(form->name); /* free the name */
if(form->contents)
if( !(form->flags & HTTPPOST_PTRCONTENTS) && form->contents)
free(form->contents); /* free the contents */
if(form->contenttype)
free(form->contenttype); /* free the content type */
@@ -446,9 +930,12 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
/* boundary */
size += AddFormDataf(&form, "\r\n--%s\r\n", boundary);
size += AddFormDataf(&form,
"Content-Disposition: form-data; name=\"%s\"",
post->name);
size += AddFormData(&form,
"Content-Disposition: form-data; name=\"", 0);
size += AddFormData(&form, post->name, post->namelength);
size += AddFormData(&form, "\"", 0);
if(post->more) {
/* If used, this is a link to more file names, we must then do
@@ -525,7 +1012,7 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
}
} else {
/* include the contents we got */
size += AddFormData(&form, post->contents, 0);
size += AddFormData(&form, post->contents, post->contentslength);
}
} while((file = file->more)); /* for each specified file for this field */
@@ -568,6 +1055,52 @@ int Curl_FormReader(char *buffer,
size_t size,
size_t nitems,
FILE *mydata)
{
struct Form *form;
int wantedsize;
int gotsize = 0;
form=(struct Form *)mydata;
wantedsize = size * nitems;
if(!form->data)
return -1; /* nothing, error, empty */
do {
if( (form->data->length - form->sent ) > wantedsize - gotsize) {
memcpy(buffer + gotsize , form->data->line + form->sent,
wantedsize - gotsize);
form->sent += wantedsize-gotsize;
return wantedsize;
}
memcpy(buffer+gotsize,
form->data->line + form->sent,
(form->data->length - form->sent) );
gotsize += form->data->length - form->sent;
form->sent = 0;
form->data = form->data->next; /* advance */
} while(form->data);
/* If we got an empty line and we have more data, we proceed to the next
line immediately to avoid returning zero before we've reached the end.
This is the bug reported November 22 1999 on curl 6.3. (Daniel) */
return gotsize;
}
/* possible (old) fread() emulation that copies at most one line */
int Curl_FormReadOneLine(char *buffer,
size_t size,
size_t nitems,
FILE *mydata)
{
struct Form *form;
int wantedsize;
@@ -609,6 +1142,134 @@ int Curl_FormReader(char *buffer,
#ifdef _FORM_DEBUG
int FormAddTest(const char * errormsg,
struct HttpPost **httppost,
struct HttpPost **last_post,
...)
{
int result;
va_list arg;
va_start(arg, last_post);
if ((result = FormAdd(httppost, last_post, arg)))
fprintf (stderr, "ERROR doing FormAdd ret: %d action: %s\n", result,
errormsg);
va_end(arg);
return result;
}
int main()
{
char name1[] = "simple_COPYCONTENTS";
char name2[] = "COPYCONTENTS_+_CONTENTTYPE";
char name3[] = "PTRNAME_+_NAMELENGTH_+_COPYNAME_+_CONTENTSLENGTH";
char name4[] = "simple_PTRCONTENTS";
char name5[] = "PTRCONTENTS_+_CONTENTSLENGTH";
char name6[] = "PTRCONTENTS_+_CONTENTSLENGTH_+_CONTENTTYPE";
char name7[] = "FILE1_+_CONTENTTYPE";
char name8[] = "FILE1_+_FILE2";
char name9[] = "FILE1_+_FILE2_+_FILE3";
char value1[] = "value for simple COPYCONTENTS";
char value2[] = "value for COPYCONTENTS + CONTENTTYPE";
char value3[] = "value for PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH";
char value4[] = "value for simple PTRCONTENTS";
char value5[] = "value for PTRCONTENTS + CONTENTSLENGTH";
char value6[] = "value for PTRCOTNENTS + CONTENTSLENGTH + CONTENTTYPE";
char value7[] = "inet_ntoa_r.h";
char value8[] = "Makefile.b32.resp";
char type2[] = "image/gif";
char type6[] = "text/plain";
char type7[] = "text/html";
int name3length = strlen(name3);
int value3length = strlen(value3);
int value5length = strlen(value4);
int value6length = strlen(value5);
int errors = 0;
int size;
int nread;
char buffer[4096];
struct HttpPost *httppost=NULL;
struct HttpPost *last_post=NULL;
struct FormData *form;
struct Form formread;
if (FormAddTest("simple COPYCONTENTS test", &httppost, &last_post,
CURLFORM_COPYNAME, name1, CURLFORM_COPYCONTENTS, value1,
CURLFORM_END))
++errors;
if (FormAddTest("COPYCONTENTS + CONTENTTYPE test", &httppost, &last_post,
CURLFORM_COPYNAME, name2, CURLFORM_COPYCONTENTS, value2,
CURLFORM_CONTENTTYPE, type2, CURLFORM_END))
++errors;
/* make null character at start to check that contentslength works
correctly */
name3[1] = '\0';
value3[1] = '\0';
if (FormAddTest("PTRNAME + NAMELENGTH + COPYNAME + CONTENTSLENGTH test",
&httppost, &last_post,
CURLFORM_PTRNAME, name3, CURLFORM_COPYCONTENTS, value3,
CURLFORM_CONTENTSLENGTH, value3length,
CURLFORM_NAMELENGTH, name3length, CURLFORM_END))
++errors;
if (FormAddTest("simple PTRCONTENTS test", &httppost, &last_post,
CURLFORM_COPYNAME, name4, CURLFORM_PTRCONTENTS, value4,
CURLFORM_END))
++errors;
/* make null character at start to check that contentslength works
correctly */
value5[1] = '\0';
if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH test", &httppost, &last_post,
CURLFORM_COPYNAME, name5, CURLFORM_PTRCONTENTS, value5,
CURLFORM_CONTENTSLENGTH, value5length, CURLFORM_END))
++errors;
/* make null character at start to check that contentslength works
correctly */
value6[1] = '\0';
if (FormAddTest("PTRCONTENTS + CONTENTSLENGTH + CONTENTTYPE test",
&httppost, &last_post,
CURLFORM_COPYNAME, name6, CURLFORM_PTRCONTENTS, value6,
CURLFORM_CONTENTSLENGTH, value6length,
CURLFORM_CONTENTTYPE, type6, CURLFORM_END))
++errors;
if (FormAddTest("FILE + CONTENTTYPE test", &httppost, &last_post,
CURLFORM_COPYNAME, name7, CURLFORM_FILE, value7,
CURLFORM_CONTENTTYPE, type7, CURLFORM_END))
++errors;
if (FormAddTest("FILE1 + FILE2 test", &httppost, &last_post,
CURLFORM_COPYNAME, name8, CURLFORM_FILE, value7,
CURLFORM_FILE, value8, CURLFORM_END))
++errors;
if (FormAddTest("FILE1 + FILE2 + FILE3 test", &httppost, &last_post,
CURLFORM_COPYNAME, name9, CURLFORM_FILE, value7,
CURLFORM_FILE, value8, CURLFORM_FILE, value7, CURLFORM_END))
++errors;
form=Curl_getFormData(httppost, &size);
Curl_FormInit(&formread, form);
do {
nread = Curl_FormReader(buffer, 1, sizeof(buffer),
(FILE *)&formread);
if(-1 == nread)
break;
fwrite(buffer, nread, 1, stderr);
} while(1);
fprintf(stderr, "size: %d\n", size);
if (errors)
fprintf(stderr, "\n==> %d Test(s) failed!\n", errors);
else
fprintf(stdout, "\nAll Tests seem to have worked (please check output)\n");
return 0;
}
#endif
#ifdef _OLD_FORM_DEBUG
int main(int argc, char **argv)
{

View File

@@ -36,6 +36,17 @@ struct Form {
been sent in a previous invoke */
};
/* used by FormAdd for temporary storage */
typedef struct FormInfo {
char *name;
long namelength;
char *value;
long contentslength;
char *contenttype;
long flags;
struct FormInfo *more;
} FormInfo;
int Curl_FormInit(struct Form *form, struct FormData *formdata );
struct FormData *Curl_getFormData(struct HttpPost *post,
@@ -47,8 +58,15 @@ int Curl_FormReader(char *buffer,
size_t nitems,
FILE *mydata);
/* possible (old) fread() emulation that copies at most one line */
int Curl_FormReadOneLine(char *buffer,
size_t size,
size_t nitems,
FILE *mydata);
char *Curl_FormBoundary(void);
void Curl_formclean(struct FormData *);
#endif

269
lib/ftp.c
View File

@@ -151,9 +151,11 @@ static CURLcode AllowServerConnect(struct UrlData *data,
/* --- parse FTP server responses --- */
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
isdigit((int)line[2]) && (' ' == line[3]))
/*
* Curl_GetFTPResponse() is supposed to be invoked after each command sent to
* a remote FTP server. This function will wait and read all lines of the
* response and extract the relevant return code for the invoking function.
*/
int Curl_GetFTPResponse(int sockfd,
char *buf,
@@ -165,8 +167,7 @@ int Curl_GetFTPResponse(int sockfd,
* as it seems that the OpenSSL read() stuff doesn't grok that properly.
*
* Alas, read as much as possible, split up into lines, use the ending
* line in a response or continue reading.
*/
* line in a response or continue reading. */
int nread; /* total size read */
int perline; /* count bytes per line */
@@ -260,6 +261,9 @@ int Curl_GetFTPResponse(int sockfd,
/* no need to output LF here, it is part of the data */
}
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
isdigit((int)line[2]) && (' ' == line[3]))
if(perline>3 && lastline(line_start)) {
/* This is the end of the last line, copy the last
* line to the start of the buffer and zero terminate,
@@ -599,7 +603,7 @@ CURLcode _ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
ftpsendf(conn->firstsocket, conn, "%s", item->data);
nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, &ftpcode);
conn->data->buffer, conn, &ftpcode);
if (nread < 0)
return CURLE_OPERATION_TIMEOUTED;
@@ -623,7 +627,7 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path)
ftpsendf(conn->firstsocket, conn, "CWD %s", path);
nread = Curl_GetFTPResponse(conn->firstsocket,
conn->data->buffer, conn, &ftpcode);
conn->data->buffer, conn, &ftpcode);
if (nread < 0)
return CURLE_OPERATION_TIMEOUTED;
@@ -635,6 +639,90 @@ CURLcode _ftp_cwd(struct connectdata *conn, char *path)
return CURLE_OK;
}
static
CURLcode _ftp_getfiletime(struct connectdata *conn, char *file)
{
CURLcode result=CURLE_OK;
int ftpcode; /* for ftp status */
ssize_t nread;
char *buf = conn->data->buffer;
/* we have requested to get the modified-time of the file, this is yet
again a grey area as the MDTM is not kosher RFC959 */
ftpsendf(conn->firstsocket, conn, "MDTM %s", file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode == 213) {
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
&year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
time_t secs=time(NULL);
sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
year, month, day, hour, minute, second);
/* now, convert this into a time() value: */
conn->data->progress.filetime = curl_getdate(buf, &secs);
}
else {
infof(conn->data, "unsupported MDTM reply format\n");
}
}
return result;
}
static CURLcode _ftp_transfertype(struct connectdata *conn,
bool ascii)
{
struct UrlData *data = conn->data;
int ftpcode;
ssize_t nread;
char *buf=data->buffer;
ftpsendf(conn->firstsocket, conn, "TYPE %s", ascii?"A":"I");
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 200) {
failf(data, "Couldn't set %s mode",
ascii?"ASCII":"binary");
return ascii? CURLE_FTP_COULDNT_SET_ASCII:CURLE_FTP_COULDNT_SET_BINARY;
}
return CURLE_OK;
}
static
CURLcode _ftp_getsize(struct connectdata *conn, char *file,
ssize_t *size)
{
struct UrlData *data = conn->data;
int ftpcode;
ssize_t nread;
char *buf=data->buffer;
ftpsendf(conn->firstsocket, conn, "SIZE %s", file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode == 213) {
/* get the size from the ascii string: */
*size = atoi(buf+4);
}
else
return CURLE_FTP_COULDNT_GET_SIZE;
return CURLE_OK;
}
static
CURLcode _ftp(struct connectdata *conn)
{
@@ -675,40 +763,17 @@ CURLcode _ftp(struct connectdata *conn)
return result;
}
/* change directory first! */
if(ftp->dir && ftp->dir[0]) {
if ((result = _ftp_cwd(conn, ftp->dir)) != CURLE_OK)
return result;
}
/* Requested time of file? */
if(data->bits.get_filetime && ftp->file) {
/* we have requested to get the modified-time of the file, this is yet
again a grey area as the MDTM is not kosher RFC959 */
ftpsendf(conn->firstsocket, conn, "MDTM %s", ftp->file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode == 213) {
/* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
last .sss part is optional and means fractions of a second */
int year, month, day, hour, minute, second;
if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
&year, &month, &day, &hour, &minute, &second)) {
/* we have a time, reformat it */
time_t secs=time(NULL);
sprintf(buf, "%04d%02d%02d %02d:%02d:%02d",
year, month, day, hour, minute, second);
/* now, convert this into a time() value: */
data->progress.filetime = curl_getdate(buf, &secs);
}
else {
infof(data, "unsupported MDTM reply format\n");
}
}
result = _ftp_getfiletime(conn, ftp->file);
if(result)
return result;
}
/* If we have selected NOBODY, it means that we only want file information.
@@ -717,58 +782,44 @@ CURLcode _ftp(struct connectdata *conn)
/* The SIZE command is _not_ RFC 959 specified, and therefor many servers
may not support it! It is however the only way we have to get a file's
size! */
int filesize;
ssize_t filesize;
/* Some servers return different sizes for different modes, and thus we
must set the proper type before we check the size */
ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
if(result)
return result;
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 200) {
failf(data, "Couldn't set %s mode",
(data->bits.ftp_ascii)?"ASCII":"binary");
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
CURLE_FTP_COULDNT_SET_BINARY;
}
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode == 213) {
/* get the size from the ascii string: */
filesize = atoi(buf+4);
/* failing to get size is not a serious error */
result = _ftp_getsize(conn, ftp->file, &filesize);
if(CURLE_OK == result) {
sprintf(buf, "Content-Length: %d\r\n", filesize);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
/* If we asked for a time of the file and we actually got one as
well, we "emulate" a HTTP-style header in our output. */
#ifdef HAVE_STRFTIME
if(data->bits.get_filetime && data->progress.filetime) {
struct tm *tm;
if(data->bits.get_filetime && data->progress.filetime) {
struct tm *tm;
#ifdef HAVE_LOCALTIME_R
struct tm buffer;
tm = (struct tm *)localtime_r(&data->progress.filetime, &buffer);
struct tm buffer;
tm = (struct tm *)localtime_r(&data->progress.filetime, &buffer);
#else
tm = localtime(&data->progress.filetime);
#endif
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
tm);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
tm = localtime(&data->progress.filetime);
#endif
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
tm);
result = Curl_client_write(data, CLIENTWRITE_BOTH, buf, 0);
if(result)
return result;
}
#endif
return CURLE_OK;
}
@@ -1312,19 +1363,9 @@ CURLcode _ftp(struct connectdata *conn)
if(data->bits.upload) {
/* Set type to binary (unless specified ASCII) */
ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 200) {
failf(data, "Couldn't set %s mode",
(data->bits.ftp_ascii)?"ASCII":"binary");
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
CURLE_FTP_COULDNT_SET_BINARY;
}
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
if(result)
return result;
if(conn->resume_from) {
/* we're about to continue the uploading of a file */
@@ -1344,19 +1385,10 @@ CURLcode _ftp(struct connectdata *conn)
/* we could've got a specified offset from the command line,
but now we know we didn't */
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 213) {
failf(data, "Couldn't get file size: %s", buf+4);
if(CURLE_OK != _ftp_getsize(conn, ftp->file, &conn->resume_from)) {
failf(data, "Couldn't get remote file size");
return CURLE_FTP_COULDNT_GET_SIZE;
}
/* get the size from the ascii string: */
conn->resume_from = atoi(buf+4);
}
if(conn->resume_from) {
@@ -1380,8 +1412,7 @@ CURLcode _ftp(struct connectdata *conn)
passed += actuallyread;
if(actuallyread != readthisamountnow) {
failf(data, "Could only read %d bytes from the input\n",
passed);
failf(data, "Could only read %d bytes from the input\n", passed);
return CURLE_FTP_COULDNT_USE_REST;
}
}
@@ -1427,6 +1458,7 @@ CURLcode _ftp(struct connectdata *conn)
}
if(data->bits.ftp_use_port) {
/* PORT means we are now awaiting the server to connect to us. */
result = AllowServerConnect(data, conn, portsock);
if( result )
return result;
@@ -1495,16 +1527,9 @@ CURLcode _ftp(struct connectdata *conn)
dirlist = TRUE;
/* Set type to ASCII */
ftpsendf(conn->firstsocket, conn, "TYPE A");
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 200) {
failf(data, "Couldn't set ascii mode");
return CURLE_FTP_COULDNT_SET_ASCII;
}
result = _ftp_transfertype(conn, TRUE /* ASCII enforced */);
if(result)
return result;
/* if this output is to be machine-parsed, the NLST command will be
better used since the LIST command output is not specified or
@@ -1516,19 +1541,9 @@ CURLcode _ftp(struct connectdata *conn)
}
else {
/* Set type to binary (unless specified ASCII) */
ftpsendf(conn->firstsocket, conn, "TYPE %s",
(data->bits.ftp_ascii)?"A":"I");
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 200) {
failf(data, "Couldn't set %s mode",
(data->bits.ftp_ascii)?"ASCII":"binary");
return (data->bits.ftp_ascii)? CURLE_FTP_COULDNT_SET_ASCII:
CURLE_FTP_COULDNT_SET_BINARY;
}
result = _ftp_transfertype(conn, data->bits.ftp_ascii);
if(result)
return result;
if(conn->resume_from) {
@@ -1537,22 +1552,18 @@ CURLcode _ftp(struct connectdata *conn)
* We start with trying to use the SIZE command to figure out the size
* of the file we're gonna get. If we can get the size, this is by far
* the best way to know if we're trying to resume beyond the EOF. */
int foundsize=-1;
result = _ftp_getsize(conn, ftp->file, &foundsize);
ftpsendf(conn->firstsocket, conn, "SIZE %s", ftp->file);
nread = Curl_GetFTPResponse(conn->firstsocket, buf, conn, &ftpcode);
if(nread < 0)
return CURLE_OPERATION_TIMEOUTED;
if(ftpcode != 213) {
infof(data, "server doesn't support SIZE: %s", buf+4);
if(CURLE_OK != result) {
infof(data, "ftp server doesn't support SIZE");
/* We couldn't get the size and therefore we can't know if there
really is a part of the file left to get, although the server
will just close the connection when we start the connection so it
won't cause us any harm, just not make us exit as nicely. */
}
else {
int foundsize=atoi(buf+4);
/* We got a file size report, so we check that there actually is a
part of the file left to get, or else we go home. */
if(conn->resume_from< 0) {

View File

@@ -1524,9 +1524,11 @@ yyerrhandle:
the same signature as the function definition does. */
#include "getdate.h"
#ifndef WIN32 /* the windows dudes don't need these, does anyone really? */
extern struct tm *gmtime ();
extern struct tm *localtime ();
extern time_t mktime ();
#endif
/* Month and day table. */
static TABLE const MonthDayTable[] = {

View File

@@ -477,9 +477,11 @@ o_merid : /* NULL */
the same signature as the function definition does. */
#include "getdate.h"
#ifndef WIN32 /* the windows dudes don't need these, does anyone really? */
extern struct tm *gmtime ();
extern struct tm *localtime ();
extern time_t mktime ();
#endif
/* Month and day table. */
static TABLE const MonthDayTable[] = {

View File

@@ -703,6 +703,8 @@ CURLcode Curl_http(struct connectdata *conn)
}
if(HTTPREQ_POST_FORM == data->httpreq) {
char contentType[256];
int linelength=0;
if(Curl_FormInit(&http->form, http->sendit)) {
failf(data, "Internal HTTP POST error!\n");
return CURLE_HTTP_POST_ERROR;
@@ -719,15 +721,40 @@ CURLcode Curl_http(struct connectdata *conn)
add_bufferf(req_buffer,
"Content-Length: %d\r\n", http->postsize-2);
if(!checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue
to the headers which actually speeds up post operations (as
there is one packet coming back from the web server) */
add_bufferf(req_buffer,
"Expect: 100-continue\r\n");
data->bits.expect100header = TRUE;
/* Get Content-Type: line from Curl_FormReadOneLine, which happens
to always be the first line. We can know this for sure since
we always build the formpost linked list the same way! */
linelength = Curl_FormReadOneLine (contentType,
sizeof(contentType),
1,
(FILE *)&http->form);
if(linelength == -1) {
failf(data, "Could not get Content-Type header line!\n");
return CURLE_HTTP_POST_ERROR;
}
add_buffer(req_buffer, contentType, linelength);
}
/* set upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
/* fire away the whole request to the server */
data->request_size =
add_buffer_send(conn->firstsocket, conn, req_buffer);
/* setup variables for the upcoming transfer */
result = Curl_Transfer(conn, conn->firstsocket, -1, TRUE,
&http->readbytecount,
conn->firstsocket,
&http->writebytecount);
&http->readbytecount,
conn->firstsocket,
&http->writebytecount);
if(result) {
Curl_formclean(http->sendit); /* free that whole lot */
return result;

View File

@@ -1151,7 +1151,9 @@ int curl_msprintf(char *buffer, const char *format, ...)
return retcode;
}
#ifndef WIN32 /* not needed on win32 */
extern int fputc(int, FILE *);
#endif
int curl_mprintf(const char *format, ...)
{

View File

@@ -327,5 +327,8 @@ int Curl_pgrsUpdate(struct connectdata *conn)
max5data(data->progress.current_speed, max5[5]) /* current speed */
);
/* we flush the output stream to make it appear as soon as possible */
fflush(data->err);
return 0;
}

View File

@@ -96,24 +96,6 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
#endif
#endif
#if 0 /* zlib experiments are halted 17th october, 1999 (Daniel) */
#if defined(HAVE_ZLIB_H) && defined(HAVE_LIBZ)
/* Both lib and header file exist, we have libz! */
#define USE_ZLIB
#endif
#endif
#if 0
#ifdef HAVE_STRCASECMP
#define strnequal(x,y,z) !(strncasecmp)(x,y,z)
#define strequal(x,y) !(strcasecmp)(x,y)
#else
#define strnequal(x,y,z) !strnicmp(x,y,z)
#define strequal(x,y) !stricmp(x,y)
#endif
#endif
/* Below we define four functions. They should
1. close a socket
2. read from a socket

View File

@@ -278,10 +278,43 @@ void Curl_SSL_init(void)
#endif
}
/*
* This function is called when an SSL connection is closed.
*/
void Curl_SSL_Close(struct connectdata *conn)
{
if (conn->ssl.use) {
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
error queue removed.
Since error queue data structures are allocated
automatically for new threads, they must be freed when
threads are terminated in oder to avoid memory leaks.
*/
ERR_remove_state(0);
if(conn->ssl.handle) {
(void)SSL_shutdown(conn->ssl.handle);
SSL_set_connect_state(conn->ssl.handle);
SSL_free (conn->ssl.handle);
conn->ssl.handle = NULL;
}
if(conn->ssl.ctx) {
SSL_CTX_free (conn->ssl.ctx);
conn->ssl.ctx = NULL;
}
conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
}
/* Global cleanup */
void Curl_SSL_cleanup(void)
{
#ifdef USE_SSLEAY
if(init_ssl) {
/* only cleanup if we did a previous init */
@@ -295,6 +328,142 @@ void Curl_SSL_cleanup(void)
#endif
}
/*
* This sets up a session cache to the specified size.
*/
CURLcode Curl_SSL_InitSessions(struct UrlData *data, long amount)
{
struct curl_ssl_session *session;
if(data->ssl.session)
/* this is just a precaution to prevent multiple inits */
return CURLE_OK;
session = (struct curl_ssl_session *)
malloc(amount * sizeof(struct curl_ssl_session));
if(!session)
return CURLE_OUT_OF_MEMORY;
/* "blank out" the newly allocated memory */
memset(session, 0, amount * sizeof(struct curl_ssl_session));
/* store the info in the SSL section */
data->ssl.numsessions = amount;
data->ssl.session = session;
data->ssl.sessionage = 1; /* this is brand new */
return CURLE_OK;
}
/*
* Check if there's a session ID for the given connection in the cache,
* and if there's one suitable, it is returned.
*/
static int Get_SSL_Session(struct connectdata *conn,
SSL_SESSION **ssl_sessionid)
{
struct curl_ssl_session *check;
struct UrlData *data = conn->data;
long i;
for(i=0; i< data->ssl.numsessions; i++) {
check = &data->ssl.session[i];
if(!check->sessionid)
/* not session ID means blank entry */
continue;
if(strequal(conn->name, check->name) &&
(conn->remote_port == check->remote_port) ) {
/* yes, we have a session ID! */
data->ssl.sessionage++; /* increase general age */
check->age = data->ssl.sessionage; /* set this as used in this age */
*ssl_sessionid = check->sessionid;
return FALSE;
}
}
*ssl_sessionid = (SSL_SESSION *)NULL;
return TRUE;
}
/*
* Kill a single session ID entry in the cache.
*/
static int Kill_Single_Session(struct curl_ssl_session *session)
{
if(session->sessionid) {
/* defensive check */
/* free the ID */
SSL_SESSION_free(session->sessionid);
session->sessionid=NULL;
session->age = 0; /* fresh */
free(session->name);
session->name = NULL; /* no name */
return 0; /* ok */
}
else
return 1;
}
/*
* This function is called when the 'data' struct is going away. Close
* down everything and free all resources!
*/
int Curl_SSL_Close_All(struct UrlData *data)
{
int i;
for(i=0; i< data->ssl.numsessions; i++)
/* the single-killer function handles empty table slots */
Kill_Single_Session(&data->ssl.session[i]);
/* free the cache data */
free(data->ssl.session);
return 0;
}
/*
* Extract the session id and store it in the session cache.
*/
static int Store_SSL_Session(struct connectdata *conn)
{
SSL_SESSION *ssl_sessionid;
struct curl_ssl_session *store;
int i;
struct UrlData *data=conn->data; /* the mother of all structs */
int oldest_age=data->ssl.session[0].age; /* zero if unused */
/* ask OpenSSL, say please */
ssl_sessionid = SSL_get1_session(conn->ssl.handle);
/* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with
SSL_SESSION_free(3), regardless of its state. */
/* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
/* find an empty slot for us, or find the oldest */
for(i=0; (i<data->ssl.numsessions) && data->ssl.session[i].sessionid; i++) {
if(data->ssl.session[i].age < oldest_age) {
oldest_age = data->ssl.session[i].age;
store = &data->ssl.session[i];
}
}
if(i == data->ssl.numsessions)
/* cache is full, we must "kill" the oldest entry! */
Kill_Single_Session(store);
else
store = &data->ssl.session[i]; /* use this slot */
/* now init the session struct wisely */
store->sessionid = ssl_sessionid;
store->age = data->ssl.sessionage; /* set current age */
store->name = strdup(conn->name); /* clone host name */
store->remote_port = conn->remote_port; /* port number */
return 0;
}
/* ====================================================== */
CURLcode
@@ -307,6 +476,7 @@ Curl_SSLConnect(struct connectdata *conn)
int err;
char * str;
SSL_METHOD *req_method;
SSL_SESSION *ssl_sessionid=NULL;
/* mark this is being ssl enabled from here on out. */
conn->ssl.use = TRUE;
@@ -362,6 +532,17 @@ Curl_SSLConnect(struct connectdata *conn)
conn->ssl.server_cert = 0x0;
if(!conn->bits.reuse) {
/* We're not re-using a connection, check if there's a cached ID we
can/should use here! */
if(!Get_SSL_Session(conn, &ssl_sessionid)) {
/* we got a session id, use it! */
SSL_set_session(conn->ssl.handle, ssl_sessionid);
/* Informational message */
infof (data, "SSL re-using session ID\n");
}
}
/* pass the raw socket into the SSL layers */
SSL_set_fd (conn->ssl.handle, conn->firstsocket);
err = SSL_connect (conn->ssl.handle);
@@ -375,6 +556,13 @@ Curl_SSLConnect(struct connectdata *conn)
/* Informational message */
infof (data, "SSL connection using %s\n",
SSL_get_cipher(conn->ssl.handle));
if(!ssl_sessionid) {
/* Since this is not a cached session ID, then we want to stach this one
in the cache! */
Store_SSL_Session(conn);
}
/* Get server's certificate (note: beware of dynamic allocation) - opt */
/* major serious hack alert -- we should check certificates
@@ -407,7 +595,7 @@ Curl_SSLConnect(struct connectdata *conn)
return CURLE_SSL_PEER_CERTIFICATE;
}
if (strcasecmp(peer_CN, conn->hostname) != 0) {
if (!strequal(peer_CN, conn->hostname)) {
if (data->ssl.verifyhost > 1) {
failf(data, "SSL: certificate subject name '%s' does not match target host name '%s'",
peer_CN, conn->hostname);

View File

@@ -24,8 +24,14 @@
*****************************************************************************/
#include "urldata.h"
CURLcode Curl_SSLConnect(struct connectdata *conn);
/* Global SSL init */
void Curl_SSL_init(void);
/* Global SSL cleanup */
void Curl_SSL_cleanup(void);
void Curl_SSL_init(void); /* Global SSL init */
void Curl_SSL_cleanup(void); /* Global SSL cleanup */
/* init the SSL session ID cache */
CURLcode Curl_SSL_InitSessions(struct UrlData *, long);
void Curl_SSL_Close(struct connectdata *conn); /* close a SSL connection */
/* tell the SSL stuff to close down all open information regarding
connections (and thus session ID caching etc) */
int Curl_SSL_Close_All(struct UrlData *data);
#endif

View File

@@ -28,11 +28,11 @@
int curl_strequal(const char *first, const char *second)
{
#if defined(HAVE_STRCASECMP)
return !strcasecmp(first, second);
return !(strcasecmp)(first, second);
#elif defined(HAVE_STRCMPI)
return !strcmpi(first, second);
return !(strcmpi)(first, second);
#elif defined(HAVE_STRICMP)
return !stricmp(first, second);
return !(stricmp)(first, second);
#else
while (*first && *second) {
if (toupper(*first) != toupper(*second)) {

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* 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.
@@ -21,108 +21,47 @@
* $Id$
*****************************************************************************/
#include "setup.h"
#ifndef HAVE_STRTOK_R
/*
* Copyright (c) 1998 Softweyr LLC. All rights reserved.
*
* strtok_r, from Berkeley strtok
* Oct 13, 1998 by Wes Peters <wes@softweyr.com>
*
* Copyright (c) 1988, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notices, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notices, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by Softweyr LLC, the
* University of California, Berkeley, and its contributors.
*
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SOFTWEYR LLC, THE
* REGENTS, OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <stddef.h>
#include <string.h>
char *
Curl_strtok_r(char *s, const char *delim, char **last)
Curl_strtok_r(char *ptr, const char *sep, char **end)
{
char *spanp;
int c, sc;
char *tok;
if (!ptr)
/* we got NULL input so then we get our last position instead */
ptr = *end;
if (s == NULL && (s = *last) == NULL) {
return NULL;
}
/* pass all letters that are including in the separator string */
while (*ptr && strchr(sep, *ptr))
++ptr;
/*
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
*/
cont:
c = *s++;
for (spanp = (char *)delim; (sc = *spanp++) != 0; ) {
if (c == sc) {
goto cont;
if (*ptr) {
/* so this is where the next piece of string starts */
char *start = ptr;
/* set the end pointer to the first byte after the start */
*end = start + 1;
/* scan through the string to find where it ends, it ends on a
null byte or a character that exists in the separator string */
while (**end && !strchr(sep, **end))
++*end;
if (**end) {
/* the end is not a null byte */
**end = '\0'; /* zero terminate it! */
++*end; /* advance the last pointer to beyond the null byte */
}
return start; /* return the position where the string starts */
}
if (c == 0) { /* no non-delimiter characters */
*last = NULL;
return NULL;
}
tok = s - 1;
/*
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
* Note that delim must have one NUL; we stop if we see that, too.
*/
for (;;) {
c = *s++;
spanp = (char *)delim;
do {
if ((sc = *spanp++) == c) {
if (c == 0) {
s = NULL;
}
else {
char *w = s - 1;
*w = '\0';
}
*last = s;
return tok;
}
}
while (sc != 0);
}
/* NOTREACHED */
/* we ended up on a null byte, there are no more strings to find! */
return NULL;
}
#endif
#endif /* this was only compiled if strtok_r wasn't present */

View File

@@ -92,6 +92,7 @@
#include "http.h"
#include "url.h"
#include "getinfo.h"
#include "ssluse.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -197,6 +198,9 @@ Transfer(struct connectdata *c_conn)
Content-Range: header */
int httpcode = 0; /* error code from the 'HTTP/1.? XXX' line */
int httpversion = -1; /* the HTTP version*10 */
bool write_after_100_header = FALSE; /* should we enable the write after
we received a 100-continue/timeout
or directly */
/* for the low speed checks: */
CURLcode urg;
@@ -263,8 +267,13 @@ Transfer(struct connectdata *c_conn)
FD_ZERO (&writefd); /* clear it */
if(conn->writesockfd != -1) {
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
if (data->bits.expect100header)
/* wait with write until we either got 100-continue or a timeout */
write_after_100_header = TRUE;
else {
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
}
}
/* get these in backup variables to be able to restore them on each lap in
@@ -290,6 +299,12 @@ Transfer(struct connectdata *c_conn)
keepon = 0; /* no more read or write */
continue;
case 0: /* timeout */
if (write_after_100_header) {
write_after_100_header = FALSE;
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
wkeepfd = writefd;
}
break;
default:
if((keepon & KEEP_READ) && FD_ISSET(conn->sockfd, &readfd)) {
@@ -408,10 +423,29 @@ Transfer(struct connectdata *c_conn)
*/
header = TRUE;
headerline = 0; /* we restart the header line counter */
/* if we did wait for this do enable write now! */
if (write_after_100_header) {
write_after_100_header = FALSE;
FD_SET (conn->writesockfd, &writefd); /* write socket */
keepon |= KEEP_WRITE;
wkeepfd = writefd;
}
}
else
else
header = FALSE; /* no more header to parse! */
if (417 == httpcode) {
/*
* we got: "417 Expectation Failed" this means:
* we have made a HTTP call and our Expect Header
* seems to cause a problem => abort the write operations
* (or prevent them from starting
*/
write_after_100_header = FALSE;
keepon &= ~KEEP_WRITE;
FD_ZERO(&wkeepfd);
}
/* now, only output this if the header AND body are requested:
*/
writetype = CLIENTWRITE_HEADER;
@@ -875,6 +909,13 @@ CURLcode Curl_perform(struct UrlData *data)
/* we can't do anything wihout URL */
return CURLE_URL_MALFORMAT;
#ifdef USE_SSLEAY
/* Init the SSL session ID cache here. We do it here since we want to
do it after the *_setopt() calls (that could change the size) but
before any transfer. */
Curl_SSL_InitSessions(data, data->ssl.numsessions);
#endif
data->followlocation=0; /* reset the location-follow counter */
data->bits.this_is_a_follow = FALSE; /* reset this */

View File

@@ -148,6 +148,11 @@ CURLcode Curl_close(struct UrlData *data)
/* Loop through all open connections and kill them one by one */
while(-1 != ConnectionKillOne(data));
#ifdef USE_SSLEAY
/* Close down all open info open SSL and sessions */
Curl_SSL_Close_All(data);
#endif
if(data->bits.proxystringalloc) {
data->bits.proxystringalloc=FALSE;;
free(data->proxy);
@@ -173,6 +178,10 @@ CURLcode Curl_close(struct UrlData *data)
/* the URL is allocated, free it! */
free(data->url);
if(data->cookiejar)
/* we have a "destination" for all the cookies to get dumped to */
Curl_cookie_output(data->cookies, data->cookiejar);
Curl_cookie_cleanup(data->cookies);
/* free the connection cache */
@@ -242,6 +251,9 @@ CURLcode Curl_open(struct UrlData **curl)
data->bits.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
data->progress.flags |= PGRS_HIDE;
/* Set the default size of the SSL session ID cache */
data->ssl.numsessions = 5;
/* create an array with connection data struct pointers */
data->numconnects = 5; /* hard-coded right now */
data->connects = (struct connectdata **)
@@ -430,9 +442,12 @@ CURLcode Curl_setopt(struct UrlData *data, CURLoption option, ...)
*/
data->bits.http_follow_location = va_arg(param, long)?TRUE:FALSE;
break;
case CURLOPT_FTPASCII:
case CURLOPT_TRANSFERTEXT:
/*
* Transfer FTP using ASCII instead of BINARY.
* This option was previously named 'FTPASCII'. Renamed to work with
* more protocols than merely FTP.
*
* Transfer using ASCII (instead of BINARY).
*/
data->bits.ftp_ascii = va_arg(param, long)?TRUE:FALSE;
break;
@@ -477,12 +492,18 @@ CURLcode Curl_setopt(struct UrlData *data, CURLoption option, ...)
case CURLOPT_COOKIEFILE:
/*
* Set cookie file to read and parse.
* Set cookie file to read and parse. Can be used multiple times.
*/
cookiefile = (char *)va_arg(param, void *);
if(cookiefile) {
data->cookies = Curl_cookie_init(cookiefile);
}
if(cookiefile)
data->cookies = Curl_cookie_init(cookiefile, data->cookies);
break;
case CURLOPT_COOKIEJAR:
/*
* Set cookie file name to dump all cookies to when we're done.
*/
data->cookiejar = cookiefile = (char *)va_arg(param, void *);
break;
case CURLOPT_WRITEHEADER:
/*
@@ -579,6 +600,11 @@ CURLcode Curl_setopt(struct UrlData *data, CURLoption option, ...)
/*
* The URL to fetch.
*/
if(data->bits.urlstringalloc) {
/* the already set URL is allocated, free it first! */
free(data->url);
data->bits.urlstringalloc=FALSE;
}
data->url = va_arg(param, char *);
break;
case CURLOPT_PORT:
@@ -625,6 +651,13 @@ CURLcode Curl_setopt(struct UrlData *data, CURLoption option, ...)
/*
* Set proxy server:port to use as HTTP proxy
*/
if(data->bits.proxystringalloc) {
/*
* The already set string is allocated, free that first
*/
data->bits.proxystringalloc=FALSE;;
free(data->proxy);
}
data->proxy = va_arg(param, char *);
data->bits.httpproxy = data->proxy?1:0;
break;
@@ -861,31 +894,7 @@ CURLcode Curl_disconnect(struct connectdata *conn)
free(conn->path);
#ifdef USE_SSLEAY
if (conn->ssl.use) {
/*
ERR_remove_state() frees the error queue associated with
thread pid. If pid == 0, the current thread will have its
error queue removed.
Since error queue data structures are allocated
automatically for new threads, they must be freed when
threads are terminated in oder to avoid memory leaks.
*/
ERR_remove_state(0);
if(conn->ssl.handle) {
(void)SSL_shutdown(conn->ssl.handle);
SSL_set_connect_state(conn->ssl.handle);
SSL_free (conn->ssl.handle);
conn->ssl.handle = NULL;
}
if(conn->ssl.ctx) {
SSL_CTX_free (conn->ssl.ctx);
conn->ssl.ctx = NULL;
}
conn->ssl.use = FALSE; /* get back to ordinary socket usage */
}
Curl_SSL_Close(conn);
#endif /* USE_SSLEAY */
/* close possibly still open sockets */

View File

@@ -125,6 +125,14 @@ struct ssl_connect_data {
#endif /* USE_SSLEAY */
};
/* information about one single SSL session */
struct curl_ssl_session {
char *name; /* host name for which this ID was used */
void *sessionid; /* as returned from the SSL layer */
long age; /* just a number, the higher the more recent */
unsigned short remote_port; /* remote port to connect to */
};
struct ssl_config_data {
long version; /* what version the client wants to use */
long certverifyresult; /* result from the certificate verification */
@@ -134,6 +142,10 @@ struct ssl_config_data {
char *CAfile; /* cerficate to verify peer against */
char *random_file; /* path to file containing "random" data */
char *egdsocket; /* path to file containing the EGD daemon socket */
struct curl_ssl_session *session; /* array of 'numsessions' size */
long numsessions; /* SSL session id cache size */
long sessionage; /* number of the most recent session */
};
/****************************************************************************
@@ -413,6 +425,8 @@ struct Configbits {
after use */
bool reuse_fresh; /* do not re-use an existing connection for this
transfer */
bool expect100header; /* TRUE if we added Expect: 100-continue to the
HTTP header */
};
/*
@@ -528,6 +542,7 @@ struct UrlData {
char *cert_passwd; /* plain text certificate password */
struct CookieInfo *cookies;
char *cookiejar; /* dump all cookies to this file */
long crlf;
struct curl_slist *quote; /* before the transfer */

View File

@@ -76,6 +76,12 @@ else
automake --include-deps Makefile
fi
############################################################################
#
# Make sure we have updated HTML versions of all man pages:
#
make html
############################################################################
#
# Now run make dist

133
missing
View File

@@ -1,7 +1,7 @@
#! /bin/sh
# Common stub for a few missing GNU programs while installing.
# Copyright (C) 1996, 1997 Free Software Foundation, Inc.
# Franc,ois Pinard <pinard@iro.umontreal.ca>, 1996.
# Copyright 1996, 1997, 1999, 2000 Free Software Foundation, Inc.
# Originally by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,11 +18,37 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
# As a special exception to the GNU General Public License, if you
# distribute this file as part of a program that contains a
# configuration script generated by Autoconf, you may include it under
# the same distribution terms that you use for the rest of that program.
if test $# -eq 0; then
echo 1>&2 "Try \`$0 --help' for more information"
exit 1
fi
run=:
# In the cases where this matters, `missing' is being run in the
# srcdir already.
if test -f configure.ac; then
configure_ac=configure.ac
else
configure_ac=configure.in
fi
case "$1" in
--run)
# Try to run requested program, and just exit if it succeeds.
run=
shift
"$@" && exit 0
;;
esac
# If it does not exist, or fails to run (possibly an outdated version),
# try to emulate it.
case "$1" in
-h|--h|--he|--hel|--help)
@@ -35,6 +61,7 @@ error status if there is no known handling for PROGRAM.
Options:
-h, --help display this help and exit
-v, --version output version information and exit
--run try to run the given command, and emulate it if it fails
Supported PROGRAM values:
aclocal touch file \`aclocal.m4'
@@ -43,13 +70,15 @@ Supported PROGRAM values:
automake touch all \`Makefile.in' files
bison create \`y.tab.[ch]', if possible, from existing .[ch]
flex create \`lex.yy.c', if possible, from existing .c
help2man touch the output file
lex create \`lex.yy.c', if possible, from existing .c
makeinfo touch the output file
tar try tar, gnutar, gtar, then tar without non-portable flags
yacc create \`y.tab.[ch]', if possible, from existing .[ch]"
;;
-v|--v|--ve|--ver|--vers|--versi|--versio|--version)
echo "missing - GNU libit 0.0"
echo "missing 0.3 - GNU automake"
;;
-*)
@@ -61,7 +90,7 @@ Supported PROGRAM values:
aclocal)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acinclude.m4' or \`configure.in'. You might want
you modified \`acinclude.m4' or \`${configure_ac}'. You might want
to install the \`Automake' and \`Perl' packages. Grab them from
any GNU archive site."
touch aclocal.m4
@@ -70,7 +99,7 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoconf)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`configure.in'. You might want to install the
you modified \`${configure_ac}'. You might want to install the
\`Autoconf' and \`GNU m4' packages. Grab them from any GNU
archive site."
touch configure
@@ -79,29 +108,31 @@ WARNING: \`$1' is missing on your system. You should only need it if
autoheader)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`acconfig.h' or \`configure.in'. You might want
you modified \`acconfig.h' or \`${configure_ac}'. You might want
to install the \`Autoconf' and \`GNU m4' packages. Grab them
from any GNU archive site."
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER([^):]*:\([^)]*\)).*/\1/p' configure.in`
if test -z "$files"; then
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^):]*\)).*/\1/p' configure.in`
test -z "$files" || files="$files.in"
else
files=`echo "$files" | sed -e 's/:/ /g'`
fi
test -z "$files" && files="config.h.in"
touch $files
files=`sed -n 's/^[ ]*A[CM]_CONFIG_HEADER(\([^)]*\)).*/\1/p' ${configure_ac}`
test -z "$files" && files="config.h"
touch_files=
for f in $files; do
case "$f" in
*:*) touch_files="$touch_files "`echo "$f" |
sed -e 's/^[^:]*://' -e 's/:.*//'`;;
*) touch_files="$touch_files $f.in";;
esac
done
touch $touch_files
;;
automake)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified \`Makefile.am', \`acinclude.m4' or \`configure.in'.
you modified \`Makefile.am', \`acinclude.m4' or \`${configure_ac}'.
You might want to install the \`Automake' and \`Perl' packages.
Grab them from any GNU archive site."
find . -type f -name Makefile.am -print \
| sed 's/^\(.*\).am$/touch \1.in/' \
| sh
find . -type f -name Makefile.am -print |
sed 's/\.am$/.in/' |
while read f; do touch "$f"; done
;;
bison|yacc)
@@ -157,7 +188,32 @@ WARNING: \`$1' is missing on your system. You should only need it if
fi
;;
help2man)
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a dependency of a manual page. You may need the
\`Help2man' package in order for those modifications to take
effect. You can get \`Help2man' from any GNU archive site."
file=`echo "$*" | sed -n 's/.*-o \([^ ]*\).*/\1/p'`
if test -z "$file"; then
file=`echo "$*" | sed -n 's/.*--output=\([^ ]*\).*/\1/p'`
fi
if [ -f "$file" ]; then
touch $file
else
test -z "$file" || exec >$file
echo ".ab help2man is required to generate this page"
exit 1
fi
;;
makeinfo)
if test -z "$run" && (makeinfo --version) > /dev/null 2>&1; then
# We have makeinfo, but it failed.
exit 1
fi
echo 1>&2 "\
WARNING: \`$1' is missing on your system. You should only need it if
you modified a \`.texi' or \`.texinfo' file, or any other file
@@ -173,6 +229,45 @@ WARNING: \`$1' is missing on your system. You should only need it if
touch $file
;;
tar)
shift
if test -n "$run"; then
echo 1>&2 "ERROR: \`tar' requires --run"
exit 1
fi
# We have already tried tar in the generic part.
# Look for gnutar/gtar before invocation to avoid ugly error
# messages.
if (gnutar --version > /dev/null 2>&1); then
gnutar ${1+"$@"} && exit 0
fi
if (gtar --version > /dev/null 2>&1); then
gtar ${1+"$@"} && exit 0
fi
firstarg="$1"
if shift; then
case "$firstarg" in
*o*)
firstarg=`echo "$firstarg" | sed s/o//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
case "$firstarg" in
*h*)
firstarg=`echo "$firstarg" | sed s/h//`
tar "$firstarg" ${1+"$@"} && exit 0
;;
esac
fi
echo 1>&2 "\
WARNING: I can't seem to be able to run \`tar' with the given arguments.
You may want to install GNU tar or Free paxutils, or check the
command line arguments."
exit 1
;;
*)
echo 1>&2 "\
WARNING: \`$1' is needed, and you do not seem to have it handy on your

View File

@@ -301,7 +301,8 @@ static void help(void)
" -b/--cookie <name=string/file> Cookie string or file to read cookies from (H)\n"
" -B/--use-ascii Use ASCII/text transfer\n",
curl_version());
puts(" -C/--continue-at <offset> Specify absolute resume offset\n"
puts(" -c/--cookie-jar <file> Write all cookies to this file after operation (H)\n"
" -C/--continue-at <offset> Specify absolute resume offset\n"
" -d/--data <data> HTTP POST data (H)\n"
" --data-ascii <data> HTTP POST ASCII data (H)\n"
" --data-binary <data> HTTP POST binary data (H)\n"
@@ -314,9 +315,9 @@ static void help(void)
" -f/--fail Fail silently (no output at all) on errors (H)\n"
" -F/--form <name=content> Specify HTTP POST data (H)\n"
" -g/--globoff Disable URL sequences and ranges using {} and []\n"
" -G/--get Send the -d data with a HTTP GET (H)\n");
" -G/--get Send the -d data with a HTTP GET (H)");
puts(" -h/--help This help text\n"
" -H/--header <line> Custom header to pass to server. (H)"
" -H/--header <line> Custom header to pass to server. (H)\n"
" -i/--include Include the HTTP-header in the output (H)\n"
" -I/--head Fetch document info only (HTTP HEAD/FTP SIZE)\n"
" --interface <interface> Specify the interface to be used\n"
@@ -369,7 +370,9 @@ struct Configurable {
char *random_file;
char *egd_file;
char *useragent;
char *cookie;
char *cookie; /* single line with specified cookies */
char *cookiejar; /* write to this file */
char *cookiefile; /* read from this file */
bool use_resume;
bool resume_from_current;
int resume_from;
@@ -405,7 +408,6 @@ struct Configurable {
char *cacert;
char *cert_passwd;
bool crlf;
char *cookiefile;
char *customrequest;
char *krb4level;
bool progressmode;
@@ -601,7 +603,7 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
{"b", "cookie", TRUE},
{"B", "ftp-ascii", FALSE}, /* this long format is OBSOLETE now! */
{"B", "use-ascii", FALSE},
{"c", "continue", FALSE},
{"c", "cookie-jar", TRUE},
{"C", "continue-at", TRUE},
{"d", "data", TRUE},
{"da", "data-ascii", TRUE},
@@ -816,9 +818,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
config->conf ^= CONF_GETTEXT;
break;
case 'c':
/* This makes us continue an ftp transfer */
config->use_resume^=TRUE;
fprintf(stderr, "-c is a deprecated switch, use '-C -' instead!\n");
/* get the file name to dump all cookies in */
GetStr(&config->cookiejar, nextarg);
break;
case 'C':
/* This makes us continue an ftp transfer at given position */
@@ -1654,7 +1655,8 @@ operate(struct Configurable *config, int argc, char *argv[])
httpgetfields = strdup(config->postfields);
free(config->postfields);
config->postfields = NULL;
if(SetHTTPrequest(HTTPREQ_GET, &config->httpreq)) {
if(SetHTTPrequest((config->conf&CONF_NOBODY?HTTPREQ_HEAD:HTTPREQ_GET),
&config->httpreq)) {
free(httpgetfields);
return PARAM_BAD_USE;
}
@@ -1858,12 +1860,22 @@ operate(struct Configurable *config, int argc, char *argv[])
if (httpgetfields) {
/* Find out whether the url contains a file name */
char *pc =strstr(url, "://");
char separator='?';
if(pc)
pc+=3;
else
pc=url;
pc = strrchr(pc, '/');
pc = strrchr(pc, '/'); /* check for a slash */
if(pc) {
/* there is a slash present in the URL */
if(strchr(pc, '?'))
/* Ouch, there's already a question mark in the URL string, we
then appead the data with an amperand separator instead! */
separator='&';
}
/*
* Then append ? followed by the get fields to the url.
*/
@@ -1872,12 +1884,12 @@ operate(struct Configurable *config, int argc, char *argv[])
helpf("out of memory\n");
return CURLE_OUT_OF_MEMORY;
}
/* Append / before the ? to create a well-formed url
if the url contains a hostname only
*/
if (pc)
sprintf(urlbuffer, "%s?%s", url, httpgetfields);
sprintf(urlbuffer, "%s%c%s", url, separator, httpgetfields);
else
/* Append / before the ? to create a well-formed url
if the url contains a hostname only
*/
sprintf(urlbuffer, "%s/?%s", url, httpgetfields);
free(url); /* free previous URL */
@@ -1971,6 +1983,8 @@ operate(struct Configurable *config, int argc, char *argv[])
curl_easy_setopt(curl, CURLOPT_WRITEHEADER,
config->headerfile?&heads:NULL);
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, config->cookiefile);
/* cookie jar was added in 7.9 */
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, config->cookiejar);
curl_easy_setopt(curl, CURLOPT_SSLVERSION, config->ssl_version);
curl_easy_setopt(curl, CURLOPT_TIMECONDITION, config->timecond);
curl_easy_setopt(curl, CURLOPT_TIMEVALUE, config->condtime);

View File

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

View File

@@ -10,4 +10,4 @@ test10 test105 test14 test2 test22 test300 test6 \
test100 test106 test15 test20 test23 test33 test7 \
test101 test107 test16 test200 test24 test4 test8 \
test102 test11 test17 test201 test25 test400 test9 \
test103 test12 test18 test202 test26 test43
test103 test12 test18 test202 test26 test43 test44

60
tests/data/test44 Normal file
View File

@@ -0,0 +1,60 @@
# Server-side
<reply>
<data>
HTTP/1.1 200 OK
Date: Thu, 09 Nov 2010 14:49:00 GMT
Server: test-server/fake
blablabla
</data>
</reply>
# Client-side
<client>
<name>
HTTP RFC1867-type formposting without Expect: header
</name>
<command>
http://%HOSTIP:%HOSTPORT/we/want/44 -F name=daniel -F tool=curl -F file=@log/test44.txt -H 'Expect:'
</command>
# We create this file before the command is invoked!
<file name="log/test44.txt">
foo-
This is a moo-
bar
</file>
</test>
# Verify data after the test has been "shot"
<verify>
<strip>
^(User-Agent:|Content-Type: multipart/form-data;|--curl).*
</strip>
<protocol>
POST /we/want/44 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Content-Length: 376
Content-Type: multipart/form-data; boundary=curluczemxkcWWsxptLlAImrFQHwQ3W
--curluczemxkcWWsxptLlAImrFQHwQ3W
Content-Disposition: form-data; name="name"
daniel
--curluczemxkcWWsxptLlAImrFQHwQ3W
Content-Disposition: form-data; name="tool"
curl
--curluczemxkcWWsxptLlAImrFQHwQ3W
Content-Disposition: form-data; name="file"; filename="log/test44.txt"
Content-Type: text/plain
foo-
This is a moo-
bar
--curluczemxkcWWsxptLlAImrFQHwQ3W--
</protocol>
</verify>

View File

@@ -41,7 +41,7 @@ GET /we/want/8 HTTP/1.1
Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Cookie: foobar=name; partmatch=present
Cookie: partmatch=present; foobar=name
</protocol>
</verify>

View File

@@ -37,6 +37,7 @@ Host: 127.0.0.1:8999
Pragma: no-cache
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, */*
Content-Length: 375
Expect: 100-continue
Content-Type: multipart/form-data; boundary=curluczemxkcWWsxptLlAImrFQHwQ3W
--curluczemxkcWWsxptLlAImrFQHwQ3W

View File

@@ -741,6 +741,11 @@ do {
# verbose output
$verbose=1;
}
elsif ($ARGV[0] eq "-c") {
# use this path to curl instead of default
$CURL=$ARGV[1];
shift @ARGV;
}
elsif ($ARGV[0] eq "-d") {
# have the servers display protocol output
$debugprotocol=1;