Compare commits
52 Commits
curl-7_8_1
...
before_url
Author | SHA1 | Date | |
---|---|---|---|
![]() |
26983053c4 | ||
![]() |
8e0043165a | ||
![]() |
c13dbf7bae | ||
![]() |
a2b6ef3478 | ||
![]() |
b6526af442 | ||
![]() |
4edba42c7c | ||
![]() |
1180ef4b31 | ||
![]() |
94bf462473 | ||
![]() |
233b3f718f | ||
![]() |
0452fd8657 | ||
![]() |
613eafaf02 | ||
![]() |
725bd1dddf | ||
![]() |
9835629801 | ||
![]() |
3c52c53ddd | ||
![]() |
321ba15a82 | ||
![]() |
9e5dfc15ac | ||
![]() |
8d52681e1d | ||
![]() |
56f6815d3d | ||
![]() |
ce07e79f3c | ||
![]() |
723ced9336 | ||
![]() |
73417b59c7 | ||
![]() |
f4e2774ab8 | ||
![]() |
d5112c0dec | ||
![]() |
aace68c91b | ||
![]() |
4034f31823 | ||
![]() |
5323340cae | ||
![]() |
3aae2ec511 | ||
![]() |
df09214c62 | ||
![]() |
12acab9b86 | ||
![]() |
c9c2115088 | ||
![]() |
d73d28a75b | ||
![]() |
13bf964b78 | ||
![]() |
3fb9c5727c | ||
![]() |
b69f33ed44 | ||
![]() |
56e8d073bf | ||
![]() |
83a8786fe1 | ||
![]() |
e3d7cc895b | ||
![]() |
0f425b01aa | ||
![]() |
c5a4b52d83 | ||
![]() |
fc2d24105c | ||
![]() |
6704d44dd4 | ||
![]() |
3d9aeccc90 | ||
![]() |
08655d8d5d | ||
![]() |
3e5dbac7a2 | ||
![]() |
05d9c9b849 | ||
![]() |
4c2fb64e21 | ||
![]() |
46a897f604 | ||
![]() |
d4b23198fa | ||
![]() |
6581663687 | ||
![]() |
4398151fd5 | ||
![]() |
d5fbfa3d0b | ||
![]() |
3a588fc9e7 |
72
CHANGES
72
CHANGES
@@ -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
|
||||
|
@@ -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
2
README
@@ -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.
|
||||
|
BIN
build_vms.com
BIN
build_vms.com
Binary file not shown.
@@ -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
|
||||
|
@@ -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
|
||||
|
10
docs/FAQ
10
docs/FAQ
@@ -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?
|
||||
|
||||
|
117
docs/LIBCURL
117
docs/LIBCURL
@@ -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.
|
||||
|
@@ -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)
|
||||
|
28
docs/TODO
28
docs/TODO
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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
121
docs/curl_formadd.3
Normal 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!
|
||||
|
@@ -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.
|
||||
|
@@ -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!
|
||||
|
@@ -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
|
||||
|
@@ -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
88
docs/examples/ftpupload.c
Normal 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
92
docs/examples/postit2.c
Normal 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;
|
||||
}
|
@@ -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
|
||||
|
@@ -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 {
|
||||
|
@@ -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.
|
||||
|
@@ -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
|
||||
|
@@ -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>
|
||||
|
||||
|
192
lib/cookie.c
192
lib/cookie.c
@@ -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
|
||||
|
14
lib/cookie.h
14
lib/cookie.h
@@ -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
|
||||
|
@@ -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
|
||||
|
@@ -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);
|
||||
|
@@ -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
|
||||
|
679
lib/formdata.c
679
lib/formdata.c
@@ -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)
|
||||
{
|
||||
|
@@ -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
269
lib/ftp.c
@@ -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) {
|
||||
|
@@ -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[] = {
|
||||
|
@@ -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[] = {
|
||||
|
33
lib/http.c
33
lib/http.c
@@ -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;
|
||||
|
@@ -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, ...)
|
||||
{
|
||||
|
@@ -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;
|
||||
}
|
||||
|
18
lib/setup.h
18
lib/setup.h
@@ -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
|
||||
|
190
lib/ssluse.c
190
lib/ssluse.c
@@ -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);
|
||||
|
14
lib/ssluse.h
14
lib/ssluse.h
@@ -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
|
||||
|
@@ -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)) {
|
||||
|
121
lib/strtok.c
121
lib/strtok.c
@@ -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 */
|
||||
|
||||
|
@@ -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 */
|
||||
|
||||
|
71
lib/url.c
71
lib/url.c
@@ -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 */
|
||||
|
@@ -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 */
|
||||
|
6
maketgz
6
maketgz
@@ -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
133
missing
@@ -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
|
||||
|
44
src/main.c
44
src/main.c
@@ -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);
|
||||
|
@@ -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 ") "
|
||||
|
@@ -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
60
tests/data/test44
Normal 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>
|
@@ -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>
|
||||
|
@@ -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
|
||||
|
@@ -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;
|
||||
|
Reference in New Issue
Block a user