Compare commits

...

219 Commits

Author SHA1 Message Date
Daniel Stenberg
d9c244278d 7.9.5-pre4 commit 2002-02-26 07:59:43 +00:00
Daniel Stenberg
b6c4185b27 more custom stuff, much about dealing with cookies 2002-02-25 15:25:34 +00:00
Daniel Stenberg
5896d35e72 a never ending stream of things to do... 2002-02-25 14:09:31 +00:00
Daniel Stenberg
b4dfdd8bbc use env to run perl 2002-02-25 14:08:51 +00:00
Daniel Stenberg
e6ed3478ea automake usage and options cleanup 2002-02-25 14:08:18 +00:00
Daniel Stenberg
db08d9c6b9 happy new year 2002-02-25 13:25:33 +00:00
Daniel Stenberg
9490278ece We got this web server's embryo from Georg Horn, muchos gracias. 2002-02-25 12:49:21 +00:00
Daniel Stenberg
fd8bf5f171 the test suite http server is now automake'd 2002-02-25 12:45:48 +00:00
Daniel Stenberg
c9bc14a222 use the pid file, use the automake subdir 2002-02-25 12:45:20 +00:00
Daniel Stenberg
63708cbfb0 automake this dir too 2002-02-25 12:44:58 +00:00
Daniel Stenberg
d9f307623c use the former logfile name again since the ftp server also uses that... 2002-02-25 12:14:24 +00:00
Daniel Stenberg
540f77a627 we actually ran all tests just now, feb 25th, 2002 12:11 MET. with the
new http server on Linux
2002-02-25 11:12:10 +00:00
Daniel Stenberg
71bb2d0b8b reply/postcmd support for "wait" 2002-02-25 11:11:03 +00:00
Daniel Stenberg
87dc44e434 portability, step one, use a config.h.in file 2002-02-25 11:00:16 +00:00
Daniel Stenberg
29e0fcd091 generate a config file for the test suite http server too 2002-02-25 10:56:37 +00:00
Daniel Stenberg
2e9a798f09 create the pidfile and store the pid on invoke 2002-02-25 10:27:29 +00:00
Daniel Stenberg
b32a39f44f oops, #if not #ifdef 2002-02-25 10:12:04 +00:00
Daniel Stenberg
d86f9611b3 support HUGE requests too 2002-02-25 09:42:58 +00:00
Daniel Stenberg
6a62fc4a40 make sure -d is treated as a POST request and thus should fail if mixed
with -I for example
2002-02-25 09:08:28 +00:00
Daniel Stenberg
7cdd6455d7 modified the command to fail properly! ;-) 2002-02-25 09:07:26 +00:00
Daniel Stenberg
e4fefd088d cygnus can't include winsock.h even though it has it, why we need to
make a different and more complicated check for when to include it
2002-02-25 08:20:29 +00:00
Daniel Stenberg
95e601e2b1 "Yet Another Geek" made %{content_type} work in the -w/--writeout option. 2002-02-25 07:40:49 +00:00
Daniel Stenberg
b1ffe7b74a better time selection for the connect timeout 2002-02-22 15:44:37 +00:00
Daniel Stenberg
417c8fb602 16 tests OK 2002-02-22 15:40:17 +00:00
Daniel Stenberg
85efa64c31 cut off big parts of the banner 2002-02-22 15:17:41 +00:00
Daniel Stenberg
d8cb026e80 make sure the custom config-*.h files are in the dist as well 2002-02-22 15:12:17 +00:00
Daniel Stenberg
41dd5121f0 adjusted to work on test case 11 better 2002-02-22 13:54:06 +00:00
Daniel Stenberg
94482d7ca5 use -W too 2002-02-22 13:53:41 +00:00
Daniel Stenberg
4d0e51aead fixed to work with 'nonewline' and thus this passes OK with the new http
server and things
2002-02-22 10:51:19 +00:00
Daniel Stenberg
ae8a8c8ba4 support for using protocol without a trailing newline 2002-02-22 10:50:36 +00:00
Daniel Stenberg
7d043f46d5 hide debug output from screen, use log/ for logfiles 2002-02-22 10:40:05 +00:00
Daniel Stenberg
cbca19d6c2 lib/config.h.in added to dist 2002-02-22 07:51:23 +00:00
Daniel Stenberg
b40b9677b6 VMS adjustments 2002-02-20 23:24:04 +00:00
Daniel Stenberg
c80ad865db new from Nico! 2002-02-20 13:48:03 +00:00
Daniel Stenberg
758eae49ab four more bugfixes, one VMS adjustment 2002-02-20 13:47:36 +00:00
Daniel Stenberg
721b05e343 Nico Baggus' VMS tweaks 2002-02-20 13:46:53 +00:00
Daniel Stenberg
a333bddeeb Andrs Garca solved bug report #515228 by making sure the progress meter
is updated even if everything is read in one single pass, as the windows
functions apparantly does more often than other systems.
2002-02-20 13:38:34 +00:00
Daniel Stenberg
4c6a52fe90 corrected reference to multi-using examples 2002-02-19 11:02:01 +00:00
Daniel Stenberg
792d73a9cf include winsock.h on window boxen to work smoother there 2002-02-19 11:00:34 +00:00
Daniel Stenberg
9a95a3f8c3 moved the config.h to lib/config.h 2002-02-19 01:06:56 +00:00
Daniel Stenberg
485edb777f a minor step forwards 2002-02-19 01:04:46 +00:00
Daniel Stenberg
a8c3431ae9 use the new HTTP server input file 2002-02-19 01:04:31 +00:00
Daniel Stenberg
6fe4a6fa9a cut off the old perl one, this only runs the C coded version 2002-02-19 01:03:45 +00:00
Daniel Stenberg
6d8c7356d6 fixed the huge text just in case anyone actually reads it 2002-02-19 00:26:44 +00:00
Daniel Stenberg
a782c96e81 no .. in path 2002-02-19 00:26:25 +00:00
Daniel Stenberg
c795123cd5 fixed a long long mistake 2002-02-18 23:32:45 +00:00
Daniel Stenberg
0ec370e6fb auth on multiple hosts with follow-location 2002-02-18 23:17:57 +00:00
Daniel Stenberg
3d5732d4e0 Rick Richardson's getaddrinfo() usage fix to speed up name resolves 2002-02-18 23:12:37 +00:00
Daniel Stenberg
b795929858 INADDR_NONE should be in_addr_t to work with 64bit archs better.
Really, we should only #define this in one file, not both here and in
connect.c!
2002-02-18 22:59:26 +00:00
Daniel Stenberg
535258ffe4 Philip Gladstone's size problem in add_buffer_send() 2002-02-18 22:41:52 +00:00
Daniel Stenberg
cc161b96ac 4 fixes 2002-02-18 10:51:50 +00:00
Daniel Stenberg
5c4b422b18 offer SSL verfication callback,
add 'headers=' in client formpost
2002-02-18 10:51:28 +00:00
Daniel Stenberg
89bad584c3 updated LDAP URL syntax references by Aron Roberts 2002-02-18 10:47:27 +00:00
Daniel Stenberg
e21926f7f0 connection timeout comparison fix by Emil 2002-02-18 10:05:18 +00:00
Daniel Stenberg
e452f467d4 Philip Gladstone's 64-bit issues corrected.
Reminder for the future: when we're using malloc() we MUST include <stdlib.h>
as otherwise 64bit archs go bananas.

Bug report #517687
2002-02-17 14:55:35 +00:00
Daniel Stenberg
dfda7ba456 corrected the Expect: ignore, made Content-Type: possible to skip 2002-02-17 14:42:44 +00:00
Daniel Stenberg
feb6b6445e Giaslas Georgios's Host: over proxy fix 2002-02-17 11:17:37 +00:00
Daniel Stenberg
0b57fa9c51 http server added to CVS, config*h files moved 2002-02-07 15:13:11 +00:00
Daniel Stenberg
55c6f60c90 ugh. the VMS stuff must've been like that for a reason, I put it back again 2002-02-07 14:47:41 +00:00
Daniel Stenberg
9def011e8e moved the config-* files to lib/Makefile.am 2002-02-07 14:35:14 +00:00
Daniel Stenberg
7cf6e8c9cc moved the config-* files here from the ../Makefile.am 2002-02-07 14:34:34 +00:00
Daniel Stenberg
cdee43aa59 use the config files in this directory now, not ../ 2002-02-07 14:33:36 +00:00
Daniel Stenberg
9c25b58b4c moved the config-*.h files from root to the lib/ dir 2002-02-07 14:32:28 +00:00
Daniel Stenberg
83f35463f5 added note about persistancy in the server 2002-02-07 12:52:04 +00:00
Daniel Stenberg
818cdb879e POSTs seems to work somewhat now 2002-02-07 12:42:59 +00:00
Daniel Stenberg
3eead2d6c4 port number fix, now stores the processed request sent to the server 2002-02-07 12:40:06 +00:00
Daniel Stenberg
5cffe055ad added Cris Bailiff's CAdir option suggestion 2002-02-07 10:43:43 +00:00
Daniel Stenberg
3d4511daf3 the initial C code for the new HTTP test server 2002-02-07 09:39:15 +00:00
Daniel Stenberg
4748b40ad9 changes since 7.9.4 2002-02-07 09:34:43 +00:00
Daniel Stenberg
c40b4f6c39 don't add 2 to the post size, that was a previous mistake because there
was an extra CRLF added to the post data
2002-02-07 09:32:40 +00:00
Daniel Stenberg
d3b96dd394 Miklos Nemeth windows update 2002-02-06 16:04:03 +00:00
Daniel Stenberg
f946df640b Miklos Nemeth added comments 2002-02-06 16:03:28 +00:00
Daniel Stenberg
fef78bd6f1 Miklos Nemeth improved the windows section 2002-02-06 16:01:10 +00:00
Daniel Stenberg
9e6cc86bf7 Miklos Nemeth improved 2002-02-06 16:00:55 +00:00
Daniel Stenberg
b544c5fa5c ARGH the CRLF I removed recently was not only done after the initial
content-type header, it was used for each part and thus without this it
failed MISERABLY. *smacks forhead*
2002-02-06 15:48:53 +00:00
Daniel Stenberg
afa64ee31f a few of the SSL options were added in 7.9.3 and it should be noted
accordingly
2002-02-06 09:49:34 +00:00
Daniel Stenberg
e9bfef0eb1 Brent Beardsley found the content-type bug! 2002-02-06 07:02:13 +00:00
Daniel Stenberg
ddbcccd43d Kevin Roth's discovered SSL download problem 2002-02-05 15:33:00 +00:00
Daniel Stenberg
5370d7a6eb 7.9.4 2002-02-05 11:43:29 +00:00
Daniel Stenberg
685b180ab6 7.9.4-pre2 2002-02-04 09:51:41 +00:00
Daniel Stenberg
9dab850874 Eric Melville fixed spell mistakes on a few places 2002-02-03 15:00:51 +00:00
Daniel Stenberg
0d5bfe883e Andreas Damm made getdate use gmtime_r if available 2002-02-01 11:11:26 +00:00
Daniel Stenberg
cc2f1d4894 Added the recycle handles chapter
Added most of the Customizing Operations chapter
2002-01-31 14:41:01 +00:00
Daniel Stenberg
a8dd13db4c struct HttpHeader died ages ago, corrected comments 2002-01-31 14:24:55 +00:00
Daniel Stenberg
325391aef9 Albert Chin:
Forgot one case. On HP-UX 11.00, gethostbyname_r() is properly defined
if -D_REENTRANT is used. Without it, the compiler still accepts the
function prototype but gives a warning about hostent_data going out of
scope. This is because struct hostent_data is not declared. So, we
force an error by trying to set a variable to the struct.
2002-01-31 07:53:20 +00:00
Daniel Stenberg
3474ec4ecb _num_chars did wrong when called with a number that starts with 1! 2002-01-31 07:51:06 +00:00
Daniel Stenberg
ec1736d488 corrected the docs for CURLINFO_FILETIME 2002-01-31 07:17:32 +00:00
Daniel Stenberg
4522579688 Giaslas Georgios provided docs for CURLINFO_CONTENT_TYPE 2002-01-31 07:10:41 +00:00
Daniel Stenberg
907a6e0eed Georg Horn the previous SSL_read() fix, this was actually the fix I did
on my test machine! :-)
2002-01-30 21:49:29 +00:00
Daniel Stenberg
d20186a7b8 I have too many ideas of what to mention in this docs 2002-01-30 15:35:02 +00:00
Daniel Stenberg
b28051881e Georg Horn found yet another SSL reading problem caused by the non-blocks.
This was a real bummer!
2002-01-30 15:11:47 +00:00
Daniel Stenberg
bdea56cd3f big-time alert that this doesn't work 2002-01-30 10:18:47 +00:00
Daniel Stenberg
8a3ec2c659 the interface is simply called the "C" one these days 2002-01-30 10:07:49 +00:00
Daniel Stenberg
14e9420d2c extended the proxy chapter mucho 2002-01-30 10:04:40 +00:00
Daniel Stenberg
5b58e61f28 now re-seed by force (even if already seeded) if a random file or egd socket
is given
2002-01-30 08:17:23 +00:00
Daniel Stenberg
be2f3071b5 conn->upload_bufsize exists no more 2002-01-29 20:34:30 +00:00
Daniel Stenberg
85dbf82d93 append a CRLF pair after the content-type line 2002-01-29 20:32:10 +00:00
Daniel Stenberg
a9c4963cc0 removed three loust fprintf()s
removed the initial CRLF in the formpost, as they are part of the request
and should be written by the code in http.c!
2002-01-29 20:30:56 +00:00
Daniel Stenberg
a4934387d5 upload progress counter fix, removed the adjustable upload buffer size 2002-01-29 20:28:59 +00:00
Daniel Stenberg
e88a2ec6fc no more adjustable upload buffer size, we use non-blocking sockets now so
this work-around is not needed anymore!
2002-01-29 20:28:26 +00:00
Daniel Stenberg
0666960173 nine items since 7.9.3 2002-01-29 14:12:12 +00:00
Daniel Stenberg
f114caca90 - T. Bharath pointed out that we seed SSL on every connect, which is a time-
consuming operation that should only be needed to do once. We patched
  libcurl to now only seed on the first connect when unseeded. The seeded
  status is global so it'll now only happen once during a program's life time.
2002-01-29 14:11:38 +00:00
Daniel Stenberg
9468c9c796 bad tag 2002-01-29 10:55:57 +00:00
Daniel Stenberg
76c53c690c Giaslas Georgios introduced CURLINFO_CONTENT_TYPE 2002-01-29 10:49:32 +00:00
Daniel Stenberg
c341b11aaf Steve Marx helped us realize that we shouldn't treat customrequest as a
request of its own, it just changes the keyword of a request.
2002-01-28 19:31:26 +00:00
Daniel Stenberg
6212e6990a someone should have me punished, but this bug made curl bug seriously
on IPv4-linux machines
2002-01-28 19:23:18 +00:00
Daniel Stenberg
28049a183c don't count a custom request as a request type of its own, it is merely
a modifier of another type
2002-01-28 19:22:40 +00:00
Daniel Stenberg
5d3dd7911e newly generated 2002-01-28 18:39:55 +00:00
Daniel Stenberg
ae8375516b Andreas Damm made it reentrant safe! 2002-01-28 18:39:40 +00:00
Daniel Stenberg
e3f10eb825 no longer add CRLF _after_ POST data, it should not be needed. Pedro Neves
pointed out this ugliness.
2002-01-27 11:51:11 +00:00
Daniel Stenberg
2b1f683239 set header and request size to 0 before each *_perform() 2002-01-27 11:49:17 +00:00
Daniel Stenberg
a2b19c9a63 postit.c is removed, it used the deprecated curl_formparse() and may
encourage people to use bad functions
2002-01-25 10:07:07 +00:00
Daniel Stenberg
4146ce8267 bug report #508235 identified a non-working Location: following, and this
little fix seems to correct it. another case where we just returned and
didn't shut off the reading. This bug is introduced in 7.9.3 due to the
new internal "order".
2002-01-25 08:35:49 +00:00
Daniel Stenberg
170bd6dafc don't install the example programs! :-O 2002-01-24 07:38:01 +00:00
Daniel Stenberg
7e16ec8724 7.9.3 2002-01-23 18:10:00 +00:00
Daniel Stenberg
8c459156f8 7.9.3 public 2002-01-23 18:01:16 +00:00
Daniel Stenberg
2db894807b Andrs Garca found out that we didn't properly stop reading from a connection
after the headers on a HEAD request. This bug has been added in 7.9.3 and was
mnot present earlier.
2002-01-23 07:15:32 +00:00
Daniel Stenberg
95ceeb6e0b more about passwords and started about proxies 2002-01-22 13:41:00 +00:00
Daniel Stenberg
c9c00d2a23 verify big files 2002-01-22 13:10:16 +00:00
Daniel Stenberg
1afe49864d minor edit 2002-01-22 08:22:04 +00:00
Daniel Stenberg
6924bee3a0 added --cc description and an example 2002-01-21 14:57:07 +00:00
Daniel Stenberg
39d4552dab pre4 2002-01-21 12:11:45 +00:00
Daniel Stenberg
a23c63738f HTTP POST explained 2002-01-21 10:54:56 +00:00
Daniel Stenberg
e911945c55 #505514, as correctly pointed out by Antonio (anton@concord.ru), trying to
post a non-existing file should include nothing, not an error text!
2002-01-19 11:08:05 +00:00
Daniel Stenberg
6d58d13710 mingw fix, mac os x fix, long long check removed from configure,
--enable-debug uses even stricter options now
2002-01-18 15:16:08 +00:00
Daniel Stenberg
0b177cb165 newly generated 2002-01-18 15:14:35 +00:00
Daniel Stenberg
3e31b619de added more text in the 'passwords' section 2002-01-18 15:08:32 +00:00
Daniel Stenberg
f925979b2f satisfy gcc -Wundef 2002-01-18 13:10:41 +00:00
Daniel Stenberg
49f7fa82b9 #if [undefined] => #ifdef [undefined] 2002-01-18 13:04:48 +00:00
Daniel Stenberg
e4cd4cf3f3 playing with more strict gcc warnings with --enable-debug 2002-01-18 13:00:13 +00:00
Daniel Stenberg
e74b20926d prevents gcc -Wcast-align from complaining 2002-01-18 12:59:33 +00:00
Daniel Stenberg
a312127c91 made gcc -Wcast-align happy 2002-01-18 12:56:10 +00:00
Daniel Stenberg
1dc5bf4f73 #ifndef and #define magic to prevent compiler warnings when doing #if BLA
where BLA is undefined
2002-01-18 12:53:05 +00:00
Daniel Stenberg
01cfe670c5 updated to 2002 status ;-) 2002-01-18 12:48:36 +00:00
Daniel Stenberg
fd307bfe29 cut off a big piece of comment and added a pointer to the Trio web page
should anyone ever want a good printf() clone
2002-01-18 10:45:03 +00:00
Daniel Stenberg
a00de093a7 commented out the 'long long' and 'long double' checks, as we don't really
use them anyway and they cause warnings in lib/mprint.c
2002-01-18 10:43:55 +00:00
Daniel Stenberg
7bfe853af3 I wish I could type. Anyway, this proved it is a good habit to put the NULL
on the left side of comparisons...
2002-01-18 10:36:25 +00:00
Daniel Stenberg
cbaecca8e9 added typecast for a malloc() return, and added check for NULL 2002-01-18 10:30:51 +00:00
Daniel Stenberg
8edfb370a8 Added #include <errno.h> 2002-01-18 09:25:58 +00:00
Daniel Stenberg
4c08c8f7db Andrs Garca patched. It now checks for EWOULDBLOCK properly on windows
boxes.
2002-01-18 08:03:54 +00:00
Daniel Stenberg
c174680a03 patched by Andrs Garca 2002-01-18 08:03:12 +00:00
Daniel Stenberg
cb5f6e18e6 7.9.3-pre3 2002-01-17 14:34:26 +00:00
Daniel Stenberg
b798e7a5ae correct ssl version, fixed ssl writes, solved time-out disconnect without
text, fixed dns cache problem, made it compile with openssl before 0.9.5
again and extended libcurl-the-guide a bit more
2002-01-17 14:25:49 +00:00
Daniel Stenberg
5deab7ad27 more text added 2002-01-17 14:24:25 +00:00
Daniel Stenberg
12cdfd282d added a comment about this example only works with 7.9.3 and newer libs 2002-01-17 13:45:19 +00:00
Daniel Stenberg
eba8035e12 Richard Archer made it compile and build with OpenSSL versions prior to
0.9.5
2002-01-17 10:40:13 +00:00
Daniel Stenberg
edcbf4350b include our own sprintf() prototype to make it return sensible data on
all platforms, I also edited a few data types slightly to prevent my
compiler from warning on comparisions between signed and unsigned values
2002-01-17 08:03:48 +00:00
Sterling Hughes
9289ea471f Get this working, still need to check for leaks and such, but should be
fine..
2002-01-17 07:38:25 +00:00
Sterling Hughes
7d06185aa6 Make the keys for hostcache entries be in the format::
host:port, so accessing curl.haxx.se on port 80 would yield a key value
of ::
curl.haxx.se:80
2002-01-17 06:55:37 +00:00
Daniel Stenberg
01ecb1d7e7 filled-in text in the "Building" chapter and added a "libcurl with C++"
chapter
2002-01-17 00:27:56 +00:00
Daniel Stenberg
e177f14595 SSL writes passed back a silly length... 2002-01-16 23:28:58 +00:00
Daniel Stenberg
5c6eddcadd fixed time-out returned without error text set 2002-01-16 22:26:01 +00:00
Daniel Stenberg
b3b4786990 Kevin Roth's SSLeay() patch, slight edited by me. Works with OpenSSL 0.9.5
now.
2002-01-16 17:45:08 +00:00
Daniel Stenberg
fbe2907599 7.9.3-pre2 2002-01-16 15:12:12 +00:00
Daniel Stenberg
343da8d4b3 --cc and working non-blocking sockets uploads 2002-01-16 15:04:37 +00:00
Daniel Stenberg
8d97792dbc - shrunk the BUFSIZE define from 50K to 20K
- made a separate buffer for uploads (due to the non-blocking stuff)
- added two connectdata struct fields for non-blocking uploads
2002-01-16 14:53:19 +00:00
Daniel Stenberg
8d07c87be7 modified to deal with the new non-blocking versions of Curl_read() and
Curl_write().
2002-01-16 14:50:53 +00:00
Daniel Stenberg
ed21701df3 Curl_write's 5th argument now is signed 2002-01-16 14:49:51 +00:00
Daniel Stenberg
df01507582 Curl_read() and Curl_write() are both now adjusted to return properly in
cases where EWOULDBLOCK or equivalent is returned. We must not block.
2002-01-16 14:49:08 +00:00
Daniel Stenberg
f2bda5fd5b Curl_write() now takes a different 5th argument 2002-01-16 14:47:50 +00:00
Daniel Stenberg
cba9838e8f Somewhat ugly fix to deal with non-blocking sockets. We just loop and try
again. THIS IS NOT A NICE FIX.
2002-01-16 14:47:00 +00:00
Daniel Stenberg
b6dba9f5dd Somewhat ugly fix to deal with non-blocking sockets. We just loop and try
again. THIS IS NOT A NICE FIX. We should/must make a select() then and only
retry when we can write to the socket again.
2002-01-16 14:46:00 +00:00
Daniel Stenberg
6e9d1617c6 added support for --cc to output the compiler name. This makes it possible
to compile libcurl stuff without any prior knowledge:

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

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

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

`curl-config --cc --cflags --libs` -o example example.c
2002-01-16 14:20:06 +00:00
Daniel Stenberg
ea811fee52 added a somewhat cool single-line command that builds most example sources
on unix-like systems
2002-01-16 14:13:54 +00:00
Daniel Stenberg
7391fd8f6a initial attempt to write a tutorial-like libcurl guide 2002-01-15 08:22:00 +00:00
Daniel Stenberg
6c00c58f2a fixed non-blocking reads, fixed ssl sessions, in_addr_t and more non-blocking 2002-01-14 23:32:57 +00:00
Daniel Stenberg
4931fbce49 Curl_read() now returns a negative return code if EWOULDBLOCK or similar 2002-01-14 23:14:59 +00:00
Daniel Stenberg
fefc7ea600 a memory leak when name lookup failed is now removed 2002-01-14 23:14:24 +00:00
Daniel Stenberg
d220389647 Stoned Elipot's patch for the in_addr_t test 2002-01-14 07:53:09 +00:00
Sterling Hughes
a1f910c159 Remove erreaneous include, setup.h is included one line above 2002-01-14 05:36:28 +00:00
Daniel Stenberg
e4866563de Gtz Babin-Ebell updated with some new 7.9.3 features 2002-01-13 11:32:36 +00:00
Daniel Stenberg
47f45aa229 Gtz Babin-Ebell provided some documantation for the ENGINE stuff 2002-01-13 11:32:05 +00:00
Daniel Stenberg
affe334675 added http-post.c 2002-01-10 09:00:02 +00:00
Daniel Stenberg
ee7e184e26 slightly extended to mention that -v and -i are good options to use when
reporting bugs
2002-01-10 07:38:53 +00:00
Daniel Stenberg
bec0ebacf1 bad comment begone 2002-01-09 13:23:01 +00:00
Daniel Stenberg
5bd6d631c6 cut off argc and argv as well 2002-01-09 13:22:31 +00:00
Daniel Stenberg
fd1799f3bb Cleaned up this example to make it even simpler. 2002-01-09 13:22:03 +00:00
Daniel Stenberg
d84a0c51e0 Cris Bailiff found out that when the SSL session cache was filled, libcurl
would crash. This corrects the problem.
2002-01-09 09:38:37 +00:00
Daniel Stenberg
d9a7c7de51 David Bentham's updated QNX notification 2002-01-08 23:27:42 +00:00
Daniel Stenberg
d57e09889a added a missing failf() before returning an error code 2002-01-08 23:23:24 +00:00
Daniel Stenberg
eecb86bfb0 this seems to correct the SSL reading problem introduced when switching
over to non-blocking sockets, but this loops very nastily. We should return
back to the select() and wait there until more data arrives, not just blindly
attempt again and again...
2002-01-08 23:19:32 +00:00
Daniel Stenberg
0b1197936c I made the write callback create the file the first time it gets called so
that it won't create an empty file if the remote file doesn't exist
2002-01-08 13:05:44 +00:00
Daniel Stenberg
b545ac6391 test case 38 added a few new requirements 2002-01-08 09:32:41 +00:00
Daniel Stenberg
a922132e4a updated 2002-01-08 09:32:21 +00:00
Daniel Stenberg
9474e8d6d2 added some tracability 2002-01-08 09:32:10 +00:00
Daniel Stenberg
6328428568 test case 38, try a HTTP download resume without the server supporting
ranges
2002-01-08 09:31:40 +00:00
Daniel Stenberg
ea9a88a9b8 another example source added 2002-01-08 08:26:22 +00:00
Daniel Stenberg
aec7358ca4 7.9.3 pre-release commit 2002-01-08 08:25:44 +00:00
Daniel Stenberg
3c334b2bb6 non-blocking sockets, DNS caching updated, cookies corrected, bool is now
unsigned everywhere
2002-01-08 07:22:33 +00:00
Daniel Stenberg
75bba0da92 added two typecasts to prevent compiler (gcc3) warnings 2002-01-08 07:06:07 +00:00
Sterling Hughes
c0bfe7be15 1) the dns_cache_timeout should be an integer, not a bool
2) in the curl_dns_cache_entry structure, timestamp should be
a time_t instead of an integer (although I doubt it matters).
2002-01-08 04:30:59 +00:00
Sterling Hughes
22ac08e06d Add support for DNS cache timeouts via the CURLOPT_DNS_CACHE_TIMEOUT option.
The default cache timeout for this is 60 seconds, which is arbitrary and
completely subject to change :)
2002-01-08 04:26:47 +00:00
Daniel Stenberg
87037136ef As identified in bug report #495290, the last "name=value" pair in a
Set-Cookie: line was ignored if they didn't end with a trailing
semicolon. This is indeed wrong syntax, but there are high-profile web sites
out there sending cookies like that so we must make a best-effort to parse
them.
2002-01-07 23:05:36 +00:00
Daniel Stenberg
2182e37433 the bool typedef is now made unsigned, to make sure it stays that on all
platforms, unrelated to what they might prefer by default
2002-01-07 22:47:21 +00:00
Daniel Stenberg
1de82b220d removed silly check for >=0 of a supposedly unsigned value! 2002-01-07 22:46:38 +00:00
Sterling Hughes
bd878756fc Probably not necessary, but good practice. 2002-01-07 20:55:35 +00:00
Sterling Hughes
8d7f402efb Make cach'ing work with threads now, there are now three cases:
- Use a global dns cache (via setting the tentatively named,
    CURLOPT_DNS_USE_GLOBAL_CACHE option to true)
    - Use a per-handle dns cache, by default
    - Use a pooled dns cache when in the "multi" interface
2002-01-07 20:52:32 +00:00
Daniel Stenberg
d3299beec7 Modified to use non-blocking sockets all the time. 2002-01-07 18:38:01 +00:00
Daniel Stenberg
f9192db358 VC++ makefile, HTTP 204, cookie fix, non-blocking socket for better SSL
connection timeout
2002-01-07 16:03:36 +00:00
Daniel Stenberg
c69c0c0446 added proper breaks in the switch() 2002-01-07 15:24:52 +00:00
Daniel Stenberg
deb2911c0e Added David Bentham's notes about QNX and FD_SETSIZE 2002-01-07 15:14:01 +00:00
Daniel Stenberg
e31a306a38 HTTP response 204 should be treated similar to 304, that is we must not
expect (nor read) any response-body
2002-01-07 14:57:18 +00:00
Daniel Stenberg
d9a7773011 added precautions to not go insane when two matching cookies end up in the
cookie list, even though they're not supposed to do that...
2002-01-07 14:56:15 +00:00
sm
2b14916813 Add hash and llist to VC dsp file 2002-01-04 23:48:28 +00:00
sm
1d1530e14c Add hash and llist to VC makefile 2002-01-04 23:47:07 +00:00
Daniel Stenberg
b4fdc025a8 -l lists all tests 2002-01-04 13:20:17 +00:00
Daniel Stenberg
f1c14fe0b4 The former -c is "-C -" these days 2002-01-04 13:15:07 +00:00
Daniel Stenberg
38306cda54 dns cache, ftp response read, 64bit fixes, printf replaces, inet_ntoa_r
corrections
2002-01-04 09:57:57 +00:00
Daniel Stenberg
5a0f0023cf replaced printf() => Curl_sendf() 2002-01-04 09:53:39 +00:00
Daniel Stenberg
6dcdb8b821 removed a commented line 2002-01-04 09:53:10 +00:00
Daniel Stenberg
781f52a287 fixed an inet_ntoa() occurance to use inet_ntoa_r() if it is available.
I also replaced all printf() calls with calls to Curl_failf()
2002-01-04 09:52:44 +00:00
Daniel Stenberg
f75ff58b4b an unconditional occurance of inet_ntoa() now uses inet_ntoa_r() on all
platforms that have such a function.
This affects multi-thread running libcurls on IPv4 systems that have VERBOSE
switched on. The previous version was risking that another thread overwrote
the data before it was read out in this thread. There could possibly also
be a slight risk that the data isn't zero terminated for a short while and
thus could cause the thread to crash...
2002-01-04 09:38:52 +00:00
Daniel Stenberg
ae9bf16dee #include the local "inet_ntoa_r.h" file if no proto was found in the global
header directory but the function *is* present!
2002-01-04 09:35:23 +00:00
Daniel Stenberg
17a8bf212f The buffer in ftp_pasv_verbose(), used for gethostbyaddr_r(), is now defined
to become properly 8-byte aligned on 64-bit archs. Philip Gladstone reported.
2002-01-04 09:17:52 +00:00
Daniel Stenberg
4fc76afef4 The FTP response lines are now passed to the function callback registered for
headers.
2002-01-04 09:03:11 +00:00
Daniel Stenberg
a31155a72a multi stuff from the multi-dev branch 2002-01-03 15:03:57 +00:00
Daniel Stenberg
75601f7924 multi interface example/test sources from the multi-dev branch 2002-01-03 15:03:14 +00:00
Daniel Stenberg
8b6314ccfb merged the multi-dev branch back into MAIN again 2002-01-03 15:01:22 +00:00
Daniel Stenberg
6de7dc5879 Sterling Hughes' provided initial DNS cache source code. 2002-01-03 10:22:59 +00:00
96 changed files with 5684 additions and 2026 deletions

324
CHANGES
View File

@@ -6,7 +6,331 @@
History of Changes
Daniel (25 February 2002)
- Fiddled with the automake files to make all source files in the lib
directory not have ../src in the include path, and the src sources shouldn't
have ../lib!
- All 79 test cases ran OK under Linux and Solaris using the new HTTP server
in the test suite. The new HTTP server was first donated by Georg Horn and
subsequently modified to work with the test suite. It is currently still not
portable enough to run on "all over" but this is a start and I can run all
curl tests on my machines. This is an important requirement for the upcoming
public release.
- Using -d and -I on the same command line now reports an error, as it implies
two different HTTP requests that can't be mixed.
- Jeffrey Pohlmeyer provided a patch that made the -w/--write-out option
support %{content_type} to get the content type of the recent download.
- Kevin Roth reported that pre2 and pre3 didn't compile properly on cygwin,
and this was because I used #ifdef HAVE_WINSOCK_H in lib/multi.h to figure
out if we could include winsock.h which turns out not to be a wise choice to
do on cygwin since it has the file but can't include it!
Daniel (22 February 2002)
- Added src/config-vms.h to the release archive.
- Fixed the connection timeout value again, the change from February 18 wasn't
complete.
Version 7.9.5-pre3
Daniel (21 February 2002)
- Kevin Roth and Andr<64>s Garc<72>a both found out that lib/config.h.in was missing
in the pre-release archive and thus the configure script failed.
Version 7.9.5-pre2
Daniel (20 February 2002)
- Andr<64>s Garc<72>a provided a solution to bug report #515228. the total time
counter was not set correctly when -I was used during some conditions (all
headers were read in one single read).
- Nico Baggus provided a huge patch with minor tweaks all over to make curl
compile nicely on VMS.
Daniel (19 February 2002)
- Rick Richardson found out that by replacing PF_UNSPEC with PF_INET in the
getaddrinfo() calls, he could speed up some name resolving calls with an
order of magnitudes on his Redhat Linux 7.2.
- Philip Gladstone found a second INADDR_NONE problem where we used long
intead of in_addr_t which caused 64bit problemos. We really shouldn't define
that on two different places.
Daniel (18 February 2002)
- Philip Gladstone found a problem in how HTTP requests were sent if the
request couldn't be sent all at once.
- Emil found and corrected a bad connection timeout comparison that made curl
use the longest of connect-timeout and timout as a timeout value, instead of
the shortest as it was supposed to!
- Aron Roberts provided updated information about LDAP URL syntax to go into
the manual as a replacement for the old references.
Daniel (17 February 2002)
- Philip Gladstone pointed out two missing include files that made curl core
dump on 64bit architectures. We need to pay more attention on these details.
It is *lethal* to for example forget the malloc() prototype, as 'int' is
32bit and malloc() must return a 64bit pointer on these platforms.
- Giaslas Georgios fixed a problem with Host: headers on repeated requests on
the same handle using a proxy.
Daniel (8 February 2002)
- Hanno L. Kranzhoff accurately found out that disabling the Expect: header
when doing multipart formposts didn't work very well. It disabled other
parts of the request header too, resulting in a broken header. When I fixed
this, I also noticed that the Content-Type wasn't possible to disable. It is
now, even though it probably is really stupid to try to do this (because of
the boundary string that is included in the internally generated header,
used as form part separator.)
Daniel (7 February 2002)
- I moved the config*.h files from the root directory to the lib/ directory.
- I've added the new test suite HTTP server to the CVS repository, It seems to
work pretty good now, but we must make it get used by the test scripts
properly and then we need to make sure that it compiles, builds and runs on
most operating systems.
Version 7.9.5-pre1
Daniel (6 February 2002)
- Miklos Nemeth provided updated windows makefiles and INSTALL docs.
- Mr Larry Fahnoe found a problem with formposts and I managed to track down
and patch this bug. This was actually two bugs, as the posted size was also
said to be two bytes too large.
- Brent Beardsley found out and brought a correction for the
CURLINFO_CONTENT_TYPE parser that was off one byte. This was my fault, I
accidentaly broke Giaslas Georgios' patch.
Daniel (5 February 2002)
- Kevin Roth found yet another SSL download problem.
Version 7.9.4
- no changes since pre-release
Version 7.9.4-pre2
Daniel (3 February 2002)
- Eric Melville provided a few spelling corrections in the curl man page.
Daniel (1 February 2002)
- Andreas Damm corrected the unconditional use of gmtime() in getdate, it now
uses gmtime_r() on all hosts that have it.
Daniel (31 January 2002)
- An anonymous bug report identified a problem in the DNS caching which made it
sometimes allocate one byte too little to store the cache entry in. This
happened when the port number started with 1!
- Albert Chin provided a patch that improves the gethostbyname_r() configure
check on HP-UX 11.00.
Version 7.9.4-pre1
Daniel (30 January 2002)
- Georg Horn found another way the SSL reading failed due to the non-blocking
state of the sockets! I fixed.
Daniel (29 January 2002)
- Multipart formposts now send the full request properly, including the CRLF.
They were previously treated as part of the post data.
- The upload byte counter bugged.
- T. Bharath pointed out that we seed SSL on every connect, which is a time-
consuming operation that should only be needed to do once. We patched
libcurl to now only seed on the first connect when unseeded. The seeded
status is global so it'll now only happen once during a program's life time.
If the random_file or egdsocket is set, the seed will be re-made though.
- Giaslas Georgios introduced CURLINFO_CONTENT_TYPE that lets
curl_easy_getinfo() read the content-type from the previous request.
Daniel (28 January 2002)
- Kjetil Jacobsen found a way to crash curl and after much debugging, it
turned out it was a IPv4-linux only problem introduced in 7.9.3 related to
name resolving.
- Andreas Damm posted a huge patch that made the curl_getdate() function fully
reentrant!
- Steve Marx pointed out that you couldn't mix CURLOPT_CUSTOMREQUEST with
CURLOPT_POSTFIELDS. You can now!
Daniel (25 January 2002)
- Krishnendu Majumdar pointed out that the header length counter was not reset
between multiple requests on the same handle.
- Pedro Neves rightfully questioned why curl always append \r\n to the data
that is sent in HTTP POST requests. Unfortunately, this broke the test suite
as the test HTTP server is lame enough not to deal with this... :-O
- Following Location: headers when the connection didn't close didn't work as
libcurl didn't properly stop reading. This problem was added in 7.9.3 due to
the restructured internals. 'Frank' posted a bug report about this.
Daniel (24 January 2002)
- Kevin Roth very quickly spotted that we wrongly installed the example
programs that were built in the multi directory, when 'make install' was
used. :-/
Version 7.9.3
Daniel (23 January 2002)
- Andr<64>s Garc<72>a found a persistancy problem when doing HTTP HEAD, that made
curl "hang" until the connection was closed by the server. This problem has
been introduced in 7.9.3 due to internal rewrites, this was not present in
7.9.2.
Version 7.9.3-pre4
Daniel (19 January 2002)
- Antonio filed bug report #505514 and provided a fix! When doing multipart
formposts, libcurl would include an error text in the actual post if a
specified file wasn't found. This is not libcurl's job. Instead we add an
empty part.
Daniel (18 January 2002)
- Played around with stricter compiler warnings for gcc (when ./configure
--enable-debug is used) and changed some minor things to stop the warnings.
- Commented out the 'long long' and 'long double' checks in configure.in, as
we don't currently use them anyway and the code in lib/mprintf.c that use
them causes warnings.
- Saul Good and jonatan pointed out Mac OS X build problems with pre3 and how
to correct them. Two compiler warnings were removed as well.
- Andr<64>s Garc<72>a fixed two minor mingw32 building problems.
Version 7.9.3-pre3
Daniel (17 January 2002)
- docs/libcurl-the-guide is a new tutorial for our libcurl programming
friends.
- Richard Archer brought back the ability to compile and build with OpenSSL
versions before 0.9.5.
[http://sourceforge.net/tracker/?func=detail&atid=100976&aid=504163&group_id=976]
- The DNS cache code didn't take the port number into account, which made it
work rather bad on IPv6-enabled hosts (especially when doing passive
FTP). Sterling fixed it.
Daniel (16 January 2002)
- Georg Horn could make a transfer time-out without error text. I found it and
corrected it.
- SSL writes didn't work, they return an uninitialized value that caused
havoc all over. Georg Horn experienced this.
- Kevin Roth patched the curl_version() function to use the proper OpenSSL
function for version information. This way, curl will report the version of
the SSL library actually running right now, not the one that had its headers
installed when libcurl was built. Mainly intersting when running with shared
OpenSSL libraries.
Version 7.9.3-pre2
Daniel (16 January 2002)
- Mofied the main transfer loop and related stuff to deal with non-blocking
sockets in the upload section. While doing this, I've now separated the
connection oriented buffers to have one for downloads and one for uploads
(as two can happen simultaneously). I also shrunk the buffers to 20K
each. As we have a scratch buffer twice the size of the upload buffer, we
arrived at 80K for buffers compared with the previous 150K.
- Added the --cc option to curl-config command as it enables so very cool
one-liners. Have a go a this one, building the simple.c example:
$ `curl-config --cc --cflags --libs` -o example simple.c
Daniel (14 January 2002)
- I made all socket reads (recv) handle EWOULDBLOCK. I hope nicely. Now we
only need to address all writes (send) too and then I'm ready for another
pre-release...
- Stoned Elipot patched the in_addr_t configure test to make it work better on
more platforms.
Daniel (9 January 2002)
- Cris Bailiff found out that filling up curl's SSL session cache caused a
crash!
- Posted the curl questionnaire on the web site. If you haven't posted your
opinions there yet, go there and do it now while it is still there:
http://curl.haxx.se/q/
- Georg Horn quickly found out that the SSL reading no longer worked as
supposed since the switch to non-blocking sockets. I've made a quick patch
(for reading only) but we should improve it even further.
Version 7.9.3-pre1
Daniel (7 January 2002)
- I made the 'bool' typedef use an "unsigned char". It makes it the same on
all platforms, no matter what the platform thinks the default format for
char is. This was noticed since we made a silly comparison involving such a
bool variable, and only one compiler/platform combination (on Debian Linux)
complained about it (that happened to have its char unsigned by default).
- Bug report #495290 identified a cookie parsing problem that was corrected.
When a Set-Cookie: line is received without a trailing semicolon, libcurl
didn't read the last "name=value" pair of the line, leading to confusions...
- Sterling committed his updated DNS cache code.
- I worked with Georg Horn and comments from G<>tz Babin-Ebell and switched
curl's socket operations completely over to non-blocking for the entire
operation (previously we used non-blocking only for the connection phase).
We had to do this to make the SSL connection phase timeout properly without
the use of signals. A little extra code to deal with this was added.
- T. Bharath pointed out a slightly obscure cookie engine flaw.
- Pete Su pointed out that libcurl didn't treat HTTP code 204 as it should.
204-replies never provides a response-body. This resulted in bad persistant
behavior when 204 was received.
Daniel (5 January 2002)
- SM updated the VC++ library Makefiles for the new source files.
Daniel (4 January 2002)
- I discovered that we wrongly used inet_ntoa() (instead of inet_ntoa_r() in
two places in the source code). One happened with VERBOSE set on connects,
and the other when VERBOSE was on and krb4 over nat was used... I honestly
don't think anyone has suffered from these mistakes.
- I replaced a lot of silly occurances of printf() to instead use the more
appropriate Curl_infof() or Curl_failf(). The krb4 and telnet code were
affected.
- Philip Gladstone found a few more problems with 64-bit archs (the 64-bit
sparc on solaris 8).
- After discussions on the libcurl list with Raoul Cridlig, I just made FTP
response lines get passed to the header callback if such a one is
registered. It'll make it possible for any application to get all the
responses an FTP server sends to libcurl.
Daniel (3 January 2002)
- Sterling Hughes brought a few buckets of code. Now, libcurl will
automatically cache DNS lookups and re-use the previous results first if any
such is available. It greatly improves speed when doing many repeated
operations to the same host.
- As the test case uses --include and then --head, I had to modify src/main.c
to deal with this situation slightly better than previously. When done, we
have 100% good tests again in the main branch.

View File

@@ -2,16 +2,15 @@
# $Id$
#
AUTOMAKE_OPTIONS = foreign no-dependencies
AUTOMAKE_OPTIONS = foreign
EXTRA_DIST = \
CHANGES LEGAL maketgz MITX.txt MPL-1.1.txt \
reconf Makefile.dist curl-config.in build_vms.com curl-mode.el \
config-vms.h config-win32.h config-riscos.h config-mac.h
reconf Makefile.dist curl-config.in build_vms.com curl-mode.el
bin_SCRIPTS = curl-config
SUBDIRS = docs lib src include tests packages
SUBDIRS = docs lib src include tests packages multi
# create a root makefile in the distribution:
dist-hook:

View File

@@ -5,7 +5,7 @@
# | (__| |_| | _ <| |___
# \___|\___/|_| \_\_____|
#
# Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
# Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
#
# In order to be useful for every potential user, curl and libcurl are
# dual-licensed under the MPL and the MIT/X-derivate licenses.
@@ -51,6 +51,12 @@ vc-ssl:
cd lib
nmake -f Makefile.vc6 cfg=release-ssl
cd ..\src
nmake -f Makefile.vc6 cfg=release-ssl
vc-ssl-dll:
cd lib
nmake -f Makefile.vc6 cfg=release-ssl-dll
cd ..\src
nmake -f Makefile.vc6
cygwin:

View File

@@ -176,7 +176,7 @@ AC_DEFUN([TYPE_IN_ADDR_T],
AC_DEFINE_UNQUOTED(in_addr_t, $curl_cv_in_addr_t_equiv,
[type to use in place of in_addr_t if not defined])],
[#include <sys/types.h>
#include <sys/socket.h>,
#include <sys/socket.h>
#include <arpa/inet.h>])
])
@@ -377,6 +377,7 @@ AC_DEFUN(CURL_CHECK_GETHOSTBYNAME_R,
int
gethostbyname_r(const char *, struct hostent *, struct hostent_data *);],[
struct hostent_data data;
gethostbyname_r(NULL, NULL, NULL);],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_GETHOSTBYNAME_R_3)
@@ -394,6 +395,7 @@ gethostbyname_r(NULL, NULL, NULL);],[
int
gethostbyname_r(const char *,struct hostent *, struct hostent_data *);],[
struct hostent_data data;
gethostbyname_r(NULL, NULL, NULL);],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_GETHOSTBYNAME_R_3)

View File

@@ -6,14 +6,16 @@ $ loc = f$environment("PROCEDURE")
$ def = f$parse("X.X;1",loc) - "X.X;1"
$
$ set def 'def'
$ cc_qual = "/define=HAVE_CONFIG_H=1/include=(""../include/"",""../"")"
$ cc_qual = "/define=HAVE_CONFIG_H=1/include=(""../include/"",""../"",""../../openssl-0_9_6c/include/"")"
$ if p1 .eqs. "LISTING" then cc_qual = cc_qual + "/LIST/MACHINE"
$ if p1 .eqs. "DEBUG" then cc_qual = cc_qual + "/LIST/MACHINE/DEBUG"
$ msg_qual = ""
$ call build "[.lib]" "*.c"
$ call build "[.src]" "*.c"
$ call build "[.src]" "*.msg"
$ link /exe=curl.exe [.src]curl/lib/include=main,[.lib]curl/lib
$ link /exe=curl.exe [.src]curl/lib/include=main,[.lib]curl/lib, -
[-.openssl-0_9_6c.axp.exe.ssl]libssl/lib, -
[-.openssl-0_9_6c.axp.exe.crypto]libcrypto/lib
$
$
$ goto Common_Exit

View File

@@ -8,7 +8,7 @@ AC_PREREQ(2.50)
dnl First some basic init macros
AC_INIT
AC_CONFIG_SRCDIR([lib/urldata.h])
AM_CONFIG_HEADER(config.h src/config.h)
AM_CONFIG_HEADER(lib/config.h src/config.h tests/server/config.h)
dnl figure out the libcurl version
VERSION=`sed -ne 's/^#define LIBCURL_VERSION "\(.*\)"/\1/p' ${srcdir}/include/curl/curl.h`
@@ -69,7 +69,7 @@ AC_ARG_ENABLE(debug,
*) AC_MSG_RESULT(yes)
CPPFLAGS="$CPPFLAGS -DMALLOCDEBUG"
CFLAGS="-W -Wall -Wwrite-strings -pedantic -g"
CFLAGS="-W -Wall -Wwrite-strings -pedantic -Wundef -Wpointer-arith -Wcast-align -Wnested-externs -g"
;;
esac ],
AC_MSG_RESULT(no)
@@ -524,9 +524,9 @@ AC_HEADER_TIME
# mprintf() checks:
# check for 'long double'
AC_CHECK_SIZEOF(long double, 8)
# AC_CHECK_SIZEOF(long double, 8)
# check for 'long long'
AC_CHECK_SIZEOF(long long, 4)
# AC_CHECK_SIZEOF(long long, 4)
# check for ssize_t
AC_CHECK_TYPE(ssize_t, int)
@@ -597,9 +597,11 @@ AC_CONFIG_FILES([Makefile \
include/Makefile \
include/curl/Makefile \
src/Makefile \
multi/Makefile \
lib/Makefile \
tests/Makefile \
tests/data/Makefile \
tests/server/Makefile \
packages/Makefile \
packages/Win32/Makefile \
packages/Win32/cygwin/Makefile \

View File

@@ -16,6 +16,7 @@ Usage: curl-config [OPTION]
Available values for OPTION include:
--cc compiler
--cflags pre-processor and compiler flags
--feature newline separated list of enabled features
--help display this help and exit
@@ -42,6 +43,10 @@ while test $# -gt 0; do
esac
case "$1" in
--cc)
echo @CC@
;;
--prefix)
echo $prefix
;;

View File

@@ -23,11 +23,16 @@ BUGS
When reporting a bug, you should include information that will help us
understand what's wrong, what you expected to happen and how to repeat the
bad behaviour. You therefore need to supply your operating system's name and
bad behavior. You therefore need to supply your operating system's name and
version number (uname -a under a unix is fine), what version of curl you're
using (curl -V is fine), what URL you were working with and anything else
you think matters.
Since curl deals with networks, it often helps us a lot if you include a
protocol debug dump with your bug report. The output you get by using the -v
flag. Usually, you also get more info by using -i so that is likely to be
useful when reporting bugs as well.
If curl crashed, causing a core dump (in unix), there is hardly any use to
send that huge file to anyone of us. Unless we have an exact same system
setup as you, we can't do much with it. What we instead ask of you is to get
@@ -36,8 +41,7 @@ BUGS
The address and how to subscribe to the mailing list is detailed in the
MANUAL file.
How To Get A Stack Trace
========================
HOW TO GET A STACK TRACE
First, you must make sure that you compile all sources with -g and that you
don't 'strip' the final executable. Try to avoid optimizing the code as

View File

@@ -1,4 +1,4 @@
Updated: December 21, 2001 (http://curl.haxx.se/docs/faq.shtml)
Updated: January 22, 2002 (http://curl.haxx.se/docs/faq.shtml)
_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
@@ -163,9 +163,8 @@ FAQ
1.6 What do you get for making cURL?
Project cURL is entirely free and open, without any commercial interests or
money involved. No person gets paid in any way for developing curl. We all
do this voluntarily on our spare time.
Project cURL is entirely free and open. No person gets paid in any way for
developing curl. We all do this voluntarily on our spare time.
We get some help from companies. Contactor Data hosts the curl web site and
the main mailing list, Haxx owns the curl web site's domain and

View File

@@ -179,8 +179,8 @@ Win32
to use out-of-the-box.
Microsoft note: add /Zm200 to the compiler options to increase the
compiler's memory allocation limit, as the hugehelp.c won't compile
due to "too long puts string".
compiler's memory allocation limit, as the hugehelp.c won't compile
due to "too long puts string".
With SSL:
@@ -203,15 +203,32 @@ Win32
----------------------------
Please read the OpenSSL documentation on how to compile and install
the OpenSSL library. This generates the libeay32.dll and ssleay32.dll
files.
files in the out32dll subdirectory in the OpenSSL home directory. If
you compiled OpenSSL static libraries (libeay32.lib, ssleay32.lib,
RSAglue.lib) they are created in the out32 subdirectory.
Run the 'vcvars32.bat' file to get the proper environment variables
set. Edit the makefile.vc6 in the lib directory and define
OPENSSL_PATH. Set the location of the OpenSSL library and run 'nmake
vc-ssl' in the root directory.
set. The vcvars32.bat file is part of the Microsoft development
environment and you may find it in 'C:\Program Files\Microsoft Visual
Studio\vc98\bin' if you installed Visual C/C++ 6 in the default
directory.
The vcvars32.bat file is part of the Microsoft development
environment.
Before running nmake define the OPENSSL_PATH environment variable with
the root/base directory of OpenSSL, for example:
set OPENSSL_PATH=c:\openssl-0.9.6b
Then run 'nmake vc-ssl' or 'nmake vc-ssl-dll' in the curl's root
directory. 'nmake vc-ssl' will create a libcurl static and dynamic
libraries in the lib subdirectory, as well as a statically linked
version of curl.exe in the scr subdirectory. This statically linked
version is a standalone executable not requiring any DLL at
runtime. This making method requires that you have build the static
libraries of OpenSSL available in OpenSSL's out32 subdirectory.
'nmake vc-ssl-dll' creates the libcurl dynamic library and
links curl.exe against libcurl and OpenSSL dynamically.
This executables requires libcurl.dll and the OpenSSL DLLs
at runtime.
Microsoft / Borland style
-------------------------
@@ -322,6 +339,20 @@ VMS
13-jul-2001
N. Baggus
QNX
===
(This section was graciously brought to us by David Bentham)
As QNX is targetted for resource constrained environments, the QNX headers
set conservative limits. This includes the FD_SETSIZE macro, set by default
to 32. Socket descriptors returned within the CURL library may exceed this,
resulting in memory faults/SIGSEGV crashes when passed into select(..)
calls using fd_set macros.
A good all-round solution to this is to override the default when building
libcurl, by overriding CFLAGS during configure, example
# configure CFLAGS='-DFD_SETSIZE=64 -g -O2'
CROSS COMPILE
=============

View File

@@ -601,15 +601,15 @@ RESUMING FILE TRANSFERS
Continue downloading a document:
curl -c -o file ftp://ftp.server.com/path/file
curl -C - -o file ftp://ftp.server.com/path/file
Continue uploading a document(*1):
curl -c -T file ftp://ftp.server.com/path/file
curl -C - -T file ftp://ftp.server.com/path/file
Continue downloading a document from a web server(*2):
curl -c -o file http://www.server.com/
curl -C - -o file http://www.server.com/
(*1) = This requires that the ftp server supports the non-standard command
SIZE. If it doesn't, curl will say so.
@@ -668,8 +668,14 @@ LDAP
and offer ldap:// support.
LDAP is a complex thing and writing an LDAP query is not an easy task. I do
advice you to dig up the syntax description for that elsewhere, RFC 1959 if
no other place is better.
advice you to dig up the syntax description for that elsewhere. Two places
that might suit you are:
Netscape's "Netscape Directory SDK 3.0 for C Programmer's Guide Chapter 10:
Working with LDAP URLs":
http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm
RFC 2255, "The LDAP URL Format" http://www.rfc-editor.org/rfc/rfc2255.txt
To show you an example, this is now I can get all people from my local LDAP
server that has a certain sub-domain in their email address:

119
docs/TODO
View File

@@ -19,10 +19,7 @@ TODO
* The new 'multi' interface is being designed. Work out the details, start
implementing and write test applications!
[http://curl.haxx.se/dev/multi.h]
* Add a name resolve cache to libcurl to make repeated fetches to the same
host name (when persitancy isn't available) faster.
[http://curl.haxx.se/lxr/source/lib/multi.h]
* Introduce another callback interface for upload/download that makes one
less copy of data and thus a faster operation.
@@ -33,13 +30,36 @@ TODO
telnet, ldap, dict or file.
* Add asynchronous name resolving. http://curl.haxx.se/dev/async-resolver.txt
This should be made to work on most of the supported platforms, or
otherwise it isn't really interesting.
* Strip any trailing CR from the error message when Curl_failf() is used.
* Data sharing. Tell which easy handles within a multi handle that should
share cookies, connection cache, dns cache, ssl session cache.
* Mutexes. By adding mutex callback support, the 'data sharing' mentioned
above can be made between several easy handles running in different threads
too. The actual mutex implementations will be left for the application to
implement, libcurl will merely call 'getmutex' and 'leavemutex' callbacks.
* No-faster-then-this transfers. Many people have limited bandwidth and they
want the ability to make sure their transfers never use more bandwith than
they think is good.
* Set the SO_KEEPALIVE socket option to make libcurl notice and disconnect
very long time idle connections.
* Make sure we don't ever loop because of non-blocking sockets return
EWOULDBLOCK or similar. This concerns the HTTP request sending (and
especially regular HTTP POST), the FTP command sending etc.
* Go through the code and verify that libcurl deals with big files >2GB and
>4GB all over. Bug reports indicate that it doesn't currently work
properly.
DOCUMENTATION
* Document all CURLcode error codes, why they happen and what most likely
will make them not happen again.
will make them not happen again. In a libcurl point of view.
FTP
@@ -54,11 +74,7 @@ TODO
already working http dito works. It of course requires that 'MDTM' works,
and it isn't a standard FTP command.
* Suggested on the mailing list: CURLOPT_FTP_MKDIR...!
* Always use the FTP SIZE command before downloading, as that makes it more
likely that we know the size when downloading. Some sites support SIZE but
don't show the size in the RETR response!
* Add FTPS support with SSL for the data connection too.
HTTP
@@ -67,6 +83,12 @@ TODO
encoding. [http://curl.haxx.se/dev/HTTP-PUT-stdin.txt] When the filter
system mentioned above gets real, it'll be a piece of cake to add.
* Pass a list of host name to libcurl to which we allow the user name and
password to get sent to. Currently, it only get sent to the host name that
the first URL uses (to prevent others from being able to read it), but this
also prevents the authentication info from getting sent when following
locations to legitimate other host names.
* "Content-Encoding: compress/gzip/zlib" HTTP 1.1 clearly defines how to get
and decode compressed documents. There is the zlib that is pretty good at
decompressing stuff. This work was started in October 1999 but halted again
@@ -83,34 +105,66 @@ TODO
http://www.innovation.ch/java/ntlm.html that contains detailed reverse-
engineered info.
* RFC2617 compliance, "Digest Access Authentication"
A valid test page seem to exist at:
http://hopf.math.nwu.edu/testpage/digest/
And some friendly person's server source code is available at
http://hopf.math.nwu.edu/digestauth/index.html
Then there's the Apache mod_digest source code too of course. It seems as
if Netscape doesn't support this, and not many servers do. Although this is
a lot better authentication method than the more common "Basic". Basic
sends the password in cleartext over the network, this "Digest" method uses
a challange-response protocol which increases security quite a lot.
* RFC2617 compliance, "Digest Access Authentication" A valid test page seem
to exist at: http://hopf.math.nwu.edu/testpage/digest/ And some friendly
person's server source code is available at
http://hopf.math.nwu.edu/digestauth/index.html Then there's the Apache
mod_digest source code too of course. It seems as if Netscape doesn't
support this, and not many servers do. Although this is a lot better
authentication method than the more common "Basic". Basic sends the
password in cleartext over the network, this "Digest" method uses a
challange-response protocol which increases security quite a lot.
* Pipelining. Sending multiple requests before the previous one(s) are done.
This could possibly be implemented using the multi interface to queue
requests and the response data.
TELNET
* Make TELNET work on windows98!
* Reading input (to send to the remote server) on stdin is a crappy solution
for library purposes. We need to invent a good way for the application to
be able to provide the data to send.
* Move the telnet support's network select() loop go away and merge the code
into the main transfer loop. Until this is done, the multi interface won't
work for telnet.
SSL
* If you really want to improve the SSL situation, you should probably have a
look at SSL cafile loading as well - quick traces look to me like these are
done on every request as well, when they should only be necessary once per
ssl context (or once per handle). Even better would be to support the SSL
CAdir option - instead of loading all of the root CA certs for every
request, this option allows you to only read the CA chain that is actually
required (into the cache)...
* Add an interface to libcurl that enables "session IDs" to get
exported/imported. Cris Bailiff said: "OpenSSL has functions which can
serialise the current SSL state to a buffer of your choice, and
recover/reset the state from such a buffer at a later date - this is used
by mod_ssl for apache to implement and SSL session ID cache"
by mod_ssl for apache to implement and SSL session ID cache". This whole
idea might become moot if we enable the 'data sharing' as mentioned in the
LIBCURL label above.
* OpenSSL supports a callback for customised verification of the peer
certificate, but this doesn't seem to be exposed in the libcurl APIs. Could
it be? There's so much that could be done if it were! (brought by Chris
Clark)
* Make curl's SSL layer option capable of using other free SSL libraries.
Such as the Mozilla Security Services
(http://www.mozilla.org/projects/security/pki/nss/) and GNUTLS
(http://gnutls.hellug.gr/)
LDAP
* Look over the implementation. The looping will have to "go away" from the
lib/ldap.c source file and get moved to the main network code so that the
multi interface and friends will work for LDAP as well.
CLIENT
* "curl ftp://site.com/*.txt"
@@ -119,11 +173,22 @@ TODO
the same syntax to specify several files to get uploaded (using the same
persistant connection), using -T.
* Say you have a list of FTP addresses to download in a file named
ftp-list.txt: "cat ftp-list.txt | xargs curl -O -O -O [...]". curl _needs_
an "-Oalways" flag -- all addresses on the command line use the base
filename to store locally. Else a script must precount the # of URLs,
construct the proper number of "-O"s...
* When the multi interface has been implemented and proved to work, the
client could be told to use maximum N simultaneous transfers and then just
make sure that happens. It should of course not make more than one
connection to the same remote host.
* Extending the capabilities of the multipart formposting. How about leaving
the ';type=foo' syntax as it is and adding an extra tag (headers) which
works like this: curl -F "coolfiles=@fil1.txt;headers=@fil1.hdr" where
fil1.hdr contains extra headers like
Content-Type: text/plain; charset=KOI8-R"
Content-Transfer-Encoding: base64
X-User-Comment: Please don't use browser specific HTML code
which should overwrite the program reasonable defaults (plain/text,
8bit...) (Idea brough to us by kromJx)
TEST SUITE

View File

@@ -2,7 +2,7 @@
.\" nroff -man curl-config.1
.\" Written by Daniel Stenberg
.\"
.TH curl-config 1 "16 August 2001" "Curl 7.8.1" "curl-config manual"
.TH curl-config 1 "21 January 2002" "Curl 7.9.3" "curl-config manual"
.SH NAME
curl-config \- Get information about a libcurl installation
.SH SYNOPSIS
@@ -11,6 +11,8 @@ curl-config \- Get information about a libcurl installation
.B curl-config
displays information about a previous curl and libcurl installation.
.SH OPTIONS
.IP "--cc"
Displays the compiler used to build libcurl.
.IP "--cflags"
Set of compiler options (CFLAGS) to use when compiling files that use
libcurl. Currently that is only thw include path to the curl include files.
@@ -38,18 +40,23 @@ major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl
.SH "EXAMPLES"
What linker options do I need when I link with libcurl?
curl-config --libs
$ curl-config --libs
What compiler options do I need when I compile using libcurl functions?
curl-config --cflags
$ curl-config --cflags
How do I know if libcurl was built with SSL support?
curl-config --feature | grep SSL
$ curl-config --feature | grep SSL
What's the installed libcurl version?
curl-config --version
$ curl-config --version
How do I build a single file with a one-line command?
$ `curl-config --cc --cflags --libs` -o example example.c
.SH "SEE ALSO"
.BR curl (1)

View File

@@ -2,7 +2,7 @@
.\" nroff -man curl.1
.\" Written by Daniel Stenberg
.\"
.TH curl 1 "30 Nov 2001" "Curl 7.9.2" "Curl Manual"
.TH curl 1 "25 Feb 2002" "Curl 7.9.5" "Curl Manual"
.SH NAME
curl \- transfer a URL
.SH SYNOPSIS
@@ -510,7 +510,7 @@ password is specified, curl will ask for it interactively.
If this option is used several times, the last one will be used.
.IP "--url <URL>"
Specify a URL to fetch. This option is mostly handy when you wanna specify
Specify a URL to fetch. This option is mostly handy when you want to specify
URL(s) in a config file.
This option may be used any number of times. To control where this URL is written, use the
@@ -538,7 +538,7 @@ write "@-".
The variables present in the output format will be substituted by the value or
text that curl thinks fit, as described below. All variables are specified
like %{variable_name} and to output a normal % you just write them like
%%. You can output a newline by using \\n, a carrige return with \\r and a tab
%%. You can output a newline by using \\n, a carriage return with \\r and a tab
space with \\t.
.B NOTE:
@@ -594,6 +594,9 @@ The average download speed that curl measured for the complete download.
.TP
.B speed_upload
The average upload speed that curl measured for the complete upload.
.TP
.B content_type
The Content-Type of the requested document, if there was any. (Added in 7.9.5)
.RE
If this option is used several times, the last one will be used.
@@ -788,7 +791,7 @@ Internal error. A function was called in a bad order.
.IP 45
Interface error. A specified outgoing interface could not be used.
.IP 46
Bad password entered. An error was signalled when the password was entered.
Bad password entered. An error was signaled when the password was entered.
.IP 47
Too many redirects. When following redirects, curl hit the maximum amount.
.IP 48

View File

@@ -2,7 +2,7 @@
.\" nroff -man [file]
.\" $Id$
.\"
.TH curl_easy_init 3 "5 March 2001" "libcurl 7.6.1" "libcurl Manual"
.TH curl_easy_init 3 "31 Jan 2001" "libcurl 7.9.4" "libcurl Manual"
.SH NAME
curl_easy_getinfo - Extract information from a curl session (added in 7.4)
.SH SYNOPSIS
@@ -30,9 +30,11 @@ Pass a pointer to a long to receive the last received HTTP code.
.TP
.B CURLINFO_FILETIME
Pass a pointer to a long to receive the remote time of the retrieved
document. If you get 0, it can be because of many reasons (unknown, the server
hides it or the server doesn't support the command that tells document time
etc) and the time of the document is unknown. (Added in 7.5)
document. If you get -1, it can be because of many reasons (unknown, the
server hides it or the server doesn't support the command that tells document
time etc) and the time of the document is unknown. Note that you must tell the
server to collect this information before the transfer is made, by using the
CURLOPT_FILETIME option to \fIcurl_easy_setopt(3)\fP. (Added in 7.5)
.TP
.B CURLINFO_TOTAL_TIME
Pass a pointer to a double to receive the total transaction time in seconds
@@ -95,6 +97,12 @@ is the value read from the Content-Length: field. (Added in 7.6.1)
.B CURLINFO_CONTENT_LENGTH_UPLOAD
Pass a pointer to a double to receive the specified size of the upload.
(Added in 7.6.1)
.TP
.B CURLINFO_CONTENT_TYPE
Pass a pointer to a 'char *' to receive the content-type of the downloaded
object. This is the value read from the Content-Type: field. If you get NULL,
it means that the server didn't send a valid Content-Type header or that the
protocol used doesn't support this. (Added in 7.9.4)
.PP
.SH RETURN VALUE

View File

@@ -319,13 +319,59 @@ with \fIcurl_easy_cleanup(3)\fP.
.TP
.B CURLOPT_SSLCERT
Pass a pointer to a zero terminated string as parameter. The string should be
the file name of your certificate in PEM format.
the file name of your certificate. The default format is "PEM" and can be
changed with \fICURLOPT_SSLCERTTYPE\fP.
.TP
.B CURLOPT_SSLCERTTYPE
Pass a pointer to a zero terminated string as parameter. The string should be
the format of your certificate. Supported formats are "PEM" and "DER". (Added
in 7.9.3)
.TP
.B CURLOPT_SSLCERTPASSWD
Pass a pointer to a zero terminated string as parameter. It will be used as
the password required to use the CURLOPT_SSLCERT certificate. If the password
is not supplied, you will be prompted for it. \fICURLOPT_PASSWDFUNCTION\fP can
be used to set your own prompt function.
\fBNOTE:\fPThis option is replaced by \fICURLOPT_SSLKEYPASSWD\fP and only
cept for backward compatibility. You never needed a pass phrase to load
a certificate but you need one to load your private key.
.TP
.B CURLOPT_SSLKEY
Pass a pointer to a zero terminated string as parameter. The string should be
the file name of your private key. The default format is "PEM" and can be
changed with \fICURLOPT_SSLKEYTYPE\fP. (Added in 7.9.3)
.TP
.B CURLOPT_SSLKEYTYPE
Pass a pointer to a zero terminated string as parameter. The string should be
the format of your private key. Supported formats are "PEM", "DER" and "ENG".
(Added in 7.9.3)
\fBNOTE:\fPThe format "ENG" enables you to load the private key from a crypto
engine. in this case \fICURLOPT_SSLKEY\fP is used as an identifier passed to
the engine. You have to set the crypto engine with \fICURLOPT_SSL_ENGINE\fP.
.TP
.B CURLOPT_SSLKEYASSWD
Pass a pointer to a zero terminated string as parameter. It will be used as
the password required to use the \fICURLOPT_SSLKEY\fP private key. If the
password is not supplied, you will be prompted for
it. \fICURLOPT_PASSWDFUNCTION\fP can be used to set your own prompt function.
(Added in 7.9.3)
.TP
.B CURLOPT_SSL_ENGINE
Pass a pointer to a zero terminated string as parameter. It will be used as
the identifier for the crypto engine you want to use for your private
key. (Added in 7.9.3)
\fBNOTE:\fPIf the crypto device cannot be loaded,
\fICURLE_SSL_ENGINE_NOTFOUND\fP is returned.
.TP
.B CURLOPT_SSL_ENGINEDEFAULT
Sets the actual crypto engine as the default for (asymetric) crypto
operations. (Added in 7.9.3)
\fBNOTE:\fPIf the crypto device cannot be set,
\fICURLE_SSL_ENGINE_SETFAILED\fP is returned.
.TP
.B CURLOPT_CRLF
Convert Unix newlines to CRLF newlines on FTP uploads.

View File

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

View File

@@ -10,6 +10,10 @@ them for submission in future packages and on the web site.
The Makefile.example is an example makefile that could be used to build these
examples. Just edit the file according to your system and requirements first.
Most examples should build fine using a command line like this:
$ gcc `curl-config --cflags` `curl-config --libs` -o example example.c
Try the php/examples/ directory for PHP programming snippets!
*PLEASE* do not use the curl.haxx.se site as a test target for your libcurl

View File

@@ -14,31 +14,70 @@
#include <curl/types.h>
#include <curl/easy.h>
/* to make this work under windows, use the win32-functions from the
win32socket.c file as well */
/*
* This is an example showing how to get a single file from an FTP server.
* It delays the actual destination file creation until the first write
* callback so that it won't create an empty file in case the remote file
* doesn't exist or something else fails.
*/
int main(int argc, char **argv)
struct FtpFile {
char *filename;
FILE *stream;
};
int my_fwrite(void *buffer, size_t size, size_t nmemb, void *stream)
{
struct FtpFile *out=(struct FtpFile *)stream;
if(out && !out->stream) {
/* open file for writing */
out->stream=fopen(out->filename, "wb");
if(!out->stream)
return -1; /* failure, can't open file to write */
}
return fwrite(buffer, size, nmemb, out->stream);
}
int main(void)
{
CURL *curl;
CURLcode res;
FILE *ftpfile;
struct FtpFile ftpfile={
"curl.tar.gz", /* name to store the file as if succesful */
NULL
};
/* local file name to store the file as */
ftpfile = fopen("curl.tar.gz", "wb"); /* b is binary for win */
curl_global_init(CURL_GLOBAL_DEFAULT);
curl = curl_easy_init();
if(curl) {
/* Get curl 7.7 from sunet.se's FTP site: */
/* Get curl 7.9.2 from sunet.se's FTP site: */
curl_easy_setopt(curl, CURLOPT_URL,
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.7.tar.gz");
curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
"ftp://ftp.sunet.se/pub/www/utilities/curl/curl-7.9.2.tar.gz");
/* Define our callback to get called when there's data to be written */
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, my_fwrite);
/* Set a pointer to our struct to pass to the callback */
curl_easy_setopt(curl, CURLOPT_FILE, &ftpfile);
/* Switch on full protocol/debug output */
curl_easy_setopt(curl, CURLOPT_VERBOSE, TRUE);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
if(CURLE_OK != res) {
/* we failed */
fprintf(stderr, "curl told us %d\n", res);
}
}
fclose(ftpfile); /* close the local file */
if(ftpfile.stream)
fclose(ftpfile.stream); /* close the local file */
curl_global_cleanup();
return 0;
}

View File

@@ -0,0 +1,61 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*/
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
/*
* Similar to ftpget.c but this also stores the received response-lines
* in a separate file using our own callback!
*
* This functionality was introduced in libcurl 7.9.3.
*/
size_t
write_response(void *ptr, size_t size, size_t nmemb, void *data)
{
FILE *writehere = (FILE *)data;
return fwrite(ptr, size, nmemb, writehere);
}
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
FILE *ftpfile;
FILE *respfile;
/* local file name to store the file as */
ftpfile = fopen("ftp-list", "wb"); /* b is binary, needed on win32 */
/* local file name to store the FTP server's response lines in */
respfile = fopen("ftp-responses", "wb"); /* b is binary, needed on win32 */
curl = curl_easy_init();
if(curl) {
/* Get a file listing from sunet */
curl_easy_setopt(curl, CURLOPT_URL, "ftp://ftp.sunet.se/");
curl_easy_setopt(curl, CURLOPT_FILE, ftpfile);
curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, write_response);
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, respfile);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
fclose(ftpfile); /* close the local file */
fclose(respfile); /* close the response file */
return 0;
}

35
docs/examples/http-post.c Normal file
View File

@@ -0,0 +1,35 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*/
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
/* First set the URL that is about to receive our POST. This URL can
just as well be a https:// URL if that is what should receive the
data. */
curl_easy_setopt(curl, CURLOPT_URL, "http://postit.example.com/moo.cgi");
/* Now specify the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, "name=daniel&project=curl");
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}

View File

@@ -1,71 +0,0 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* $Id$
*
* Example code that uploads a file name 'foo' to a remote script that accepts
* "HTML form based" (as described in RFC1738) uploads using HTTP POST.
*
* The imaginary form we'll fill in looks like:
*
* <form method="post" enctype="multipart/form-data" action="examplepost.cgi">
* Enter file: <input type="file" name="sendfile" size="40">
* Enter file name: <input type="text" name="filename" size="30">
* <input type="submit" value="send" name="submit">
* </form>
*
* This exact source code has not been verified to work.
*/
/* to make this work under windows, use the win32-functions from the
win32socket.c file as well */
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
int main(int argc, char **argv)
{
CURL *curl;
CURLcode res;
struct HttpPost *formpost=NULL;
struct HttpPost *lastptr=NULL;
/* Fill in the file upload field */
curl_formparse("sendfile=@foo",
&formpost,
&lastptr);
/* Fill in the filename field */
curl_formparse("filename=foo",
&formpost,
&lastptr);
/* Fill in the submit field too, even if this is rarely needed */
curl_formparse("submit=send",
&formpost,
&lastptr);
curl = curl_easy_init();
if(curl) {
/* what URL that receives this POST */
curl_easy_setopt(curl, CURLOPT_URL, "http://curl.haxx.se/examplepost.cgi");
curl_easy_setopt(curl, CURLOPT_HTTPPOST, formpost);
res = curl_easy_perform(curl);
/* always cleanup */
curl_easy_cleanup(curl);
/* then cleanup the formpost chain */
curl_formfree(formpost);
}
return 0;
}

View File

@@ -9,27 +9,16 @@
*/
#include <stdio.h>
#include <curl/curl.h>
#include <curl/types.h>
#include <curl/easy.h>
/* to make this work under windows, use the win32-functions from the
win32socket.c file as well */
int main(int argc, char **argv)
int main(void)
{
CURL *curl;
CURLcode res;
FILE *headerfile;
headerfile = fopen("dumpit", "w");
curl = curl_easy_init();
if(curl) {
/* what call to write: */
curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
curl_easy_setopt(curl, CURLOPT_WRITEHEADER, headerfile);
res = curl_easy_perform(curl);
/* always cleanup */

View File

@@ -28,6 +28,9 @@
4.2. if the format of the key file is DER, set pKeyType to "DER"
!! verify of the server certificate is not implemented here !!
**** This example only works with libcurl 7.9.3 and later! ****
*/
int main(int argc, char **argv)
@@ -37,6 +40,7 @@ int main(int argc, char **argv)
FILE *headerfile;
const char *pCertFile = "testcert.pem";
const char *pCACertFile="cacert.pem"
const char *pKeyName;
const char *pKeyType;
@@ -96,6 +100,10 @@ int main(int argc, char **argv)
curl_easy_setopt(curl,CURLOPT_SSLKEYTYPE,pKeyType);
/* set the private key (file or ID in engine) */
curl_easy_setopt(curl,CURLOPT_SSLKEY,pKeyName);
/* set the file with the certs vaildating the server */
curl_easy_setopt(curl,CURLOPT_CAINFO,pCACertFile);
/* disconnect if we can't validate server's cert */
curl_easy_setopt(curl,CURLOPT_SSL_VERIFYPEER,1);
res = curl_easy_perform(curl);
break; /* we are done... */

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

@@ -0,0 +1,888 @@
$Id$
_ _ ____ _
___| | | | _ \| |
/ __| | | | |_) | |
| (__| |_| | _ <| |___
\___|\___/|_| \_\_____|
PROGRAMMING WITH LIBCURL
About this Document
This document will attempt to describe the general principle and some basic
approaches to consider when programming with libcurl. The text will focus
mainly on the C interface but might apply fairly well on other interfaces as
well as they usually follow the C one pretty closely.
This document will refer to 'the user' as the person writing the source code
that uses libcurl. That would probably be you or someone in your position.
What will be generally refered to as 'the program' will be the collected
source code that you write that is using libcurl for transfers. The program
is outside libcurl and libcurl is outside of the program.
To get the more details on all options and functions described herein, please
refer to their respective man pages.
Building
There are many different ways to build C programs. This chapter will assume a
unix-style build process. If you use a different build system, you can still
read this to get general information that may apply to your environment as
well.
Compiling the Program
Your compiler needs to know where the libcurl headers are
located. Therefore you must set your compiler's include path to point to
the directory where you installed them. The 'curl-config'[3] tool can be
used to get this information:
$ curl-config --cflags
Linking the Program with libcurl
When having compiled the program, you need to link your object files to
create a single executable. For that to succeed, you need to link with
libcurl and possibly also with other libraries that libcurl itself depends
on. Like OpenSSL librararies, but even some standard OS libraries may be
needed on the command line. To figure out which flags to use, once again
the 'curl-config' tool comes to the rescue:
$ curl-config --libs
SSL or Not
libcurl can be built and customized in many ways. One of the things that
varies from different libraries and builds is the support for SSL-based
transfers, like HTTPS and FTPS. If OpenSSL was detected properly at
build-time, libcurl will be built with SSL support. To figure out if an
installed libcurl has been built with SSL support enabled, use
'curl-config' like this:
$ curl-config --feature
And if SSL is supported, the keyword 'SSL' will be written to stdout,
possibly together with a few other features that can be on and off on
different libcurls.
Portable Code in a Portable World
The people behind libcurl have put a considerable effort to make libcurl work
on a large amount of different operating systems and environments.
You program libcurl the same way on all platforms that libcurl runs on. There
are only very few minor considerations that differs. If you just make sure to
write your code portable enough, you may very well create yourself a very
portable program. libcurl shouldn't stop you from that.
Global Preparation
The program must initialize some of the libcurl functionality globally. That
means it should be done exactly once, no matter how many times you intend to
use the library. Once for your program's entire life time. This is done using
curl_global_init()
and it takes one parameter which is a bit pattern that tells libcurl what to
intialize. Using CURL_GLOBAL_ALL will make it initialize all known internal
sub modules, and might be a good default option. The current two bits that
are specified are:
CURL_GLOBAL_WIN32 which only does anything on Windows machines. When used on
a Windows machine, it'll make libcurl intialize the win32 socket
stuff. Without having that initialized properly, your program cannot use
sockets properly. You should only do this once for each application, so if
your program already does this or of another library in use does it, you
should not tell libcurl to do this as well.
CURL_GLOBAL_SSL which only does anything on libcurls compiled and built
SSL-enabled. On these systems, this will make libcurl init OpenSSL properly
for this application. This is only needed to do once for each application so
if your program or another library already does this, this bit should not be
needed.
libcurl has a default protection mechanism that detects if curl_global_init()
hasn't been called by the time curl_easy_perform() is called and if that is
the case, libcurl runs the function itself with a guessed bit pattern. Please
note that depending solely on this is not considered nice nor very good.
When the program no longer uses libcurl, it should call
curl_global_cleanup(), which is the opposite of the init call. It will then
do the reversed operations to cleanup the resources the curl_global_init()
call initialized.
Repeated calls to curl_global_init() and curl_global_cleanup() should be
avoided. They should only be called once each.
Handle the Easy libcurl
libcurl version 7 is oriented around the so called easy interface. All
operations in the easy interface are prefixed with 'curl_easy'.
Future libcurls will also offer the multi interface. More about that
interface, what it is targeted for and how to use it is still only debated on
the libcurl mailing list and developer web pages. Join up to discuss and
figure out!
To use the easy interface, you must first create yourself an easy handle. You
need one handle for each easy session you want to perform. Basicly, you
should use one handle for every thread you plan to use for transferring. You
must never share the same handle in multiple threads.
Get an easy handle with
easyhandle = curl_easy_init();
It returns an easy handle. Using that you proceed to the next step: setting
up your preferred actions. A handle is just a logic entity for the upcoming
transfer or series of transfers.
You set properties and options for this handle using curl_easy_setopt(). They
control how the subsequent transfer or transfers will be made. Options remain
set in the handle until set again to something different. Alas, multiple
requests using the same handle will use the same options.
Many of the informationals you set in libcurl are "strings", pointers to data
terminated with a zero byte. Keep in mind that when you set strings with
curl_easy_setopt(), libcurl will not copy the data. It will merely point to
the data. You MUST make sure that the data remains available for libcurl to
use until finished or until you use the same option again to point to
something else.
One of the most basic properties to set in the handle is the URL. You set
your preferred URL to transfer with CURLOPT_URL in a manner similar to:
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://curl.haxx.se/");
Let's assume for a while that you want to receive data as the URL indentifies
a remote resource you want to get here. Since you write a sort of application
that needs this transfer, I assume that you would like to get the data passed
to you directly instead of simply getting it passed to stdout. So, you write
your own function that matches this prototype:
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp);
You tell libcurl to pass all data to this function by issuing a function
similar to this:
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data);
You can control what data your function get in the forth argument by setting
another property:
curl_easy_setopt(easyhandle, CURLOPT_FILE, &internal_struct);
Using that property, you can easily pass local data between your application
and the function that gets invoked by libcurl. libcurl itself won't touch the
data you pass with CURLOPT_FILE.
libcurl offers its own default internal callback that'll take care of the
data if you don't set the callback with CURLOPT_WRITEFUNCTION. It will then
simply output the received data to stdout. You can have the default callback
write the data to a different file handle by passing a 'FILE *' to a file
opened for writing with the CURLOPT_FILE option.
Now, we need to take a step back and have a deep breath. Here's one of those
rare platform-dependent nitpicks. Did you spot it? On some platforms[2],
libcurl won't be able to operate on files opened by the program. Thus, if you
use the default callback and pass in a an open file with CURLOPT_FILE, it
will crash. You should therefore avoid this to make your program run fine
virtually everywhere.
There are of course many more options you can set, and we'll get back to a
few of them later. Let's instead continue to the actual transfer:
success = curl_easy_perform(easyhandle);
The curl_easy_perform() will connect to the remote site, do the necessary
commands and receive the transfer. Whenever it receives data, it calls the
callback function we previously set. The function may get one byte at a time,
or it may get many kilobytes at once. libcurl delivers as much as possible as
often as possible. Your callback function should return the number of bytes
it "took care of". If that is not the exact same amount of bytes that was
passed to it, libcurl will abort the operation and return with an error code.
When the transfer is complete, the function returns a return code that
informs you if it succeeded in its mission or not. If a return code isn't
enough for you, you can use the CURLOPT_ERRORBUFFER to point libcurl to a
buffer of yours where it'll store a human readable error message as well.
If you then want to transfer another file, the handle is ready to be used
again. Mind you, it is even preferred that you re-use an existing handle if
you intend to make another transfer. libcurl will then attempt to re-use the
previous
When It Doesn't Work
There will always be times when the transfer fails for some reason. You might
have set the wrong libcurl option or misunderstood what the libcurl option
actually does, or the remote server might return non-standard replies that
confuse the library which then confuses your program.
There's one golden rule when these things occur: set the CURLOPT_VERBOSE
option to TRUE. It'll cause the library to spew out the entire protocol
details it sends, some internal info and some received protcol data as well
(especially when using FTP). If you're using HTTP, adding the headers in the
received output to study is also a clever way to get a better understanding
wht the server behaves the way it does. Include headers in the normal body
output with CURLOPT_HEADER set TRUE.
Of course there are bugs left. We need to get to know about them to be able
to fix them, so we're quite dependent on your bug reports! When you do report
suspected bugs in libcurl, please include as much details you possibly can: a
protocol dump that CURLOPT_VERBOSE produces, library version, as much as
possible of your code that uses libcurl, operating system name and version,
compiler name and version etc.
Getting some in-depth knowledge about the protocols involved is never wrong,
and if you're trying to do funny things, you might very well understand
libcurl and how to use it better if you study the appropriate RFC documents
at least briefly.
Upload Data to a Remote Site
libcurl tries to keep a protocol independent approach to most transfers, thus
uploading to a remote FTP site is very similar to uploading data to a HTTP
server with a PUT request.
Of course, first you either create an easy handle or you re-use one existing
one. Then you set the URL to operate on just like before. This is the remote
URL, that we now will upload.
Since we write an application, we most likely want libcurl to get the upload
data by asking us for it. To make it do that, we set the read callback and
the custom pointer libcurl will pass to our read callback. The read callback
should have a prototype similar to:
size_t function(char *bufptr, size_t size, size_t nitems, void *userp);
Where bufptr is the pointer to a buffer we fill in with data to upload and
size*nitems is the size of the buffer and therefore also the maximum amount
of data we can return to libcurl in this call. The 'userp' pointer is the
custom pointer we set to point to a struct of ours to pass private data
between the application and the callback.
curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function);
curl_easy_setopt(easyhandle, CURLOPT_INFILE, &filedata);
Tell libcurl that we want to upload:
curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, TRUE);
A few protocols won't behave properly when uploads are done without any prior
knowledge of the expected file size. HTTP PUT is one example [1]. So, set the
upload file size using the CURLOPT_INFILESIZE like this:
curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, file_size);
When you call curl_easy_perform() this time, it'll perform all the necessary
operations and when it has invoked the upload it'll call your supplied
callback to get the data to upload. The program should return as much data as
possible in every invoke, as that is likely to make the upload perform as
fast as possible. The callback should return the number of bytes it wrote in
the buffer. Returning 0 will signal the end of the upload.
Passwords
Many protocols use or even require that user name and password are provided
to be able to download or upload the data of your choice. libcurl offers
several ways to specify them.
Most protocols support that you specify the name and password in the URL
itself. libcurl will detect this and use them accordingly. This is written
like this:
protocol://user:password@example.com/path/
If you need any odd letters in your user name or password, you should enter
them URL encoded, as %XX where XX is a two-digit hexadecimal number.
libcurl also provides options to set various passwords. The user name and
password as shown embedded in the URL can instead get set with the
CURLOPT_USERPWD option. The argument passed to libcurl should be a char * to
a string in the format "user:password:". In a manner like this:
curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret");
Another case where name and password might be needed at times, is for those
users who need to athenticate themselves to a proxy they use. libcurl offers
another option for this, the CURLOPT_PROXYUSERPWD. It is used quite similar
to the CURLOPT_USERPWD option like this:
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret");
There's a long time unix "standard" way of storing ftp user names and
passwords, namely in the $HOME/.netrc file. The file should be made private
so that only the user may read it (see also the "Security Considerations"
chapter), as it might contain the password in plain text. libcurl has the
ability to use this file to figure out what set of user name and password to
use for a particular host. As an extension to the normal functionality,
libcurl also supports this file for non-FTP protocols such as HTTP. To make
curl use this file, use the CURLOPT_NETRC option:
curl_easy_setopt(easyhandle, CURLOPT_NETRC, TRUE);
And a very basic example of how such a .netrc file may look like:
machine myhost.mydomain.com
login userlogin
password secretword
All these examples have been cases where the password has been optional, or
at least you could leave it out and have libcurl attempt to do its job
without it. There are times when the password isn't optional, like when
you're using an SSL private key for secure transfers.
You can in this situation either pass a password to libcurl to use to unlock
the private key, or you can let libcurl prompt the user for it. If you prefer
to ask the user, then you can provide your own callback function that will be
called when libcurl wants the password. That way, you can control how the
question will appear to the user.
To pass the known private key password to libcurl:
curl_easy_setopt(easyhandle, CURLOPT_SSLKEYPASSWD, "keypassword");
To make a password callback:
int enter_passwd(void *ourp, const char *prompt, char *buffer, int len);
curl_easy_setopt(easyhandle, CURLOPT_PASSWDFUNCTION, enter_passwd);
HTTP POSTing
We get many questions regarding how to issue HTTP POSTs with libcurl the
proper way. This chapter will thus include examples using both different
versions of HTTP POST that libcurl supports.
The first version is the simple POST, the most common version, that most HTML
pages using the <form> tag uses. We provide a pointer to the data and tell
libcurl to post it all to the remote site:
char *data="name=daniel&project=curl";
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/");
curl_easy_perform(easyhandle); /* post away! */
Simple enough, huh? Since you set the POST options with the
CURLOPT_POSTFIELDS, this automaticly switches the handle to use POST in the
upcoming request.
Ok, so what if you want to post binary data that also requires you to set the
Content-Type: header of the post? Well, binary posts prevents libcurl from
being able to do strlen() on the data to figure out the size, so therefore we
must tell libcurl the size of the post data. Setting headers in libcurl
requests are done in a generic way, by building a list of our own headers and
then passing that list to libcurl.
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: text/xml");
/* post binary data */
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELD, binaryptr);
/* set the size of the postfields data */
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDSIZE, 23);
/* pass our list of custom made headers */
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(easyhandle); /* post away! */
curl_slist_free_all(headers); /* free the header list */
While the simple examples above cover the majority of all cases where HTTP
POST operations are required, they don't do multipart formposts. Multipart
formposts were introduced as a better way to post (possibly large) binary
data and was first documented in the RFC1867. They're called multipart
because they're built by a chain of parts, each being a single unit. Each
part has its own name and contents. You can in fact create and post a
multipart formpost with the regular libcurl POST support described above, but
that would require that you build a formpost yourself and provide to
libcurl. To make that easier, libcurl provides curl_formadd(). Using this
function, you add parts to the form. When you're done adding parts, you post
the whole form.
The following example sets two simple text parts with plain textual contents,
and then a file with binary contents and upload the whole thing.
struct HttpPost *post=NULL;
struct HttpPost *last=NULL;
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "name",
CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "project",
CURLFORM_COPYCONTENTS, "curl", CURLFORM_END);
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "logotype-image",
CURLFORM_FILECONTENT, "curl.png", CURLFORM_END);
/* Set the form info */
curl_easy_setopt(easyhandle, CURLOPT_HTTPPOST, post);
curl_easy_perform(easyhandle); /* post away! */
/* free the post data again */
curl_formfree(post);
Multipart formposts are chains of parts using MIME-style separators and
headers. It means that each one of these separate parts get a few headers set
that describe the individual content-type, size etc. To enable your
application to handicraft this formpost even more, libcurl allows you to
supply your own set of custom headers to such an individual form part. You
can of course supply headers to as many parts you like, but this little
example will show how you set headers to one specific part when you add that
to the post handle:
struct curl_slist *headers=NULL;
headers = curl_slist_append(headers, "Content-Type: text/xml");
curl_formadd(&post, &last,
CURLFORM_COPYNAME, "logotype-image",
CURLFORM_FILECONTENT, "curl.xml",
CURLFORM_CONTENTHEADER, headers,
CURLFORM_END);
curl_easy_perform(easyhandle); /* post away! */
curl_formfree(post); /* free post */
curl_slist_free_all(post); /* free custom header list */
Since all options on an easyhandle are "sticky", they remain the same until
changed even if you do call curl_easy_perform(), you may need to tell curl to
go back to a plain GET request if you intend to do such a one as your next
request. You force an easyhandle to back to GET by using the CURLOPT_HTTPGET
option:
curl_easy_setopt(easyhandle, CURLOPT_HTTPGET, TRUE);
Just setting CURLOPT_POSTFIELDS to "" or NULL will *not* stop libcurl from
doing a POST. It will just make it POST without any data to send!
Showing Progress
[ built-in progress meter, progress callback ]
libcurl with C++
There's basicly only one thing to keep in mind when using C++ instead of C
when interfacing libcurl:
"The Callbacks Must Be Plain C"
So if you want a write callback set in libcurl, you should put it within
'extern'. Similar to this:
extern "C" {
size_t write_data(void *ptr, size_t size, size_t nmemb,
void *ourpointer)
{
/* do what you want with the data */
}
}
This will of course effectively turn the callback code into C. There won't be
any "this" pointer available etc.
Proxies
What "proxy" means according to Merriam-Webster: "a person authorized to act
for another" but also "the agency, function, or office of a deputy who acts
as a substitute for another".
Proxies are exceedingly common these days. Companies often only offer
internet access to employees through their HTTP proxies. Network clients or
user-agents ask the proxy for docuements, the proxy does the actual request
and then it returns them.
libcurl has full support for HTTP proxies, so when a given URL is wanted,
libcurl will ask the proxy for it instead of trying to connect to the actual
host identified in the URL.
The fact that the proxy is a HTTP proxy puts certain restrictions on what can
actually happen. A requested URL that might not be a HTTP URL will be still
be passed to the HTTP proxy to deliver back to libcurl. This happens
transparantly, and an application may not need to know. I say "may", because
at times it is very important to understand that all operations over a HTTP
proxy is using the HTTP protocol. For example, you can't invoke your own
custom FTP commands or even proper FTP directory listings.
Proxy Options
To tell libcurl to use a proxy at a given port number:
curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080");
Some proxies require user authentication before allowing a request, and
you pass that information similar to this:
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password");
If you want to, you can specify the host name only in the CURLOPT_PROXY
option, and set the port number separately with CURLOPT_PROXYPORT.
Environment Variables
libcurl automaticly checks and uses a set of environment variables to know
what proxies to use for certain protocols. The names of the variables are
following an ancient de facto standard and are built up as
"[protocol]_proxy" (note the lower casing). Which makes the variable
'http_proxy' checked for a name of a proxy to use when the input URL is
HTTP. Following the same rule, the variable named 'ftp_proxy' is checked
for FTP URLs. Again, the proxies are always HTTP proxies, the different
names of the variables simply allows different HTTP proxies to be used.
The proxy environment variable contents should be in the format
"[protocol://]machine[:port]". Where the protocol:// part is simply
ignored if present (so http://proxy and bluerk://proxy will do the same)
and the optional port number specifies on which port the proxy operates on
the host. If not specified, the internal default port number will be used
and that is most likely *not* the one you would like it to be.
There are two special environment variables. 'all_proxy' is what sets
proxy for any URL in case the protocol specific variable wasn't set, and
'no_proxy' defines a list of hosts that should not use a proxy even though
a variable may say so. If 'no_proxy' is a plain asterisk ("*") it matches
all hosts.
SSL and Proxies
SSL is for secure point-to-point connections. This involves strong
encryption and similar things, which effectivly makes it impossible for a
proxy to operate as a "man in between" which the proxy's task is, as
previously discussed. Instead, the only way to have SSL work over a HTTP
proxy is to ask the proxy to tunnel trough everything without being able
to check or fiddle with the traffic.
Opening an SSL connection over a HTTP proxy is therefor a matter of asking
the proxy for a straight connection to the target host on a specified
port. This is made with the HTTP request CONNECT. ("please mr proxy,
connect me to that remote host").
Because of the nature of this operation, where the proxy has no idea what
kind of data that is passed in and out through this tunnel, this breaks
some of the very few advantages that come from using a proxy, such as
caching. Many organizations prevent this kind of tunneling to other
destination port numbers than 443 (which is the default HTTPS port
number).
Tunneling Through Proxy
As explained above, tunneling is required for SSL to work and often even
restricted to the operation intended for SSL; HTTPS.
This is however not the only time proxy-tunneling might offer benefits to
you or your application.
As tunneling opens a direct connection from your application to the remote
machine, it suddenly also re-introduces the ability to do non-HTTP
operations over a HTTP proxy. You can in fact use things such as FTP
upload or FTP custom commands this way.
Again, this is often prevented by the adminstrators of proxies and is
rarely allowed.
Tell libcurl to use proxy tunneling like this:
curl_easy_setopt(easyhandle, CURLOPT_HTTPPROXYTUNNEL, TRUE);
In fact, there might even be times when you want to do plain HTTP
operations using a tunnel like this, as it then enables you to operate on
the remote server instead of asking the proxy to do so. libcurl will not
stand in the way for such innovative actions either!
Proxy Auto-Config
Netscape first came up with this. It is basicly a web page (usually using
a .pac extension) with a javascript that when executed by the browser with
the requested URL as input, returns information to the browser on how to
connect to the URL. The returned information might be "DIRECT" (which
means no proxy should be used), "PROXY host:port" (to tell the browser
where the proxy for this particular URL is) or "SOCKS host:port" (to
direct the brower to a SOCKS proxy).
libcurl has no means to interpret or evaluate javascript and thus it
doesn't support this. If you get yourself in a position where you face
this nasty invention, the following advice have been mentioned and used in
the past:
- Depending on the javascript complexity, write up a script that
translates it to another language and execute that.
- Read the javascript code and rewrite the same logic in another language.
- Implement a javascript interpreted, people have successfully used the
Mozilla javascript engine in the past.
- Ask your admins to stop this, for a static proxy setup or similar.
Persistancy Is The Way to Happiness
Re-cycling the same easy handle several times when doing multiple requests is
the way to go.
After each single curl_easy_perform() operation, libcurl will keep the
connection alive and open. A subsequent request using the same easy handle to
the same host might just be able to use the already open connection! This
reduces network impact a lot.
Even if the connection is dropped, all connections involving SSL to the same
host again, will benefit from libcurl's session ID cache that drasticly
reduces re-connection time.
FTP connections that are kept alive saves a lot of time, as the command-
response roundtrips are skipped, and also you don't risk getting blocked
without permission to login again like on many FTP servers only allowing N
persons to be logged in at the same time.
libcurl caches DNS name resolving results, to make lookups of a previously
looked up name a lot faster.
Other interesting details that improve performance for subsequent requests
may also be added in the future.
Each easy handle will attempt to keep the last few connections alive for a
while in case they are to be used again. You can set the size of this "cache"
with the CURLOPT_MAXCONNECTS option. Default is 5. It is very seldom any
point in changing this value, and if you think of changing this it is often
just a matter of thinking again.
When the connection cache gets filled, libcurl must close an existing
connection in order to get room for the new one. To know which connection to
close, libcurl uses a "close policy" that you can affect with the
CURLOPT_CLOSEPOLICY option. There's only two polices implemented as of this
writing (libcurl 7.9.4) and they are:
CURLCLOSEPOLICY_LEAST_RECENTLY_USED simply close the one that hasn't been
used for the longest time. This is the default behavior.
CURLCLOSEPOLICY_OLDEST closes the oldest connection, the one that was
createst the longest time ago.
There are, or at least were, plans to support a close policy that would call
a user-specified callback to let the user be able to decide which connection
to dump when this is necessary and therefor is the CURLOPT_CLOSEFUNCTION an
existing option still today. Nothing ever uses this though and this will not
be used within the forseeable future either.
To force your upcoming request to not use an already existing connection (it
will even close one first if there happens to be one alive to the same host
you're about to operate on), you can do that by setting CURLOPT_FRESH_CONNECT
to TRUE. In a similar spirit, you can also forbid the upcoming request to be
"lying" around and possibly get re-used after the request by setting
CURLOPT_FORBID_REUSE to TRUE.
Customizing Operations
There is an ongoing development today where more and more protocols are built
upon HTTP for transport. This has obvious benefits as HTTP is a tested and
reliable protocol that is widely deployed and have excellent proxy-support.
When you use one of these protocols, and even when doing other kinds of
programming you may need to change the traditional HTTP (or FTP or...)
manners. You may need to change words, headers or various data.
libcurl is your friend here too.
If just changing the actual HTTP request keyword is what you want, like when
GET, HEAD or POST is not good enough for you, CURLOPT_CUSTOMREQUEST is there
for you. It is very simple to use:
curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "MYOWNRUQUEST");
When using the custom request, you change the request keyword of the actual
request you are performing. Thus, by default you make GET request but you can
also make a POST operation (as described before) and then replace the POST
keyword if you want to. You're the boss.
HTTP-like protocols pass a series of headers to the server when doing the
request, and you're free to pass any amount of extra headers that you think
fit. Adding headers are this easy:
struct curl_slist *headers;
headers = curl_slist_append(headers, "Hey-server-hey: how are you?");
headers = curl_slist_append(headers, "X-silly-content: yes");
/* pass our list of custom made headers */
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers);
curl_easy_perform(easyhandle); /* transfer http */
curl_slist_free_all(headers); /* free the header list */
... and if you think some of the internally generated headers, such as
User-Agent:, Accept: or Host: don't contain the data you want them to
contain, you can replace them by simply setting them too:
headers = curl_slist_append(headers, "User-Agent: 007");
headers = curl_slist_append(headers, "Host: munged.host.line");
If you replace an existing header with one with no contents, you will prevent
the header from being sent. Like if you want to completely prevent the
"Accept:" header to be sent, you can disable it with code similar to this:
headers = curl_slist_append(headers, "Accept:");
Both replacing and cancelling internal headers should be done with careful
consideration and you should be aware that you may violate the HTTP protocol
when doing so.
There's only one aspect left in the HTTP requests that we haven't yet
mentioned how to modify: the version field. All HTTP requests includes the
version number to tell the server which version we support. libcurl speak
HTTP 1.1 by default. Some very old servers don't like getting 1.1-requests
and when dealing with stubborn old things like that, you can tell libcurl to
use 1.0 instead by doing something like this:
curl_easy_setopt(easyhandle, CURLOPT_HTTP_VERSION, CURLHTTP_VERSION_1_0);
Not all protocols are HTTP-like, and thus the above may not help you when you
want to make for example your FTP transfers to behave differently.
Sending custom commands to a FTP server means that you need to send the
comands exactly as the FTP server expects them (RFC959 is a good guide here),
and you can only use commands that work on the control-connection alone. All
kinds of commands that requires data interchange and thus needs a
data-connection must be left to libcurl's own judgement. Also be aware that
libcurl will do its very best to change directory to the target directory
before doing any transfer, so if you change directory (with CWD or similar)
you might confuse libcurl and then it might not attempt to transfer the file
in the correct remote directory.
A little example that deletes a given file before an operation:
headers = curl_slist_append(headers, "DELE file-to-remove");
/* pass the list of custom commands to the handle */
curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers);
curl_easy_perform(easyhandle); /* transfer ftp data! */
curl_slist_free_all(headers); /* free the header list */
If you would instead want this operation (or chain of operations) to happen
_after_ the data transfer took place the option to curl_easy_setopt() would
instead be called CURLOPT_POSTQUOTE and used the exact same way.
The custom FTP command will be issued to the server in the same order they
are added to the list, and if a command gets an error code returned back from
the server, no more commands will be issued and libcurl will bail out with an
error code (CURLE_FTP_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE to
send commands before a transfer, no transfer will actually take place when a
quote command has failed.
If you set the CURLOPT_HEADER to true, you will tell libcurl to get
information about the target file and output "headers" about it. The headers
will be in "HTTP-style", looking like they do in HTTP.
The option to enable headers or to run custom FTP commands may be useful to
combine with CURLOPT_NOBODY. If this option is set, no actual file content
transfer will be performed.
Cookies Without Chocolate Chips
In the HTTP sense, a cookie is a name with an associated value. A server
sends the name and value to the client, and expects it to get sent back on
every subsequent request to the server that matches the particular conditions
set. The conditions include that the domain name and path match and that the
cookie hasn't become too old.
In real-world cases, servers send new cookies to replace existing one to
update them. Server use cookies to "track" users and to keep "sessions".
Cookies are sent from server to clients with the header Set-Cookie: and
they're sent from clients to servers with the Cookie: header.
To just send whatever cookie you want to a server, you can use CURLOPT_COOKIE
to set a cookie string like this:
curl_easy_setopt(easyhandle, CURLOPT_COOKIE, "name1=var1; name2=var2;");
In many cases, that is not enough. You might want to dynamicly save whatever
cookies the remote server passes to you, and make sure those cookies are then
use accordingly on later requests.
One way to do this, is to save all headers you receive in a plain file and
when you make a request, you tell libcurl to read the previous headers to
figure out which cookies to use. Set header file to read cookies from with
CURLOPT_COOKIEFILE.
The CURLOPT_COOKIEFILE option also automaticly enables the cookie parser in
libcurl. Until the cookie parser is enabled, libcurl will not parse or
understand incoming cookies and they will just be ignored. However, when the
parser is enabled the cookies will be understood and the cookies will be kept
in memory and used properly in subsequent requests when the same handle is
used. Many times this is enough, and you may not have to save the cookies to
disk at all. Note that the file you specify to CURLOPT_COOKIEFILE doesn't
have to exist to enable the parser, so a common way to just enable the parser
and not read able might be to use a file name you know doesn't exist.
If you rather use existing cookies that you've previously received with your
Netscape or Mozilla browsers, you can make libcurl use that cookie file as
input. The CURLOPT_COOKIEFILE is used for that too, as libcurl will
automaticly find out what kind of file it is and act accordingly.
The perhaps most advanced cookie operation libcurl offers, is saving the
entire internal cookie state back into a Netscape/Mozilla formatted cookie
file. We call that the cookie-jar. When you set a file name with
CURLOPT_COOKIEJAR, that file name will be created and all received cookies
will be stored in it when curl_easy_cleanup() is called. This enabled cookies
to get passed on properly between multiple handles without any information
getting lost.
Headers Equal Fun
[ use the header callback for HTTP, FTP etc ]
Post Transfer Information
[ curl_easy_getinfo ]
Security Considerations
[ ps output, netrc plain text, plain text protocols / base64 ]
SSL, Certificates and Other Tricks
[ seeding, passwords, keys, certificates, ENGINE, ca certs ]
Future
[ multi interface, sharing between handles, mutexes, pipelining ]
-----
Footnotes:
[1] = HTTP PUT without knowing the size prior to transfer is indeed possible,
but libcurl does not support the chunked transfers on uploading that is
necessary for this feature to work. We'd gratefully appreciate patches
that bring this functionality...
[2] = This happens on Windows machines when libcurl is built and used as a
DLL. However, you can still do this on Windows if you link with a static
library.
[3] = The curl-config tool is generated at build-time (on unix-like systems)
and should be installed with the 'make install' or similar instruction
that installs the library, header files, man pages etc.

View File

@@ -6,8 +6,10 @@
.SH NAME
libcurl \- client-side URL transfers
.SH DESCRIPTION
This is an overview on how to use libcurl in your c/c++ programs. There are
specific man pages for each function mentioned in here.
This is an overview on how to use libcurl in your C programs. There are
specific man pages for each function mentioned in here. There's also the
libcurl-the-guide document for a complete tutorial to programming with
libcurl.
libcurl can also be used directly from within your Java, PHP, Perl, Ruby or
Tcl programs as well, look elsewhere for documentation on this!
@@ -56,9 +58,6 @@ get information about a performed transfer
.B curl_formadd()
helps building a HTTP form POST
.TP
.B curl_formparse()
helps building a HTTP form POST (deprecated since 7.9 use curl_formadd()!)
.TP
.B curl_formfree()
free a list built with curl_formparse()/curl_formadd()
.TP

View File

@@ -7,7 +7,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
@@ -30,11 +30,11 @@
# include <time.h>
#else
# include <sys/types.h>
# if TIME_WITH_SYS_TIME
# ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
# else
# if HAVE_SYS_TIME_H
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
@@ -272,7 +272,7 @@ typedef enum {
/* Set cookie in request: */
CINIT(COOKIE, OBJECTPOINT, 22),
/* This points to a linked list of headers, struct HttpHeader kind */
/* This points to a linked list of headers, struct curl_slist kind */
CINIT(HTTPHEADER, OBJECTPOINT, 23),
/* This points to a linked list of post entries, struct HttpPost */
@@ -488,6 +488,12 @@ typedef enum {
*/
CINIT(SSLENGINE_DEFAULT, LONG, 90),
/* Non-zero value means to use the global dns cache */
CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91),
/* DNS cache timeout */
CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
CURLOPT_LASTENTRY /* the last unusued */
} CURLoption;
@@ -607,8 +613,8 @@ CURLcode curl_global_init(long flags);
void curl_global_cleanup(void);
/* This is the version number */
#define LIBCURL_VERSION "7.9.2"
#define LIBCURL_VERSION_NUM 0x070902
#define LIBCURL_VERSION "7.9.5-pre4"
#define LIBCURL_VERSION_NUM 0x070905
/* linked-list structure for the CURLOPT_QUOTE option (and other) */
struct curl_slist {
@@ -660,7 +666,11 @@ typedef enum {
CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
CURLINFO_LASTONE = 18
CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
/* Fill in new entries here! */
CURLINFO_LASTONE = 19
} CURLINFO;
/* unfortunately, the easy.h include file needs the options and info stuff

View File

@@ -2,17 +2,18 @@
# $Id$
#
AUTOMAKE_OPTIONS = foreign no-dependencies
AUTOMAKE_OPTIONS = foreign nostdinc
EXTRA_DIST = getdate.y \
Makefile.b32 Makefile.b32.resp Makefile.m32 Makefile.vc6 \
libcurl.def dllinit.c curllib.dsp curllib.dsw
libcurl.def dllinit.c curllib.dsp curllib.dsw \
config-vms.h config-win32.h config-riscos.h config-mac.h \
config.h.in
lib_LTLIBRARIES = libcurl.la
INCLUDES = -I$(top_srcdir)/include
libcurl_la_LDFLAGS = -no-undefined -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
@@ -56,7 +57,9 @@ escape.c mprintf.c telnet.c \
escape.h getpass.c netrc.c telnet.h \
getinfo.c getinfo.h transfer.c strequal.c strequal.h easy.c \
security.h security.c krb4.c krb4.h memdebug.c memdebug.h inet_ntoa_r.h \
http_chunks.c http_chunks.h strtok.c strtok.h connect.c connect.h
http_chunks.c http_chunks.h strtok.c strtok.h connect.c connect.h \
llist.c llist.h hash.c hash.h multi.c multi.h
noinst_HEADERS = setup.h transfer.h

View File

@@ -35,14 +35,14 @@ libcurl_a_SOURCES = arpa_telnet.h file.c getpass.h netrc.h timeval.c base64.c \
ldap.h ssluse.h escape.c getenv.h mprintf.c telnet.c escape.h getpass.c netrc.c \
telnet.h getinfo.c strequal.c strequal.h easy.c security.h \
security.c krb4.h krb4.c memdebug.h memdebug.c inet_ntoa_r.h http_chunks.h http_chunks.c \
strtok.c connect.c
strtok.c connect.c hash.c llist.c
libcurl_a_OBJECTS = file.o timeval.o base64.o hostip.o progress.o \
formdata.o cookie.o http.o sendf.o ftp.o url.o dict.o if2ip.o \
speedcheck.o getdate.o transfer.o ldap.o ssluse.o version.o \
getenv.o escape.o mprintf.o telnet.o getpass.o netrc.o getinfo.o \
strequal.o easy.o security.o krb4.o memdebug.o http_chunks.o \
strtok.o connect.o
strtok.o connect.o hash.o llist.o
LIBRARIES = $(libcurl_a_LIBRARIES)
SOURCES = $(libcurl_a_SOURCES)

View File

@@ -23,13 +23,18 @@
# CHANGE LOG
# ------------------------------------------------------------
# 05.11.2001 John Lask Initial Release
# 02.05.2002 Miklos Nemeth OPENSSL_PATH environment; no need
# for OpenSSL libraries when creating a
# static libcurl.lib
#
#
##############################################################
LIB_NAME = libcurl
LIB_NAME_DEBUG = libcurld
!IFNDEF OPENSSL_PATH
OPENSSL_PATH = ../../openssl-0.9.6
!ENDIF
#############################################################
## Nothing more to do below this line!
@@ -46,6 +51,8 @@ LFLAGSSSL = /LIBPATH:$(OPENSSL_PATH)/out32dll
LINKLIBS = ws2_32.lib
SSLLIBS = libeay32.lib ssleay32.lib RSAglue.lib
CFGSET = FALSE
LFLAGSSSL=
SSLLIBS =
######################
# release
@@ -193,8 +200,9 @@ X_OBJS= \
$(DIROBJ)\easy.obj \
$(DIROBJ)\strequal.obj \
$(DIROBJ)\strtok.obj \
$(DIROBJ)\connect.obj
$(DIROBJ)\connect.obj \
$(DIROBJ)\hash.obj \
$(DIROBJ)\llist.obj
all : $(TARGET)

View File

@@ -221,22 +221,22 @@
#define HAVE_NETINET_IN_H 1
/* Define if you have the <openssl/crypto.h> header file. */
#undef HAVE_OPENSSL_CRYPTO_H
#define HAVE_OPENSSL_CRYPTO_H 1
/* Define if you have the <openssl/err.h> header file. */
#undef HAVE_OPENSSL_ERR_H
#define HAVE_OPENSSL_ERR_H 1
/* Define if you have the <openssl/pem.h> header file. */
#undef HAVE_OPENSSL_PEM_H
#define HAVE_OPENSSL_PEM_H 1
/* Define if you have the <openssl/rsa.h> header file. */
#undef HAVE_OPENSSL_RSA_H
#define HAVE_OPENSSL_RSA_H 1
/* Define if you have the <openssl/ssl.h> header file. */
#undef HAVE_OPENSSL_SSL_H
#define HAVE_OPENSSL_SSL_H 1
/* Define if you have the <openssl/x509.h> header file. */
#undef HAVE_OPENSSL_X509_H
#define HAVE_OPENSSL_X509_H 1
/* Define if you have the <pem.h> header file. */
#undef HAVE_PEM_H
@@ -296,7 +296,7 @@
#undef HAVE_X509_H
/* Define if you have the crypto library (-lcrypto). */
#undef HAVE_LIBCRYPTO
#define HAVE_LIBCRYPTO 1
/* Define if you have the dl library (-ldl). */
#undef HAVE_LIBDL
@@ -314,7 +314,7 @@
#define HAVE_LIBSOCKET 1
/* Define if you have the ssl library (-lssl). */
#undef HAVE_LIBSSL
#define HAVE_LIBSSL 1
/* Define if you have the ucb library (-lucb). */
#undef HAVE_LIBUCB
@@ -346,7 +346,7 @@
#undef HAVE_GETPASS
/* Define if you have a working OpenSSL installation */
#undef OPENSSL_ENABLED
#define OPENSSL_ENABLED 1
/* Define if you have the `dlopen' function. */
#undef HAVE_DLOPEN
@@ -365,3 +365,4 @@
#define HAVE_MEMORY_H 1
#define HAVE_FIONBIO 1

View File

@@ -48,6 +48,10 @@
#include <stdlib.h> /* required for free() prototype, without it, this crashes
on macos 68K */
#endif
#ifdef VMS
#include <in.h>
#include <inet.h>
#endif
#endif
#include <stdio.h>
@@ -210,11 +214,11 @@ static CURLcode bindlocal(struct connectdata *conn,
in_addr_t in;
if(Curl_if2ip(data->set.device, myhost, sizeof(myhost))) {
h = Curl_getaddrinfo(data, myhost, 0, &hostdataptr);
h = Curl_resolv(data, myhost, 0, &hostdataptr);
}
else {
if(strlen(data->set.device)>1) {
h = Curl_getaddrinfo(data, data->set.device, 0, &hostdataptr);
h = Curl_resolv(data, data->set.device, 0, &hostdataptr);
}
if(h) {
/* we know data->set.device is shorter than the myhost array */
@@ -229,8 +233,6 @@ static CURLcode bindlocal(struct connectdata *conn,
hostent_buf,
sizeof(hostent_buf));
*/
if(hostdataptr)
free(hostdataptr); /* allocated by Curl_getaddrinfo() */
return CURLE_HTTP_PORT_FAILED;
}
@@ -304,9 +306,6 @@ static CURLcode bindlocal(struct connectdata *conn,
return CURLE_HTTP_PORT_FAILED;
}
if(hostdataptr)
free(hostdataptr); /* allocated by Curl_getaddrinfo() */
return CURLE_OK;
} /* end of device selection support */
@@ -365,8 +364,13 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
#endif
/* get the most strict timeout of the ones converted to milliseconds */
if(data->set.timeout &&
(data->set.timeout>data->set.connecttimeout))
if(data->set.timeout && data->set.connecttimeout) {
if (data->set.timeout < data->set.connecttimeout)
timeout_ms = data->set.timeout*1000;
else
timeout_ms = data->set.connecttimeout*1000;
}
else if(data->set.timeout)
timeout_ms = data->set.timeout*1000;
else
timeout_ms = data->set.connecttimeout*1000;
@@ -374,9 +378,11 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
/* subtract the passed time */
timeout_ms -= (long)has_passed;
if(timeout_ms < 0)
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
failf(data, "Connection time-out");
return CURLE_OPERATION_TIMEOUTED;
}
}
#ifdef ENABLE_IPV6
@@ -453,8 +459,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_COULDNT_CONNECT;
}
/* now disable the non-blocking mode again */
Curl_nonblock(sockfd, FALSE);
/* leave the socket in non-blocking mode */
if(addr)
*addr = ai; /* the address we ended up connected to */
@@ -560,8 +565,7 @@ CURLcode Curl_connecthost(struct connectdata *conn, /* context */
return CURLE_COULDNT_CONNECT;
}
/* now disable the non-blocking mode again */
Curl_nonblock(sockfd, FALSE);
/* leave the socket in non-blocking mode */
if(addr)
/* this is the address we've connected to */

View File

@@ -194,6 +194,11 @@ Curl_cookie_add(struct CookieInfo *c,
while(ptr && *ptr && isspace((int)*ptr))
ptr++;
semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
if(!semiptr && *ptr)
/* There are no more semicolons, but there's a final name=value pair
coming up */
semiptr=ptr;
} while(semiptr);
if(NULL == co->domain)
@@ -377,8 +382,15 @@ Curl_cookie_add(struct CookieInfo *c,
free(co); /* free the newly alloced memory */
co = clist; /* point to the previous struct instead */
}
/* We have replaced a cookie, now skip the rest of the list but
make sure the 'lastc' pointer is properly set */
do {
lastc = clist;
clist = clist->next;
} while(clist);
break;
}
}
lastc = clist;
clist = clist->next;

View File

@@ -38,7 +38,7 @@ struct Cookie {
char *value; /* name = <this> */
char *path; /* path = <this> */
char *domain; /* domain = <this> */
time_t expires; /* expires = <this> */
long expires; /* expires = <this> */
char *expirestr; /* the plain text version */
char field1; /* read from a cookie file, 1 => FALSE, 2=> TRUE */

View File

@@ -151,6 +151,10 @@ SOURCE=.\getpass.c
# End Source File
# Begin Source File
SOURCE=.\hash.c
# End Source File
# Begin Source File
SOURCE=.\hostip.c
# End Source File
# Begin Source File
@@ -179,6 +183,10 @@ SOURCE=.\libcurl.def
# End Source File
# Begin Source File
SOURCE=.\llist.c
# End Source File
# Begin Source File
SOURCE=.\memdebug.c
# End Source File
# Begin Source File

View File

@@ -81,6 +81,10 @@ DllMain (
}
return TRUE;
}
#else
#ifdef VMS
int VOID_VAR_DLLINIT;
#endif
#endif
/*

View File

@@ -76,6 +76,7 @@
#include "ssluse.h"
#include "url.h"
#include "getinfo.h"
#include "hostip.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -162,6 +163,8 @@ void curl_global_cleanup(void)
if (!initialized)
return;
Curl_global_host_cache_dtor();
if (init_flags & CURL_GLOBAL_SSL)
Curl_SSL_cleanup();
@@ -230,12 +233,24 @@ CURLcode curl_easy_perform(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
if (!data->hostcache) {
if (Curl_global_host_cache_use(data)) {
data->hostcache = Curl_global_host_cache_get();
}
else {
data->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo);
}
}
return Curl_perform(data);
}
void curl_easy_cleanup(CURL *curl)
{
struct SessionHandle *data = (struct SessionHandle *)curl;
if (!Curl_global_host_cache_use(data)) {
curl_hash_destroy(data->hostcache);
}
Curl_close(data);
}

View File

@@ -235,7 +235,6 @@ int FormParse(char *input,
if(2 != sscanf(type, "%127[^/]/%127[^,\n]",
major, minor)) {
fprintf(stderr, "Illegally formatted content-type field!\n");
free(contents);
return 2; /* illegal content-type syntax! */
}
@@ -371,7 +370,6 @@ int FormParse(char *input,
}
else {
fprintf(stderr, "Illegally formatted input field!\n");
free(contents);
return 1;
}
@@ -841,7 +839,6 @@ FORMcode FormAdd(struct HttpPost **httppost,
break;
}
default:
fprintf (stderr, "got unknown CURLFORM_OPTION: %d\n", option);
return_value = FORMADD_UNKNOWN_OPTION;
}
}
@@ -1068,8 +1065,11 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
do {
if(size)
size += AddFormDataf(&form, "\r\n");
/* boundary */
size += AddFormDataf(&form, "\r\n--%s\r\n", boundary);
size += AddFormDataf(&form, "--%s\r\n", boundary);
size += AddFormData(&form,
"Content-Disposition: form-data; name=\"", 0);
@@ -1155,10 +1155,13 @@ struct FormData *Curl_getFormData(struct HttpPost *post,
}
if(fileread != stdin)
fclose(fileread);
} else {
size += AddFormData(&form, "[File wasn't found by client]", 0);
}
} else {
else {
/* File wasn't found, add a nothing field! */
size += AddFormData(&form, "", 0);
}
}
else {
/* include the contents we got */
size += AddFormData(&form, post->contents, post->contentslength);
}

View File

@@ -55,6 +55,7 @@
#include <netdb.h>
#endif
#ifdef VMS
#include <in.h>
#include <inet.h>
#endif
#endif
@@ -84,6 +85,10 @@
#include "ssluse.h"
#include "connect.h"
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -192,9 +197,12 @@ int Curl_GetFTPResponse(char *buf,
char *line_start;
int code=0; /* default "error code" to return */
#define SELECT_OK 0
#define SELECT_ERROR 1
#define SELECT_TIMEOUT 2
#define SELECT_OK 0
#define SELECT_ERROR 1 /* select() problems */
#define SELECT_TIMEOUT 2 /* took too long */
#define SELECT_MEMORY 3 /* no available memory */
#define SELECT_CALLBACK 4 /* aborted by callback */
int error = SELECT_OK;
struct FTP *ftp = conn->proto.ftp;
@@ -260,9 +268,16 @@ int Curl_GetFTPResponse(char *buf,
ftp->cache = NULL; /* clear the pointer */
ftp->cache_size = 0; /* zero the size just in case */
}
else if(CURLE_OK != Curl_read(conn, sockfd, ptr,
BUFSIZE-nread, &gotbytes))
keepon = FALSE;
else {
int res = Curl_read(conn, sockfd, ptr,
BUFSIZE-nread, &gotbytes);
if(res < 0)
/* EWOULDBLOCK */
continue; /* go looping again */
if(CURLE_OK != res)
keepon = FALSE;
}
if(!keepon)
;
@@ -283,6 +298,7 @@ int Curl_GetFTPResponse(char *buf,
if(*ptr=='\n') {
/* a newline is CRLF in ftp-talk, so the CR is ignored as
the line isn't really terminated until the LF comes */
CURLcode result;
/* output debug output if that is requested */
if(data->set.verbose) {
@@ -291,6 +307,16 @@ int Curl_GetFTPResponse(char *buf,
/* no need to output LF here, it is part of the data */
}
/*
* We pass all response-lines to the callback function registered
* for "headers". The response lines can be seen as a kind of
* headers.
*/
result = Curl_client_write(data, CLIENTWRITE_HEADER,
line_start, perline);
if(result)
return -SELECT_CALLBACK;
#define lastline(line) (isdigit((int)line[0]) && isdigit((int)line[1]) && \
isdigit((int)line[2]) && (' ' == line[3]))
@@ -324,7 +350,7 @@ int Curl_GetFTPResponse(char *buf,
if(ftp->cache)
memcpy(ftp->cache, line_start, ftp->cache_size);
else
return CURLE_OUT_OF_MEMORY; /**BANG**/
return -SELECT_MEMORY; /**BANG**/
}
} /* there was data */
} /* if(no error) */
@@ -333,7 +359,7 @@ int Curl_GetFTPResponse(char *buf,
if(!error)
code = atoi(buf);
#if KRB4
#ifdef KRB4
/* handle the security-oriented responses 6xx ***/
/* FIXME: some errorchecking perhaps... ***/
switch(code) {
@@ -847,13 +873,17 @@ ftp_pasv_verbose(struct connectdata *conn,
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
#endif
char hostent_buf[9000];
/* The array size trick below is to make this a large chunk of memory
suitably 8-byte aligned on 64-bit platforms. This was thoughtfully
suggested by Philip Gladstone. */
long bigbuf[9000 / sizeof(long)];
#if defined(HAVE_INET_ADDR)
in_addr_t address;
# if defined(HAVE_GETHOSTBYADDR_R)
int h_errnop;
# endif
char *hostent_buf = (char *)bigbuf; /* get a char * to the buffer */
address = inet_addr(newhost);
# ifdef HAVE_GETHOSTBYADDR_R
@@ -882,7 +912,7 @@ ftp_pasv_verbose(struct connectdata *conn,
# ifdef HAVE_GETHOSTBYADDR_R_7
/* Solaris and IRIX */
answer = gethostbyaddr_r((char *) &address, sizeof(address), AF_INET,
(struct hostent *)hostent_buf,
(struct hostent *)bigbuf,
hostent_buf + sizeof(*answer),
sizeof(hostent_buf) - sizeof(*answer),
&h_errnop);
@@ -1174,19 +1204,19 @@ CURLcode ftp_use_port(struct connectdata *conn)
if(data->set.ftpport) {
if(Curl_if2ip(data->set.ftpport, myhost, sizeof(myhost))) {
h = Curl_getaddrinfo(data, myhost, 0, &hostdataptr);
h = Curl_resolv(data, myhost, 0, &hostdataptr);
}
else {
if(strlen(data->set.ftpport)>1)
h = Curl_getaddrinfo(data, data->set.ftpport, 0, &hostdataptr);
int len = strlen(data->set.ftpport);
if(len>1)
h = Curl_resolv(data, data->set.ftpport, 0, &hostdataptr);
if(h)
strcpy(myhost, data->set.ftpport); /* buffer overflow risk */
}
}
if(! *myhost) {
h=Curl_getaddrinfo(data,
getmyhost(myhost, sizeof(myhost)),
0, &hostdataptr);
char *tmp_host = getmyhost(myhost, sizeof(myhost));
h=Curl_resolv(data, tmp_host, 0, &hostdataptr);
}
infof(data, "We connect from %s\n", myhost);
@@ -1237,9 +1267,6 @@ CURLcode ftp_use_port(struct connectdata *conn)
free(hostdataptr);
return CURLE_FTP_PORT_FAILED;
}
if(hostdataptr)
/* free the memory used for name lookup */
Curl_freeaddrinfo(hostdataptr);
}
else {
failf(data, "could't find my own IP address (%s)", myhost);
@@ -1431,7 +1458,7 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
}
else {
/* normal, direct, ftp connection */
addr = Curl_getaddrinfo(data, newhostp, newport, &hostdataptr);
addr = Curl_resolv(data, newhostp, newport, &hostdataptr);
if(!addr) {
failf(data, "Can't resolve new host %s", newhost);
return CURLE_FTP_CANT_GET_HOST;
@@ -1450,9 +1477,6 @@ CURLcode ftp_use_pasv(struct connectdata *conn)
/* this just dumps information about this second connection */
ftp_pasv_verbose(conn, conninfo, newhost, connectport);
if(hostdataptr)
Curl_freeaddrinfo(hostdataptr);
if(CURLE_OK != result)
return result;
@@ -1552,7 +1576,7 @@ CURLcode ftp_perform(struct connectdata *conn)
struct tm buffer;
tm = (struct tm *)localtime_r(&data->info.filetime, &buffer);
#else
tm = localtime(&data->info.filetime);
tm = localtime((unsigned long *)&data->info.filetime);
#endif
/* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
strftime(buf, BUFSIZE-1, "Last-Modified: %a, %d %b %Y %H:%M:%S %Z\r\n",
@@ -2035,9 +2059,11 @@ CURLcode Curl_ftp(struct connectdata *conn)
CURLcode Curl_ftpsendf(struct connectdata *conn,
const char *fmt, ...)
{
size_t bytes_written;
ssize_t bytes_written;
char s[256];
size_t write_len;
ssize_t write_len;
char *sptr=s;
CURLcode res = CURLE_OK;
va_list ap;
va_start(ap, fmt);
@@ -2051,9 +2077,23 @@ CURLcode Curl_ftpsendf(struct connectdata *conn,
bytes_written=0;
write_len = strlen(s);
Curl_write(conn, conn->firstsocket, s, write_len, &bytes_written);
return (bytes_written==write_len)?CURLE_OK:CURLE_WRITE_ERROR;
do {
res = Curl_write(conn, conn->firstsocket, sptr, write_len,
&bytes_written);
if(CURLE_OK != res)
break;
if(bytes_written != write_len) {
write_len -= bytes_written;
sptr += bytes_written;
}
else
break;
} while(1);
return res;
}
/***********************************************************************

View File

@@ -34,8 +34,6 @@
#include "setup.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
@@ -43,6 +41,10 @@
# ifdef HAVE_TIME_H
# include <time.h>
# endif
#ifndef YYDEBUG
/* to satisfy gcc -Wundef, we set this to 0 */
#define YYDEBUG 0
#endif
/* Since the code of getdate.y is not included in the Emacs executable
@@ -192,38 +194,40 @@ typedef enum _MERIDIAN {
MERam, MERpm, MER24
} MERIDIAN;
/* parse results and input string */
typedef struct _CONTEXT {
const char *yyInput;
int yyDayOrdinal;
int yyDayNumber;
int yyHaveDate;
int yyHaveDay;
int yyHaveRel;
int yyHaveTime;
int yyHaveZone;
int yyTimezone;
int yyDay;
int yyHour;
int yyMinutes;
int yyMonth;
int yySeconds;
int yyYear;
MERIDIAN yyMeridian;
int yyRelDay;
int yyRelHour;
int yyRelMinutes;
int yyRelMonth;
int yyRelSeconds;
int yyRelYear;
} CONTEXT;
/*
** Global variables. We could get rid of most of these by using a good
** union as the yacc stack. (This routine was originally written before
** yacc had the %union construct.) Maybe someday; right now we only use
** the %union very rarely.
/* enable use of extra argument to yyparse and yylex which can be used to pass
** in a user defined value (CONTEXT struct in our case)
*/
static const char *yyInput;
static int yyDayOrdinal;
static int yyDayNumber;
static int yyHaveDate;
static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
static int yyHaveZone;
static int yyTimezone;
static int yyDay;
static int yyHour;
static int yyMinutes;
static int yyMonth;
static int yySeconds;
static int yyYear;
static MERIDIAN yyMeridian;
static int yyRelDay;
static int yyRelHour;
static int yyRelMinutes;
static int yyRelMonth;
static int yyRelSeconds;
static int yyRelYear;
#define YYPARSE_PARAM cookie
#define YYLEX_PARAM cookie
#define context ((CONTEXT *) cookie)
#line 206 "getdate.y"
#line 215 "getdate.y"
typedef union {
int Number;
enum _MERIDIAN Meridian;
@@ -306,11 +310,11 @@ static const short yyrhs[] = { -1,
#if YYDEBUG != 0
static const short yyrline[] = { 0,
222, 223, 226, 229, 232, 235, 238, 241, 244, 250,
256, 265, 271, 283, 286, 289, 295, 299, 303, 309,
313, 331, 337, 343, 347, 352, 356, 363, 371, 374,
377, 380, 383, 386, 389, 392, 395, 398, 401, 404,
407, 410, 413, 416, 419, 422, 425, 430, 463, 467
231, 232, 235, 238, 241, 244, 247, 250, 253, 259,
265, 274, 280, 292, 295, 298, 304, 308, 312, 318,
322, 340, 346, 352, 356, 361, 365, 372, 380, 383,
386, 389, 392, 395, 398, 401, 404, 407, 410, 413,
416, 419, 422, 425, 428, 431, 434, 439, 473, 477
};
#endif
@@ -390,6 +394,8 @@ static const short yycheck[] = { 0,
11, 15, 13, 14, 16, 19, 17, 16, 21, 0,
56
};
#define YYPURE 1
/* -*-C-*- Note some compilers choke on comments on `#line' lines. */
#line 3 "/usr/local/share/bison.simple"
/* This file comes from bison-1.28. */
@@ -934,135 +940,135 @@ yyreduce:
switch (yyn) {
case 3:
#line 226 "getdate.y"
#line 235 "getdate.y"
{
yyHaveTime++;
context->yyHaveTime++;
;
break;}
case 4:
#line 229 "getdate.y"
#line 238 "getdate.y"
{
yyHaveZone++;
context->yyHaveZone++;
;
break;}
case 5:
#line 232 "getdate.y"
#line 241 "getdate.y"
{
yyHaveDate++;
context->yyHaveDate++;
;
break;}
case 6:
#line 235 "getdate.y"
#line 244 "getdate.y"
{
yyHaveDay++;
context->yyHaveDay++;
;
break;}
case 7:
#line 238 "getdate.y"
#line 247 "getdate.y"
{
yyHaveRel++;
context->yyHaveRel++;
;
break;}
case 9:
#line 244 "getdate.y"
#line 253 "getdate.y"
{
yyHour = yyvsp[-1].Number;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = yyvsp[0].Meridian;
context->yyHour = yyvsp[-1].Number;
context->yyMinutes = 0;
context->yySeconds = 0;
context->yyMeridian = yyvsp[0].Meridian;
;
break;}
case 10:
#line 250 "getdate.y"
#line 259 "getdate.y"
{
yyHour = yyvsp[-3].Number;
yyMinutes = yyvsp[-1].Number;
yySeconds = 0;
yyMeridian = yyvsp[0].Meridian;
context->yyHour = yyvsp[-3].Number;
context->yyMinutes = yyvsp[-1].Number;
context->yySeconds = 0;
context->yyMeridian = yyvsp[0].Meridian;
;
break;}
case 11:
#line 256 "getdate.y"
#line 265 "getdate.y"
{
yyHour = yyvsp[-3].Number;
yyMinutes = yyvsp[-1].Number;
yyMeridian = MER24;
yyHaveZone++;
yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
context->yyHour = yyvsp[-3].Number;
context->yyMinutes = yyvsp[-1].Number;
context->yyMeridian = MER24;
context->yyHaveZone++;
context->yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
;
break;}
case 12:
#line 265 "getdate.y"
#line 274 "getdate.y"
{
yyHour = yyvsp[-5].Number;
yyMinutes = yyvsp[-3].Number;
yySeconds = yyvsp[-1].Number;
yyMeridian = yyvsp[0].Meridian;
context->yyHour = yyvsp[-5].Number;
context->yyMinutes = yyvsp[-3].Number;
context->yySeconds = yyvsp[-1].Number;
context->yyMeridian = yyvsp[0].Meridian;
;
break;}
case 13:
#line 271 "getdate.y"
#line 280 "getdate.y"
{
yyHour = yyvsp[-5].Number;
yyMinutes = yyvsp[-3].Number;
yySeconds = yyvsp[-1].Number;
yyMeridian = MER24;
yyHaveZone++;
yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
context->yyHour = yyvsp[-5].Number;
context->yyMinutes = yyvsp[-3].Number;
context->yySeconds = yyvsp[-1].Number;
context->yyMeridian = MER24;
context->yyHaveZone++;
context->yyTimezone = (yyvsp[0].Number < 0
? -yyvsp[0].Number % 100 + (-yyvsp[0].Number / 100) * 60
: - (yyvsp[0].Number % 100 + (yyvsp[0].Number / 100) * 60));
;
break;}
case 14:
#line 283 "getdate.y"
#line 292 "getdate.y"
{
yyTimezone = yyvsp[0].Number;
context->yyTimezone = yyvsp[0].Number;
;
break;}
case 15:
#line 286 "getdate.y"
#line 295 "getdate.y"
{
yyTimezone = yyvsp[0].Number - 60;
context->yyTimezone = yyvsp[0].Number - 60;
;
break;}
case 16:
#line 290 "getdate.y"
#line 299 "getdate.y"
{
yyTimezone = yyvsp[-1].Number - 60;
context->yyTimezone = yyvsp[-1].Number - 60;
;
break;}
case 17:
#line 295 "getdate.y"
#line 304 "getdate.y"
{
yyDayOrdinal = 1;
yyDayNumber = yyvsp[0].Number;
context->yyDayOrdinal = 1;
context->yyDayNumber = yyvsp[0].Number;
;
break;}
case 18:
#line 299 "getdate.y"
#line 308 "getdate.y"
{
yyDayOrdinal = 1;
yyDayNumber = yyvsp[-1].Number;
context->yyDayOrdinal = 1;
context->yyDayNumber = yyvsp[-1].Number;
;
break;}
case 19:
#line 303 "getdate.y"
#line 312 "getdate.y"
{
yyDayOrdinal = yyvsp[-1].Number;
yyDayNumber = yyvsp[0].Number;
context->yyDayOrdinal = yyvsp[-1].Number;
context->yyDayNumber = yyvsp[0].Number;
;
break;}
case 20:
#line 309 "getdate.y"
#line 318 "getdate.y"
{
yyMonth = yyvsp[-2].Number;
yyDay = yyvsp[0].Number;
context->yyMonth = yyvsp[-2].Number;
context->yyDay = yyvsp[0].Number;
;
break;}
case 21:
#line 313 "getdate.y"
#line 322 "getdate.y"
{
/* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
The goal in recognizing YYYY/MM/DD is solely to support legacy
@@ -1070,226 +1076,227 @@ case 21:
you want portability, use the ISO 8601 format. */
if (yyvsp[-4].Number >= 1000)
{
yyYear = yyvsp[-4].Number;
yyMonth = yyvsp[-2].Number;
yyDay = yyvsp[0].Number;
context->yyYear = yyvsp[-4].Number;
context->yyMonth = yyvsp[-2].Number;
context->yyDay = yyvsp[0].Number;
}
else
{
yyMonth = yyvsp[-4].Number;
yyDay = yyvsp[-2].Number;
yyYear = yyvsp[0].Number;
context->yyMonth = yyvsp[-4].Number;
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
}
;
break;}
case 22:
#line 331 "getdate.y"
#line 340 "getdate.y"
{
/* ISO 8601 format. yyyy-mm-dd. */
yyYear = yyvsp[-2].Number;
yyMonth = -yyvsp[-1].Number;
yyDay = -yyvsp[0].Number;
context->yyYear = yyvsp[-2].Number;
context->yyMonth = -yyvsp[-1].Number;
context->yyDay = -yyvsp[0].Number;
;
break;}
case 23:
#line 337 "getdate.y"
#line 346 "getdate.y"
{
/* e.g. 17-JUN-1992. */
yyDay = yyvsp[-2].Number;
yyMonth = yyvsp[-1].Number;
yyYear = -yyvsp[0].Number;
context->yyDay = yyvsp[-2].Number;
context->yyMonth = yyvsp[-1].Number;
context->yyYear = -yyvsp[0].Number;
;
break;}
case 24:
#line 343 "getdate.y"
#line 352 "getdate.y"
{
yyMonth = yyvsp[-1].Number;
yyDay = yyvsp[0].Number;
context->yyMonth = yyvsp[-1].Number;
context->yyDay = yyvsp[0].Number;
;
break;}
case 25:
#line 347 "getdate.y"
#line 356 "getdate.y"
{
yyMonth = yyvsp[-3].Number;
yyDay = yyvsp[-2].Number;
yyYear = yyvsp[0].Number;
context->yyMonth = yyvsp[-3].Number;
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
;
break;}
case 26:
#line 352 "getdate.y"
#line 361 "getdate.y"
{
yyMonth = yyvsp[0].Number;
yyDay = yyvsp[-1].Number;
context->yyMonth = yyvsp[0].Number;
context->yyDay = yyvsp[-1].Number;
;
break;}
case 27:
#line 356 "getdate.y"
#line 365 "getdate.y"
{
yyMonth = yyvsp[-1].Number;
yyDay = yyvsp[-2].Number;
yyYear = yyvsp[0].Number;
context->yyMonth = yyvsp[-1].Number;
context->yyDay = yyvsp[-2].Number;
context->yyYear = yyvsp[0].Number;
;
break;}
case 28:
#line 363 "getdate.y"
#line 372 "getdate.y"
{
yyRelSeconds = -yyRelSeconds;
yyRelMinutes = -yyRelMinutes;
yyRelHour = -yyRelHour;
yyRelDay = -yyRelDay;
yyRelMonth = -yyRelMonth;
yyRelYear = -yyRelYear;
context->yyRelSeconds = -context->yyRelSeconds;
context->yyRelMinutes = -context->yyRelMinutes;
context->yyRelHour = -context->yyRelHour;
context->yyRelDay = -context->yyRelDay;
context->yyRelMonth = -context->yyRelMonth;
context->yyRelYear = -context->yyRelYear;
;
break;}
case 30:
#line 374 "getdate.y"
#line 383 "getdate.y"
{
yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 31:
#line 377 "getdate.y"
#line 386 "getdate.y"
{
yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelYear += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 32:
#line 380 "getdate.y"
#line 389 "getdate.y"
{
yyRelYear += yyvsp[0].Number;
context->yyRelYear += yyvsp[0].Number;
;
break;}
case 33:
#line 383 "getdate.y"
#line 392 "getdate.y"
{
yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 34:
#line 386 "getdate.y"
#line 395 "getdate.y"
{
yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelMonth += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 35:
#line 389 "getdate.y"
#line 398 "getdate.y"
{
yyRelMonth += yyvsp[0].Number;
context->yyRelMonth += yyvsp[0].Number;
;
break;}
case 36:
#line 392 "getdate.y"
#line 401 "getdate.y"
{
yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 37:
#line 395 "getdate.y"
#line 404 "getdate.y"
{
yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelDay += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 38:
#line 398 "getdate.y"
#line 407 "getdate.y"
{
yyRelDay += yyvsp[0].Number;
context->yyRelDay += yyvsp[0].Number;
;
break;}
case 39:
#line 401 "getdate.y"
#line 410 "getdate.y"
{
yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 40:
#line 404 "getdate.y"
#line 413 "getdate.y"
{
yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelHour += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 41:
#line 407 "getdate.y"
#line 416 "getdate.y"
{
yyRelHour += yyvsp[0].Number;
context->yyRelHour += yyvsp[0].Number;
;
break;}
case 42:
#line 410 "getdate.y"
#line 419 "getdate.y"
{
yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 43:
#line 413 "getdate.y"
#line 422 "getdate.y"
{
yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelMinutes += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 44:
#line 416 "getdate.y"
#line 425 "getdate.y"
{
yyRelMinutes += yyvsp[0].Number;
context->yyRelMinutes += yyvsp[0].Number;
;
break;}
case 45:
#line 419 "getdate.y"
#line 428 "getdate.y"
{
yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 46:
#line 422 "getdate.y"
#line 431 "getdate.y"
{
yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
context->yyRelSeconds += yyvsp[-1].Number * yyvsp[0].Number;
;
break;}
case 47:
#line 425 "getdate.y"
#line 434 "getdate.y"
{
yyRelSeconds += yyvsp[0].Number;
context->yyRelSeconds += yyvsp[0].Number;
;
break;}
case 48:
#line 431 "getdate.y"
#line 440 "getdate.y"
{
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = yyvsp[0].Number;
if (context->yyHaveTime && context->yyHaveDate &&
!context->yyHaveRel)
context->yyYear = yyvsp[0].Number;
else
{
if (yyvsp[0].Number>10000)
{
yyHaveDate++;
yyDay= (yyvsp[0].Number)%100;
yyMonth= (yyvsp[0].Number/100)%100;
yyYear = yyvsp[0].Number/10000;
context->yyHaveDate++;
context->yyDay= (yyvsp[0].Number)%100;
context->yyMonth= (yyvsp[0].Number/100)%100;
context->yyYear = yyvsp[0].Number/10000;
}
else
{
yyHaveTime++;
context->yyHaveTime++;
if (yyvsp[0].Number < 100)
{
yyHour = yyvsp[0].Number;
yyMinutes = 0;
context->yyHour = yyvsp[0].Number;
context->yyMinutes = 0;
}
else
{
yyHour = yyvsp[0].Number / 100;
yyMinutes = yyvsp[0].Number % 100;
context->yyHour = yyvsp[0].Number / 100;
context->yyMinutes = yyvsp[0].Number % 100;
}
yySeconds = 0;
yyMeridian = MER24;
context->yySeconds = 0;
context->yyMeridian = MER24;
}
}
;
break;}
case 49:
#line 464 "getdate.y"
#line 474 "getdate.y"
{
yyval.Meridian = MER24;
;
break;}
case 50:
#line 468 "getdate.y"
#line 478 "getdate.y"
{
yyval.Meridian = yyvsp[0].Meridian;
;
@@ -1516,7 +1523,7 @@ yyerrhandle:
}
return 1;
}
#line 473 "getdate.y"
#line 483 "getdate.y"
/* Include this file down here because bison inserts code above which
@@ -1772,7 +1779,8 @@ ToYear (Year)
}
static int
LookupWord (buff)
LookupWord (yylval, buff)
YYSTYPE *yylval;
char *buff;
{
register char *p;
@@ -1788,12 +1796,12 @@ LookupWord (buff)
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
{
yylval.Meridian = MERam;
yylval->Meridian = MERam;
return tMERIDIAN;
}
if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
{
yylval.Meridian = MERpm;
yylval->Meridian = MERpm;
return tMERIDIAN;
}
@@ -1814,13 +1822,13 @@ LookupWord (buff)
{
if (strncmp (buff, tp->name, 3) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
else if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
@@ -1828,7 +1836,7 @@ LookupWord (buff)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -1838,7 +1846,7 @@ LookupWord (buff)
for (tp = UnitsTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -1850,7 +1858,7 @@ LookupWord (buff)
for (tp = UnitsTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
buff[i] = 's'; /* Put back for "this" in OtherTable. */
@@ -1859,7 +1867,7 @@ LookupWord (buff)
for (tp = OtherTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -1869,7 +1877,7 @@ LookupWord (buff)
for (tp = MilitaryTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
@@ -1885,7 +1893,7 @@ LookupWord (buff)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -1893,7 +1901,9 @@ LookupWord (buff)
}
static int
yylex ()
yylex (yylval, cookie)
YYSTYPE *yylval;
void *cookie;
{
register unsigned char c;
register char *p;
@@ -1903,42 +1913,42 @@ yylex ()
for (;;)
{
while (ISSPACE ((unsigned char) *yyInput))
yyInput++;
while (ISSPACE ((unsigned char) *context->yyInput))
context->yyInput++;
if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
{
if (c == '-' || c == '+')
{
sign = c == '-' ? -1 : 1;
if (!ISDIGIT (*++yyInput))
if (!ISDIGIT (*++context->yyInput))
/* skip the '-' sign */
continue;
}
else
sign = 0;
for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
yylval.Number = 10 * yylval.Number + c - '0';
yyInput--;
for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
yylval->Number = 10 * yylval->Number + c - '0';
context->yyInput--;
if (sign < 0)
yylval.Number = -yylval.Number;
yylval->Number = -yylval->Number;
return sign ? tSNUMBER : tUNUMBER;
}
if (ISALPHA (c))
{
for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';)
if (p < &buff[sizeof buff - 1])
*p++ = c;
*p = '\0';
yyInput--;
return LookupWord (buff);
context->yyInput--;
return LookupWord (yylval, buff);
}
if (c != '(')
return *yyInput++;
return *context->yyInput++;
Count = 0;
do
{
c = *yyInput++;
c = *context->yyInput++;
if (c == '\0')
return c;
if (c == '(')
@@ -1978,10 +1988,11 @@ curl_getdate (const char *p, const time_t *now)
{
struct tm tm, tm0, *tmp;
time_t Start;
CONTEXT cookie;
#ifdef HAVE_LOCALTIME_R
struct tm keeptime;
#endif
yyInput = p;
cookie.yyInput = p;
Start = now ? *now : time ((time_t *) NULL);
#ifdef HAVE_LOCALTIME_R
tmp = (struct tm *)localtime_r(&Start, &keeptime);
@@ -1990,52 +2001,55 @@ curl_getdate (const char *p, const time_t *now)
#endif
if (!tmp)
return -1;
yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
yyMonth = tmp->tm_mon + 1;
yyDay = tmp->tm_mday;
yyHour = tmp->tm_hour;
yyMinutes = tmp->tm_min;
yySeconds = tmp->tm_sec;
cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
cookie.yyMonth = tmp->tm_mon + 1;
cookie.yyDay = tmp->tm_mday;
cookie.yyHour = tmp->tm_hour;
cookie.yyMinutes = tmp->tm_min;
cookie.yySeconds = tmp->tm_sec;
tm.tm_isdst = tmp->tm_isdst;
yyMeridian = MER24;
yyRelSeconds = 0;
yyRelMinutes = 0;
yyRelHour = 0;
yyRelDay = 0;
yyRelMonth = 0;
yyRelYear = 0;
yyHaveDate = 0;
yyHaveDay = 0;
yyHaveRel = 0;
yyHaveTime = 0;
yyHaveZone = 0;
cookie.yyMeridian = MER24;
cookie.yyRelSeconds = 0;
cookie.yyRelMinutes = 0;
cookie.yyRelHour = 0;
cookie.yyRelDay = 0;
cookie.yyRelMonth = 0;
cookie.yyRelYear = 0;
cookie.yyHaveDate = 0;
cookie.yyHaveDay = 0;
cookie.yyHaveRel = 0;
cookie.yyHaveTime = 0;
cookie.yyHaveZone = 0;
if (yyparse ()
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
if (yyparse (&cookie)
|| cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
return -1;
tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
tm.tm_mon = yyMonth - 1 + yyRelMonth;
tm.tm_mday = yyDay + yyRelDay;
if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
if (cookie.yyHaveTime ||
(cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay))
{
tm.tm_hour = ToHour (yyHour, yyMeridian);
tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian);
if (tm.tm_hour < 0)
return -1;
tm.tm_min = yyMinutes;
tm.tm_sec = yySeconds;
tm.tm_min = cookie.yyMinutes;
tm.tm_sec = cookie.yySeconds;
}
else
{
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
}
tm.tm_hour += yyRelHour;
tm.tm_min += yyRelMinutes;
tm.tm_sec += yyRelSeconds;
tm.tm_hour += cookie.yyRelHour;
tm.tm_min += cookie.yyRelMinutes;
tm.tm_sec += cookie.yyRelSeconds;
/* Let mktime deduce tm_isdst if we have an absolute timestamp,
or if the relative timestamp mentions days, months, or years. */
if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear)
if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime |
cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear)
tm.tm_isdst = -1;
tm0 = tm;
@@ -2053,18 +2067,18 @@ curl_getdate (const char *p, const time_t *now)
we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
zone by 24 hours to compensate. This algorithm assumes that
there is no DST transition within a day of the time_t boundaries. */
if (yyHaveZone)
if (cookie.yyHaveZone)
{
tm = tm0;
if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
{
tm.tm_mday++;
yyTimezone -= 24 * 60;
cookie.yyTimezone -= 24 * 60;
}
else
{
tm.tm_mday--;
yyTimezone += 24 * 60;
cookie.yyTimezone += 24 * 60;
}
Start = mktime (&tm);
}
@@ -2073,22 +2087,29 @@ curl_getdate (const char *p, const time_t *now)
return Start;
}
if (yyHaveDay && !yyHaveDate)
if (cookie.yyHaveDay && !cookie.yyHaveDate)
{
tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+ 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
+ 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
Start = mktime (&tm);
if (Start == (time_t) -1)
return Start;
}
if (yyHaveZone)
if (cookie.yyHaveZone)
{
long delta;
struct tm *gmt = gmtime (&Start);
struct tm *gmt;
#ifdef HAVE_GMTIME_R
/* thread-safe version */
struct tm keeptime;
gmt = (struct tm *)gmtime_r(&Start, &keeptime);
#else
gmt = gmtime(&Start);
#endif
if (!gmt)
return -1;
delta = yyTimezone * 60L + difftm (&tm, gmt);
delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
if ((Start + delta < Start) != (delta < 0))
return -1; /* time_t overflow */
Start += delta;
@@ -2126,11 +2147,3 @@ main (ac, av)
/* NOTREACHED */
}
#endif /* defined (TEST) */
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78
*/

View File

@@ -7,9 +7,7 @@
** This code is in the public domain and has no copyright.
*/
#if HAVE_CONFIG_H
# include <config.h>
#endif
# include "setup.h"
#ifndef PARAMS
# if defined PROTOTYPES || (defined __STDC__ && __STDC__)

View File

@@ -10,8 +10,6 @@
#include "setup.h"
#ifdef HAVE_CONFIG_H
# include "config.h"
# ifdef HAVE_ALLOCA_H
# include <alloca.h>
# endif
@@ -19,6 +17,10 @@
# ifdef HAVE_TIME_H
# include <time.h>
# endif
#ifndef YYDEBUG
/* to satisfy gcc -Wundef, we set this to 0 */
#define YYDEBUG 0
#endif
/* Since the code of getdate.y is not included in the Emacs executable
@@ -168,41 +170,48 @@ typedef enum _MERIDIAN {
MERam, MERpm, MER24
} MERIDIAN;
/* parse results and input string */
typedef struct _CONTEXT {
const char *yyInput;
int yyDayOrdinal;
int yyDayNumber;
int yyHaveDate;
int yyHaveDay;
int yyHaveRel;
int yyHaveTime;
int yyHaveZone;
int yyTimezone;
int yyDay;
int yyHour;
int yyMinutes;
int yyMonth;
int yySeconds;
int yyYear;
MERIDIAN yyMeridian;
int yyRelDay;
int yyRelHour;
int yyRelMinutes;
int yyRelMonth;
int yyRelSeconds;
int yyRelYear;
} CONTEXT;
/*
** Global variables. We could get rid of most of these by using a good
** union as the yacc stack. (This routine was originally written before
** yacc had the %union construct.) Maybe someday; right now we only use
** the %union very rarely.
/* enable use of extra argument to yyparse and yylex which can be used to pass
** in a user defined value (CONTEXT struct in our case)
*/
static const char *yyInput;
static int yyDayOrdinal;
static int yyDayNumber;
static int yyHaveDate;
static int yyHaveDay;
static int yyHaveRel;
static int yyHaveTime;
static int yyHaveZone;
static int yyTimezone;
static int yyDay;
static int yyHour;
static int yyMinutes;
static int yyMonth;
static int yySeconds;
static int yyYear;
static MERIDIAN yyMeridian;
static int yyRelDay;
static int yyRelHour;
static int yyRelMinutes;
static int yyRelMonth;
static int yyRelSeconds;
static int yyRelYear;
#define YYPARSE_PARAM cookie
#define YYLEX_PARAM cookie
#define context ((CONTEXT *) cookie)
%}
/* This grammar has 13 shift/reduce conflicts. */
%expect 13
/* turn global variables into locals, additionally enable extra arguments
** for yylex (pointer to yylval and user defined value)
*/
%pure_parser
%union {
int Number;
enum _MERIDIAN Meridian;
@@ -224,91 +233,91 @@ spec : /* NULL */
;
item : time {
yyHaveTime++;
context->yyHaveTime++;
}
| zone {
yyHaveZone++;
context->yyHaveZone++;
}
| date {
yyHaveDate++;
context->yyHaveDate++;
}
| day {
yyHaveDay++;
context->yyHaveDay++;
}
| rel {
yyHaveRel++;
context->yyHaveRel++;
}
| number
;
time : tUNUMBER tMERIDIAN {
yyHour = $1;
yyMinutes = 0;
yySeconds = 0;
yyMeridian = $2;
context->yyHour = $1;
context->yyMinutes = 0;
context->yySeconds = 0;
context->yyMeridian = $2;
}
| tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = 0;
yyMeridian = $4;
context->yyHour = $1;
context->yyMinutes = $3;
context->yySeconds = 0;
context->yyMeridian = $4;
}
| tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yyMeridian = MER24;
yyHaveZone++;
yyTimezone = ($4 < 0
? -$4 % 100 + (-$4 / 100) * 60
: - ($4 % 100 + ($4 / 100) * 60));
context->yyHour = $1;
context->yyMinutes = $3;
context->yyMeridian = MER24;
context->yyHaveZone++;
context->yyTimezone = ($4 < 0
? -$4 % 100 + (-$4 / 100) * 60
: - ($4 % 100 + ($4 / 100) * 60));
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER o_merid {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = $6;
context->yyHour = $1;
context->yyMinutes = $3;
context->yySeconds = $5;
context->yyMeridian = $6;
}
| tUNUMBER ':' tUNUMBER ':' tUNUMBER tSNUMBER {
yyHour = $1;
yyMinutes = $3;
yySeconds = $5;
yyMeridian = MER24;
yyHaveZone++;
yyTimezone = ($6 < 0
? -$6 % 100 + (-$6 / 100) * 60
: - ($6 % 100 + ($6 / 100) * 60));
context->yyHour = $1;
context->yyMinutes = $3;
context->yySeconds = $5;
context->yyMeridian = MER24;
context->yyHaveZone++;
context->yyTimezone = ($6 < 0
? -$6 % 100 + (-$6 / 100) * 60
: - ($6 % 100 + ($6 / 100) * 60));
}
;
zone : tZONE {
yyTimezone = $1;
context->yyTimezone = $1;
}
| tDAYZONE {
yyTimezone = $1 - 60;
context->yyTimezone = $1 - 60;
}
|
tZONE tDST {
yyTimezone = $1 - 60;
context->yyTimezone = $1 - 60;
}
;
day : tDAY {
yyDayOrdinal = 1;
yyDayNumber = $1;
context->yyDayOrdinal = 1;
context->yyDayNumber = $1;
}
| tDAY ',' {
yyDayOrdinal = 1;
yyDayNumber = $1;
context->yyDayOrdinal = 1;
context->yyDayNumber = $1;
}
| tUNUMBER tDAY {
yyDayOrdinal = $1;
yyDayNumber = $2;
context->yyDayOrdinal = $1;
context->yyDayNumber = $2;
}
;
date : tUNUMBER '/' tUNUMBER {
yyMonth = $1;
yyDay = $3;
context->yyMonth = $1;
context->yyDay = $3;
}
| tUNUMBER '/' tUNUMBER '/' tUNUMBER {
/* Interpret as YYYY/MM/DD if $1 >= 1000, otherwise as MM/DD/YY.
@@ -317,144 +326,145 @@ date : tUNUMBER '/' tUNUMBER {
you want portability, use the ISO 8601 format. */
if ($1 >= 1000)
{
yyYear = $1;
yyMonth = $3;
yyDay = $5;
context->yyYear = $1;
context->yyMonth = $3;
context->yyDay = $5;
}
else
{
yyMonth = $1;
yyDay = $3;
yyYear = $5;
context->yyMonth = $1;
context->yyDay = $3;
context->yyYear = $5;
}
}
| tUNUMBER tSNUMBER tSNUMBER {
/* ISO 8601 format. yyyy-mm-dd. */
yyYear = $1;
yyMonth = -$2;
yyDay = -$3;
context->yyYear = $1;
context->yyMonth = -$2;
context->yyDay = -$3;
}
| tUNUMBER tMONTH tSNUMBER {
/* e.g. 17-JUN-1992. */
yyDay = $1;
yyMonth = $2;
yyYear = -$3;
context->yyDay = $1;
context->yyMonth = $2;
context->yyYear = -$3;
}
| tMONTH tUNUMBER {
yyMonth = $1;
yyDay = $2;
context->yyMonth = $1;
context->yyDay = $2;
}
| tMONTH tUNUMBER ',' tUNUMBER {
yyMonth = $1;
yyDay = $2;
yyYear = $4;
context->yyMonth = $1;
context->yyDay = $2;
context->yyYear = $4;
}
| tUNUMBER tMONTH {
yyMonth = $2;
yyDay = $1;
context->yyMonth = $2;
context->yyDay = $1;
}
| tUNUMBER tMONTH tUNUMBER {
yyMonth = $2;
yyDay = $1;
yyYear = $3;
context->yyMonth = $2;
context->yyDay = $1;
context->yyYear = $3;
}
;
rel : relunit tAGO {
yyRelSeconds = -yyRelSeconds;
yyRelMinutes = -yyRelMinutes;
yyRelHour = -yyRelHour;
yyRelDay = -yyRelDay;
yyRelMonth = -yyRelMonth;
yyRelYear = -yyRelYear;
context->yyRelSeconds = -context->yyRelSeconds;
context->yyRelMinutes = -context->yyRelMinutes;
context->yyRelHour = -context->yyRelHour;
context->yyRelDay = -context->yyRelDay;
context->yyRelMonth = -context->yyRelMonth;
context->yyRelYear = -context->yyRelYear;
}
| relunit
;
relunit : tUNUMBER tYEAR_UNIT {
yyRelYear += $1 * $2;
context->yyRelYear += $1 * $2;
}
| tSNUMBER tYEAR_UNIT {
yyRelYear += $1 * $2;
context->yyRelYear += $1 * $2;
}
| tYEAR_UNIT {
yyRelYear += $1;
context->yyRelYear += $1;
}
| tUNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
context->yyRelMonth += $1 * $2;
}
| tSNUMBER tMONTH_UNIT {
yyRelMonth += $1 * $2;
context->yyRelMonth += $1 * $2;
}
| tMONTH_UNIT {
yyRelMonth += $1;
context->yyRelMonth += $1;
}
| tUNUMBER tDAY_UNIT {
yyRelDay += $1 * $2;
context->yyRelDay += $1 * $2;
}
| tSNUMBER tDAY_UNIT {
yyRelDay += $1 * $2;
context->yyRelDay += $1 * $2;
}
| tDAY_UNIT {
yyRelDay += $1;
context->yyRelDay += $1;
}
| tUNUMBER tHOUR_UNIT {
yyRelHour += $1 * $2;
context->yyRelHour += $1 * $2;
}
| tSNUMBER tHOUR_UNIT {
yyRelHour += $1 * $2;
context->yyRelHour += $1 * $2;
}
| tHOUR_UNIT {
yyRelHour += $1;
context->yyRelHour += $1;
}
| tUNUMBER tMINUTE_UNIT {
yyRelMinutes += $1 * $2;
context->yyRelMinutes += $1 * $2;
}
| tSNUMBER tMINUTE_UNIT {
yyRelMinutes += $1 * $2;
context->yyRelMinutes += $1 * $2;
}
| tMINUTE_UNIT {
yyRelMinutes += $1;
context->yyRelMinutes += $1;
}
| tUNUMBER tSEC_UNIT {
yyRelSeconds += $1 * $2;
context->yyRelSeconds += $1 * $2;
}
| tSNUMBER tSEC_UNIT {
yyRelSeconds += $1 * $2;
context->yyRelSeconds += $1 * $2;
}
| tSEC_UNIT {
yyRelSeconds += $1;
context->yyRelSeconds += $1;
}
;
number : tUNUMBER
{
if (yyHaveTime && yyHaveDate && !yyHaveRel)
yyYear = $1;
if (context->yyHaveTime && context->yyHaveDate &&
!context->yyHaveRel)
context->yyYear = $1;
else
{
if ($1>10000)
{
yyHaveDate++;
yyDay= ($1)%100;
yyMonth= ($1/100)%100;
yyYear = $1/10000;
context->yyHaveDate++;
context->yyDay= ($1)%100;
context->yyMonth= ($1/100)%100;
context->yyYear = $1/10000;
}
else
{
yyHaveTime++;
context->yyHaveTime++;
if ($1 < 100)
{
yyHour = $1;
yyMinutes = 0;
context->yyHour = $1;
context->yyMinutes = 0;
}
else
{
yyHour = $1 / 100;
yyMinutes = $1 % 100;
context->yyHour = $1 / 100;
context->yyMinutes = $1 % 100;
}
yySeconds = 0;
yyMeridian = MER24;
context->yySeconds = 0;
context->yyMeridian = MER24;
}
}
}
@@ -725,7 +735,8 @@ ToYear (Year)
}
static int
LookupWord (buff)
LookupWord (yylval, buff)
YYSTYPE *yylval;
char *buff;
{
register char *p;
@@ -741,12 +752,12 @@ LookupWord (buff)
if (strcmp (buff, "am") == 0 || strcmp (buff, "a.m.") == 0)
{
yylval.Meridian = MERam;
yylval->Meridian = MERam;
return tMERIDIAN;
}
if (strcmp (buff, "pm") == 0 || strcmp (buff, "p.m.") == 0)
{
yylval.Meridian = MERpm;
yylval->Meridian = MERpm;
return tMERIDIAN;
}
@@ -767,13 +778,13 @@ LookupWord (buff)
{
if (strncmp (buff, tp->name, 3) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
else if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
@@ -781,7 +792,7 @@ LookupWord (buff)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -791,7 +802,7 @@ LookupWord (buff)
for (tp = UnitsTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -803,7 +814,7 @@ LookupWord (buff)
for (tp = UnitsTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
buff[i] = 's'; /* Put back for "this" in OtherTable. */
@@ -812,7 +823,7 @@ LookupWord (buff)
for (tp = OtherTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -822,7 +833,7 @@ LookupWord (buff)
for (tp = MilitaryTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
}
@@ -838,7 +849,7 @@ LookupWord (buff)
for (tp = TimezoneTable; tp->name; tp++)
if (strcmp (buff, tp->name) == 0)
{
yylval.Number = tp->value;
yylval->Number = tp->value;
return tp->type;
}
@@ -846,7 +857,9 @@ LookupWord (buff)
}
static int
yylex ()
yylex (yylval, cookie)
YYSTYPE *yylval;
void *cookie;
{
register unsigned char c;
register char *p;
@@ -856,42 +869,42 @@ yylex ()
for (;;)
{
while (ISSPACE ((unsigned char) *yyInput))
yyInput++;
while (ISSPACE ((unsigned char) *context->yyInput))
context->yyInput++;
if (ISDIGIT (c = *yyInput) || c == '-' || c == '+')
if (ISDIGIT (c = *context->yyInput) || c == '-' || c == '+')
{
if (c == '-' || c == '+')
{
sign = c == '-' ? -1 : 1;
if (!ISDIGIT (*++yyInput))
if (!ISDIGIT (*++context->yyInput))
/* skip the '-' sign */
continue;
}
else
sign = 0;
for (yylval.Number = 0; ISDIGIT (c = *yyInput++);)
yylval.Number = 10 * yylval.Number + c - '0';
yyInput--;
for (yylval->Number = 0; ISDIGIT (c = *context->yyInput++);)
yylval->Number = 10 * yylval->Number + c - '0';
context->yyInput--;
if (sign < 0)
yylval.Number = -yylval.Number;
yylval->Number = -yylval->Number;
return sign ? tSNUMBER : tUNUMBER;
}
if (ISALPHA (c))
{
for (p = buff; (c = *yyInput++, ISALPHA (c)) || c == '.';)
for (p = buff; (c = *context->yyInput++, ISALPHA (c)) || c == '.';)
if (p < &buff[sizeof buff - 1])
*p++ = c;
*p = '\0';
yyInput--;
return LookupWord (buff);
context->yyInput--;
return LookupWord (yylval, buff);
}
if (c != '(')
return *yyInput++;
return *context->yyInput++;
Count = 0;
do
{
c = *yyInput++;
c = *context->yyInput++;
if (c == '\0')
return c;
if (c == '(')
@@ -931,10 +944,11 @@ curl_getdate (const char *p, const time_t *now)
{
struct tm tm, tm0, *tmp;
time_t Start;
CONTEXT cookie;
#ifdef HAVE_LOCALTIME_R
struct tm keeptime;
#endif
yyInput = p;
cookie.yyInput = p;
Start = now ? *now : time ((time_t *) NULL);
#ifdef HAVE_LOCALTIME_R
tmp = (struct tm *)localtime_r(&Start, &keeptime);
@@ -943,52 +957,55 @@ curl_getdate (const char *p, const time_t *now)
#endif
if (!tmp)
return -1;
yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
yyMonth = tmp->tm_mon + 1;
yyDay = tmp->tm_mday;
yyHour = tmp->tm_hour;
yyMinutes = tmp->tm_min;
yySeconds = tmp->tm_sec;
cookie.yyYear = tmp->tm_year + TM_YEAR_ORIGIN;
cookie.yyMonth = tmp->tm_mon + 1;
cookie.yyDay = tmp->tm_mday;
cookie.yyHour = tmp->tm_hour;
cookie.yyMinutes = tmp->tm_min;
cookie.yySeconds = tmp->tm_sec;
tm.tm_isdst = tmp->tm_isdst;
yyMeridian = MER24;
yyRelSeconds = 0;
yyRelMinutes = 0;
yyRelHour = 0;
yyRelDay = 0;
yyRelMonth = 0;
yyRelYear = 0;
yyHaveDate = 0;
yyHaveDay = 0;
yyHaveRel = 0;
yyHaveTime = 0;
yyHaveZone = 0;
cookie.yyMeridian = MER24;
cookie.yyRelSeconds = 0;
cookie.yyRelMinutes = 0;
cookie.yyRelHour = 0;
cookie.yyRelDay = 0;
cookie.yyRelMonth = 0;
cookie.yyRelYear = 0;
cookie.yyHaveDate = 0;
cookie.yyHaveDay = 0;
cookie.yyHaveRel = 0;
cookie.yyHaveTime = 0;
cookie.yyHaveZone = 0;
if (yyparse ()
|| yyHaveTime > 1 || yyHaveZone > 1 || yyHaveDate > 1 || yyHaveDay > 1)
if (yyparse (&cookie)
|| cookie.yyHaveTime > 1 || cookie.yyHaveZone > 1 ||
cookie.yyHaveDate > 1 || cookie.yyHaveDay > 1)
return -1;
tm.tm_year = ToYear (yyYear) - TM_YEAR_ORIGIN + yyRelYear;
tm.tm_mon = yyMonth - 1 + yyRelMonth;
tm.tm_mday = yyDay + yyRelDay;
if (yyHaveTime || (yyHaveRel && !yyHaveDate && !yyHaveDay))
tm.tm_year = ToYear (cookie.yyYear) - TM_YEAR_ORIGIN + cookie.yyRelYear;
tm.tm_mon = cookie.yyMonth - 1 + cookie.yyRelMonth;
tm.tm_mday = cookie.yyDay + cookie.yyRelDay;
if (cookie.yyHaveTime ||
(cookie.yyHaveRel && !cookie.yyHaveDate && !cookie.yyHaveDay))
{
tm.tm_hour = ToHour (yyHour, yyMeridian);
tm.tm_hour = ToHour (cookie.yyHour, cookie.yyMeridian);
if (tm.tm_hour < 0)
return -1;
tm.tm_min = yyMinutes;
tm.tm_sec = yySeconds;
tm.tm_min = cookie.yyMinutes;
tm.tm_sec = cookie.yySeconds;
}
else
{
tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
}
tm.tm_hour += yyRelHour;
tm.tm_min += yyRelMinutes;
tm.tm_sec += yyRelSeconds;
tm.tm_hour += cookie.yyRelHour;
tm.tm_min += cookie.yyRelMinutes;
tm.tm_sec += cookie.yyRelSeconds;
/* Let mktime deduce tm_isdst if we have an absolute timestamp,
or if the relative timestamp mentions days, months, or years. */
if (yyHaveDate | yyHaveDay | yyHaveTime | yyRelDay | yyRelMonth | yyRelYear)
if (cookie.yyHaveDate | cookie.yyHaveDay | cookie.yyHaveTime |
cookie.yyRelDay | cookie.yyRelMonth | cookie.yyRelYear)
tm.tm_isdst = -1;
tm0 = tm;
@@ -1006,18 +1023,18 @@ curl_getdate (const char *p, const time_t *now)
we apply mktime to 1970-01-02 08:00:00 instead and adjust the time
zone by 24 hours to compensate. This algorithm assumes that
there is no DST transition within a day of the time_t boundaries. */
if (yyHaveZone)
if (cookie.yyHaveZone)
{
tm = tm0;
if (tm.tm_year <= EPOCH - TM_YEAR_ORIGIN)
{
tm.tm_mday++;
yyTimezone -= 24 * 60;
cookie.yyTimezone -= 24 * 60;
}
else
{
tm.tm_mday--;
yyTimezone += 24 * 60;
cookie.yyTimezone += 24 * 60;
}
Start = mktime (&tm);
}
@@ -1026,22 +1043,29 @@ curl_getdate (const char *p, const time_t *now)
return Start;
}
if (yyHaveDay && !yyHaveDate)
if (cookie.yyHaveDay && !cookie.yyHaveDate)
{
tm.tm_mday += ((yyDayNumber - tm.tm_wday + 7) % 7
+ 7 * (yyDayOrdinal - (0 < yyDayOrdinal)));
tm.tm_mday += ((cookie.yyDayNumber - tm.tm_wday + 7) % 7
+ 7 * (cookie.yyDayOrdinal - (0 < cookie.yyDayOrdinal)));
Start = mktime (&tm);
if (Start == (time_t) -1)
return Start;
}
if (yyHaveZone)
if (cookie.yyHaveZone)
{
long delta;
struct tm *gmt = gmtime (&Start);
struct tm *gmt;
#ifdef HAVE_GMTIME_R
/* thread-safe version */
struct tm keeptime;
gmt = (struct tm *)gmtime_r(&Start, &keeptime);
#else
gmt = gmtime(&Start);
#endif
if (!gmt)
return -1;
delta = yyTimezone * 60L + difftm (&tm, gmt);
delta = cookie.yyTimezone * 60L + difftm (&tm, gmt);
if ((Start + delta < Start) != (delta < 0))
return -1; /* time_t overflow */
Start += delta;

View File

@@ -55,7 +55,6 @@ char *GetEnv(const char *variable)
if (env && strcmp("HOME",variable) == 0) {
env = decc$translate_vms(env);
}
/* printf ("Getenv: %s=%s\n",variable,env); */
#else
/* no length control */
char *env = getenv(variable);

View File

@@ -31,6 +31,10 @@
#include <string.h>
#include <stdarg.h>
#ifdef VMS
#include <stdlib.h>
#endif
/*
* This is supposed to be called in the beginning of a permform() session
* and should reset all session-info variables
@@ -44,11 +48,18 @@ CURLcode Curl_initinfo(struct SessionHandle *data)
pro->t_connect = 0;
pro->t_pretransfer = 0;
pro->t_starttransfer = 0;
pro->timespent = 0;
info->httpcode = 0;
info->httpversion=0;
info->filetime=-1; /* -1 is an illegal time and thus means unknown */
if (info->contenttype)
free(info->contenttype);
info->contenttype = NULL;
info->header_size = 0;
info->request_size = 0;
return CURLE_OK;
}
@@ -132,6 +143,9 @@ CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
case CURLINFO_CONTENT_LENGTH_UPLOAD:
*param_doublep = data->progress.size_ul;
break;
case CURLINFO_CONTENT_TYPE:
*param_charp = data->info.contenttype;
break;
default:
return CURLE_BAD_FUNCTION_ARGUMENT;
}

285
lib/hash.c Normal file
View File

@@ -0,0 +1,285 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include "setup.h"
#include <string.h>
#include <stdlib.h>
#include "hash.h"
#include "llist.h"
#ifdef MALLOCDEBUG
/* this must be the last include file */
#include "memdebug.h"
#endif
static unsigned long
curl_hash_str(const char *key, unsigned int key_length)
{
register unsigned long h = 0;
register unsigned long g;
register char *p = (char *) key;
register char *end = (char *) key + key_length;
while (p < end) {
h = (h << 4) + *p++;
if ((g = (h & 0xF0000000))) {
h = h ^ (g >> 24);
h = h ^ g;
}
}
return h;
}
static unsigned long
curl_hash_num(unsigned long key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += (key << 11);
key ^= (key >> 16);
return key;
}
static void
hash_element_dtor(void *u, void *ele)
{
curl_hash_element *e = (curl_hash_element *) ele;
curl_hash *h = (curl_hash *) u;
if (e->key.type == CURL_HASH_KEY_IS_STRING) {
free(e->key.value.str.val);
}
h->dtor(e->ptr);
free(e);
e = NULL;
}
void
curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor)
{
int i;
h->dtor = dtor;
h->size = 0;
h->slots = slots;
h->table = (curl_llist **) malloc(slots * sizeof(curl_llist *));
for (i = 0; i < h->slots; ++i) {
h->table[i] = curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
}
}
curl_hash *
curl_hash_alloc(int slots, curl_hash_dtor dtor)
{
curl_hash *h;
h = (curl_hash *)malloc(sizeof(curl_hash));
if(NULL == h)
return NULL;
curl_hash_init(h, slots, dtor);
return h;
}
#define FIND_SLOT(__h, __s_key, __s_key_len, __n_key) \
((__s_key ? curl_hash_str(__s_key, __s_key_len) : curl_hash_num(__n_key)) % (__h)->slots)
#define KEY_CREATE(__k, __s_key, __s_key_len, __n_key, __dup) \
if (__s_key) { \
if (__dup) { \
(__k)->value.str.val = (char *) malloc(__s_key_len); \
memcpy((__k)->value.str.val, __s_key, __s_key_len); \
} else { \
(__k)->value.str.val = __s_key; \
} \
(__k)->value.str.len = __s_key_len; \
(__k)->type = CURL_HASH_KEY_IS_STRING; \
} else { \
(__k)->value.num = __n_key; \
(__k)->type = CURL_HASH_KEY_IS_NUM; \
}
#define MIN(a, b) (a > b ? b : a)
static int
curl_hash_key_compare(curl_hash_key *key1, curl_hash_key *key2)
{
if (key1->type == CURL_HASH_KEY_IS_NUM) {
if (key2->type == CURL_HASH_KEY_IS_STRING)
return 0;
if (key1->value.num == key2->value.num)
return 1;
} else {
if (key2->type == CURL_HASH_KEY_IS_NUM)
return 0;
if (memcmp(key1->value.str.val, key2->value.str.val,
MIN(key1->value.str.len, key2->value.str.len)) == 0)
return 1;
}
return 0;
}
int
curl_hash_add_or_update(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key, const void *p)
{
curl_hash_element *e;
curl_hash_key tmp;
curl_llist *l;
curl_llist_element *le;
int slot;
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
l = h->table[slot];
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
curl_hash_element *to_update = CURL_LLIST_VALP(le);
h->dtor(to_update->ptr);
to_update->ptr = (void *) p;
return 1;
}
}
e = (curl_hash_element *) malloc(sizeof(curl_hash_element));
KEY_CREATE(&e->key, str_key, str_key_len, num_key, 1);
e->ptr = (void *) p;
if (curl_llist_insert_next(l, CURL_LLIST_TAIL(l), e)) {
++h->size;
return 1;
} else {
return 0;
}
}
int
curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key)
{
curl_llist *l;
curl_llist_element *le;
curl_hash_key tmp;
int slot;
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
l = h->table[slot];
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
curl_llist_remove(l, le, (void *) h);
--h->size;
return 1;
}
}
return 0;
}
int
curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key, void **p)
{
curl_llist *l;
curl_llist_element *le;
curl_hash_key tmp;
int slot;
slot = FIND_SLOT(h, str_key, str_key_len, num_key);
l = h->table[slot];
KEY_CREATE(&tmp, str_key, str_key_len, num_key, 0);
for (le = CURL_LLIST_HEAD(l); le != NULL; le = CURL_LLIST_NEXT(le)) {
if (curl_hash_key_compare(&tmp, &((curl_hash_element *) CURL_LLIST_VALP(le))->key)) {
*p = ((curl_hash_element *) CURL_LLIST_VALP(le))->ptr;
return 1;
}
}
return 0;
}
void
curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *))
{
curl_llist_element *le;
int i;
for (i = 0; i < h->slots; ++i) {
for (le = CURL_LLIST_HEAD(h->table[i]); le != NULL; le = CURL_LLIST_NEXT(le)) {
cb(user, (curl_hash_element *) CURL_LLIST_VALP(le));
}
}
}
void
curl_hash_clean(curl_hash *h)
{
int i;
for (i = 0; i < h->slots; ++i) {
curl_llist_destroy(h->table[i], (void *) h);
}
free(h->table);
h->table = NULL;
}
size_t
curl_hash_count(curl_hash *h)
{
return h->size;
}
void
curl_hash_destroy(curl_hash *h)
{
if (!h) {
return;
}
curl_hash_clean(h);
free(h);
h = NULL;
}
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78
*/

85
lib/hash.h Normal file
View File

@@ -0,0 +1,85 @@
#ifndef __HASH_H
#define __HASH_H
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include "setup.h"
#include <stddef.h>
#include "llist.h"
#define CURL_HASH_KEY_IS_STRING 0
#define CURL_HASH_KEY_IS_NUM 1
typedef void (*curl_hash_dtor)(void *);
typedef struct _curl_hash {
curl_llist **table;
curl_hash_dtor dtor;
int slots;
size_t size;
} curl_hash;
typedef struct _curl_hash_key {
union {
struct {
char *val;
unsigned int len;
} str;
unsigned long num;
} value;
int type;
} curl_hash_key;
typedef struct _curl_hash_element {
curl_hash_key key;
void *ptr;
} curl_hash_element;
void curl_hash_init(curl_hash *h, int slots, curl_hash_dtor dtor);
curl_hash *curl_hash_alloc(int slots, curl_hash_dtor dtor);
int curl_hash_add_or_update(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key, const void *p);
int curl_hash_extended_delete(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key);
int curl_hash_extended_find(curl_hash *h, char *str_key, unsigned int str_key_len,
unsigned long num_key, void **p);
void curl_hash_apply(curl_hash *h, void *user, void (*cb)(void *, curl_hash_element *));
size_t curl_hash_count(curl_hash *h);
void curl_hash_clean(curl_hash *h);
void curl_hash_destroy(curl_hash *h);
#define curl_hash_find(h, key, key_len, p) curl_hash_extended_find(h, key, key_len, 0, p)
#define curl_hash_delete(h, key, key_len) curl_hash_extended_delete(h, key, key_len, 0)
#define curl_hash_add(h, key, key_len, p) curl_hash_add_or_update(h, key, key_len, 0, p)
#define curl_hash_update curl_hash_add
#define curl_hash_index_find(h, key, p) curl_hash_extended_find(h, NULL, 0, key, p)
#define curl_hash_index_delete(h, key) curl_hash_extended_delete(h, NULL, 0, key)
#define curl_hash_index_add(h, key, p) curl_hash_add_or_update(h, NULL, 0, key, p)
#define curl_hash_index_update curl_hash_index_add
#endif

View File

@@ -50,6 +50,7 @@
#include <stdlib.h> /* required for free() prototypes */
#endif
#ifdef VMS
#include <in.h>
#include <inet.h>
#include <stdlib.h>
#endif
@@ -58,6 +59,10 @@
#include "urldata.h"
#include "sendf.h"
#include "hostip.h"
#include "hash.h"
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
@@ -68,6 +73,151 @@
#include "memdebug.h"
#endif
static curl_hash hostname_cache;
static int host_cache_initialized;
void Curl_global_host_cache_init(void)
{
if (!host_cache_initialized) {
curl_hash_init(&hostname_cache, 7, Curl_freeaddrinfo);
host_cache_initialized = 1;
}
}
curl_hash *Curl_global_host_cache_get(void)
{
return &hostname_cache;
}
void Curl_global_host_cache_dtor(void)
{
if (host_cache_initialized) {
curl_hash_clean(&hostname_cache);
host_cache_initialized = 0;
}
}
struct curl_dns_cache_entry {
Curl_addrinfo *addr;
time_t timestamp;
};
/* count the number of characters that an integer takes up */
static int _num_chars(int i)
{
int chars = 0;
/* While the number divided by 10 is greater than one,
* re-divide the number by 10, and increment the number of
* characters by 1.
*
* this relies on the fact that for every multiple of 10,
* a new digit is added onto every number
*/
do {
chars++;
i = (int) i / 10;
} while (i >= 1);
return chars;
}
/* Create a hostcache id */
static char *
_create_hostcache_id(char *server, int port, ssize_t *entry_len)
{
char *id = NULL;
/* Get the length of the new entry id */
*entry_len = *entry_len + /* Hostname length */
1 + /* The ':' seperator */
_num_chars(port); /* The number of characters the port will take up */
/* Allocate the new entry id */
id = malloc(*entry_len + 1);
if (!id) {
return NULL;
}
/* Create the new entry */
/* If sprintf() doesn't return the entry length, that signals failure */
if (sprintf(id, "%s:%d", server, port) != *entry_len) {
/* Free the allocated id, set length to zero and return NULL */
*entry_len = 0;
free(id);
return NULL;
}
return id;
}
/* Macro to save redundant free'ing of entry_id */
#define _hostcache_return(__v) \
{ \
free(entry_id); \
return (__v); \
}
Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port,
char **bufp)
{
char *entry_id = NULL;
struct curl_dns_cache_entry *p = NULL;
ssize_t entry_len;
time_t now;
/* If the host cache timeout is 0, we don't do DNS cach'ing
so fall through */
if (data->set.dns_cache_timeout == 0) {
return Curl_getaddrinfo(data, hostname, port, bufp);
}
/* Create an entry id, based upon the hostname and port */
entry_len = strlen(hostname);
entry_id = _create_hostcache_id(hostname, port, &entry_len);
/* If we can't create the entry id, don't cache, just fall-through
to the plain Curl_getaddrinfo() */
if (!entry_id) {
return Curl_getaddrinfo(data, hostname, port, bufp);
}
time(&now);
/* See if its already in our dns cache */
if (entry_id && curl_hash_find(data->hostcache, entry_id, entry_len+1, (void **) &p)) {
/* Do we need to check for a cache timeout? */
if (data->set.dns_cache_timeout != -1) {
/* Return if the entry has not timed out */
if ((now - p->timestamp) < data->set.dns_cache_timeout) {
_hostcache_return(p->addr);
}
}
else {
_hostcache_return(p->addr);
}
}
/* Create a new cache entry */
p = (struct curl_dns_cache_entry *) malloc(sizeof(struct curl_dns_cache_entry));
if (!p) {
_hostcache_return(NULL);
}
p->addr = Curl_getaddrinfo(data, hostname, port, bufp);
if (!p->addr) {
free(p);
_hostcache_return(NULL);
}
p->timestamp = now;
/* Save it in our host cache */
curl_hash_update(data->hostcache, entry_id, entry_len+1, (const void *) p);
_hostcache_return(p->addr);
}
/*
* This is a wrapper function for freeing name information in a protocol
* independent way. This takes care of using the appropriate underlaying
@@ -75,11 +225,15 @@
*/
void Curl_freeaddrinfo(void *freethis)
{
struct curl_dns_cache_entry *p = (struct curl_dns_cache_entry *) freethis;
#ifdef ENABLE_IPV6
freeaddrinfo(freethis);
freeaddrinfo(p->addr);
#else
free(freethis);
free(p->addr);
#endif
free(p);
}
/* --- resolve name or IP-number --- */
@@ -102,7 +256,7 @@ int curl_getaddrinfo(char *hostname, char *service,
/* success */
if(logfile)
fprintf(logfile, "ADDR %s:%d getaddrinfo() = %p\n",
source, line, *result);
source, line, (void *)*result);
}
else {
if(logfile)
@@ -118,7 +272,7 @@ void curl_freeaddrinfo(struct addrinfo *freethis,
(freeaddrinfo)(freethis);
if(logfile)
fprintf(logfile, "ADDR %s:%d freeaddrinfo(%p)\n",
source, line, freethis);
source, line, (void *)freethis);
}
#endif
@@ -139,7 +293,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
char sbuf[NI_MAXSERV];
memset(&hints, 0, sizeof(hints));
hints.ai_family = PF_UNSPEC;
hints.ai_family = PF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_CANONNAME;
snprintf(sbuf, sizeof(sbuf), "%d", port);
@@ -256,7 +410,7 @@ static char *MakeIP(unsigned long num,char *addr, int addr_len)
considerably. */
#ifndef INADDR_NONE
#define INADDR_NONE (unsigned long) ~0
#define INADDR_NONE (in_addr_t) ~0
#endif
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
@@ -273,10 +427,10 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
* everything. OSF1 is known to require at least 8872 bytes. The buffer
* required for storing all possible aliases and IP numbers is according to
* Stevens' Unix Network Programming 2nd editor, p. 304: 8192 bytes! */
char *buf = (char *)malloc(CURL_NAMELOOKUP_SIZE);
int *buf = (int *)malloc(CURL_NAMELOOKUP_SIZE);
if(!buf)
return NULL; /* major failure */
*bufp = buf;
*bufp = (char *)buf;
port=0; /* unused in IPv4 code */
ret = 0; /* to prevent the compiler warning */
@@ -306,7 +460,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
/* Solaris, IRIX and more */
if ((h = gethostbyname_r(hostname,
(struct hostent *)buf,
buf + sizeof(struct hostent),
(char *)buf + sizeof(struct hostent),
CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
&h_errnop)) == NULL )
#endif
@@ -314,7 +468,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
/* Linux */
if( gethostbyname_r(hostname,
(struct hostent *)buf,
buf + sizeof(struct hostent),
(char *)buf + sizeof(struct hostent),
CURL_NAMELOOKUP_SIZE - sizeof(struct hostent),
&h, /* DIFFERENCE */
&h_errnop))
@@ -357,7 +511,7 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
/* we make a copy of the hostent right now, right here, as the
static one we got a pointer to might get removed when we don't
want/expect that */
h = pack_hostent(buf, h);
h = pack_hostent((char *)buf, h);
#endif
}
return (h);
@@ -372,3 +526,4 @@ Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78
*/

View File

@@ -23,10 +23,23 @@
* $Id$
*****************************************************************************/
#include "hash.h"
struct addrinfo;
struct hostent;
struct SessionHandle;
void Curl_global_host_cache_init(void);
void Curl_global_host_cache_dtor(void);
curl_hash *Curl_global_host_cache_get(void);
#define Curl_global_host_cache_use(__p) ((__p)->set.global_dns_cache)
Curl_addrinfo *Curl_resolv(struct SessionHandle *data,
char *hostname,
int port,
char **bufp);
/* Get name info */
Curl_addrinfo *Curl_getaddrinfo(struct SessionHandle *data,
char *hostname,

View File

@@ -128,8 +128,10 @@ static
CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
long *bytes_written)
{
size_t amount;
CURLcode result;
ssize_t amount;
CURLcode res;
char *ptr;
int size;
if(conn->data->set.verbose) {
fputs("> ", conn->data->set.err);
@@ -137,7 +139,25 @@ CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
fwrite(in->buffer, in->size_used, 1, conn->data->set.err);
}
result = Curl_write(conn, sockfd, in->buffer, in->size_used, &amount);
/* The looping below is required since we use non-blocking sockets, but due
to the circumstances we will just loop and try again and again etc */
ptr = in->buffer;
size = in->size_used;
do {
res = Curl_write(conn, sockfd, ptr, size, &amount);
if(CURLE_OK != res)
break;
if(amount != size) {
size -= amount;
ptr += amount;
}
else
break;
} while(1);
if(in->buffer)
free(in->buffer);
@@ -145,7 +165,7 @@ CURLcode add_buffer_send(int sockfd, struct connectdata *conn, send_buffer *in,
*bytes_written = amount;
return result;
return res;
}
@@ -235,6 +255,7 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
int subversion=0;
struct SessionHandle *data=conn->data;
CURLcode result;
int res;
int nread; /* total size read */
int perline; /* count bytes per line */
@@ -317,8 +338,12 @@ CURLcode Curl_ConnectHTTPProxyTunnel(struct connectdata *conn,
* to read, but when we use Curl_read() it may do so. Do confirm
* that this is still ok and then remove this comment!
*/
if(CURLE_OK != Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
&gotbytes))
res= Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
&gotbytes);
if(res< 0)
/* EWOULDBLOCK */
continue; /* go loop yourself */
else if(res)
keepon = FALSE;
else if(gotbytes <= 0) {
keepon = FALSE;
@@ -790,8 +815,6 @@ CURLcode Curl_http(struct connectdata *conn)
}
if(HTTPREQ_POST_FORM == data->set.httpreq) {
char contentType[256];
int linelength=0;
if(Curl_FormInit(&http->form, http->sendit)) {
failf(data, "Internal HTTP POST error!");
return CURLE_HTTP_POST_ERROR;
@@ -806,7 +829,7 @@ CURLcode Curl_http(struct connectdata *conn)
data->set.in = (FILE *)&http->form;
add_bufferf(req_buffer,
"Content-Length: %d\r\n", http->postsize-2);
"Content-Length: %d\r\n", http->postsize);
if(!checkheaders(data, "Expect:")) {
/* if not disabled explicitly we add a Expect: 100-continue
@@ -815,10 +838,19 @@ CURLcode Curl_http(struct connectdata *conn)
add_bufferf(req_buffer,
"Expect: 100-continue\r\n");
data->set.expect100header = TRUE;
}
if(!checkheaders(data, "Content-Type:")) {
/* Get Content-Type: line from Curl_FormReadOneLine, which happens
to always be the first line. We can know this for sure since
we always build the formpost linked list the same way! */
we always build the formpost linked list the same way!
The Content-Type header line also contains the MIME boundary
string etc why disabling this header is likely to not make things
work, but we support it anyway.
*/
char contentType[256];
int linelength=0;
linelength = Curl_FormReadOneLine (contentType,
sizeof(contentType),
1,
@@ -830,6 +862,9 @@ CURLcode Curl_http(struct connectdata *conn)
add_buffer(req_buffer, contentType, linelength);
}
/* make the request end in a true CRLF */
add_buffer(req_buffer, "\r\n", 2);
/* set upload size to the progress meter */
Curl_pgrsSetUploadSize(data, http->postsize);
@@ -910,12 +945,11 @@ CURLcode Curl_http(struct connectdata *conn)
add_buffer(req_buffer, "\r\n", 2);
add_buffer(req_buffer, data->set.postfields,
data->set.postfieldsize);
add_buffer(req_buffer, "\r\n", 2);
}
else {
add_bufferf(req_buffer,
"\r\n"
"%s\r\n",
"%s",
data->set.postfields );
}
}

View File

@@ -57,6 +57,10 @@
#include "ftp.h"
#include "sendf.h"
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
/* The last #include file should be: */
#ifdef MALLOCDEBUG
#include "memdebug.h"
@@ -193,10 +197,10 @@ krb4_auth(void *app_data, struct connectdata *conn)
int checksum;
u_int32_t cs;
struct krb4_data *d = app_data;
struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
char *host = conn->hostaddr->h_name;
ssize_t nread;
int l = sizeof(conn->local_addr);
struct SessionHandle *data = conn->data;
if(getsockname(conn->firstsocket,
(struct sockaddr *)LOCAL_ADDR, &l) < 0)
@@ -207,80 +211,76 @@ krb4_auth(void *app_data, struct connectdata *conn)
if(ret == KDC_PR_UNKNOWN)
ret = mk_auth(d, &adat, "rcmd", host, checksum);
if(ret) {
printf("%s\n", krb_get_err_text(ret));
Curl_infof(data, "%s\n", krb_get_err_text(ret));
return AUTH_CONTINUE;
}
#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
if (krb_get_config_bool("nat_in_use")) {
struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
struct in_addr natAddr;
if (krb_get_our_ip_for_realm(krb_realmofhost(host),
&natAddr) != KSUCCESS
&& krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
printf("Can't get address for realm %s\n",
krb_realmofhost(host));
Curl_infof(data, "Can't get address for realm %s\n",
krb_realmofhost(host));
else {
if (natAddr.s_addr != localaddr->sin_addr.s_addr) {
printf("Using NAT IP address (%s) for kerberos 4\n",
(char *)inet_ntoa(natAddr));
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
char *ip = (char *)inet_ntoa_r(natAddr, ntoa_buf, sizeof(ntoa_buf));
#else
char *ip = (char *)inet_ntoa(natAddr);
#endif
Curl_infof(data, "Using NAT IP address (%s) for kerberos 4\n", ip);
localaddr->sin_addr = natAddr;
/*
* This not the best place to do this, but it is here we know that
* (probably) NAT is in use! */
/*passivemode = 1;***/
/*printf("Setting: Passive mode on.\n");***/
}
}
}
#endif
/*printf("Local address is %s\n", inet_ntoa(localaddr->sin_addr));***/
/*printf("Remote address is %s\n", inet_ntoa(remoteaddr->sin_addr));***/
if(Curl_base64_encode(adat.dat, adat.length, &p) < 0) {
printf("Out of memory base64-encoding.\n");
Curl_failf(data, "Out of memory base64-encoding");
return AUTH_CONTINUE;
}
if(Curl_ftpsendf(conn, "ADAT %s", p))
return -2;
nread = Curl_GetFTPResponse(conn->data->state.buffer, conn, NULL);
nread = Curl_GetFTPResponse(data->state.buffer, conn, NULL);
if(nread < 0)
return -1;
free(p);
if(/*ret != COMPLETE*/conn->data->state.buffer[0] != '2'){
printf("Server didn't accept auth data.\n");
if(data->state.buffer[0] != '2'){
Curl_failf(data, "Server didn't accept auth data");
return AUTH_ERROR;
}
p = strstr(conn->data->state.buffer, "ADAT=");
if(!p){
printf("Remote host didn't send adat reply.\n");
p = strstr(data->state.buffer, "ADAT=");
if(!p) {
Curl_failf(data, "Remote host didn't send adat reply");
return AUTH_ERROR;
}
p += 5;
len = Curl_base64_decode(p, adat.dat);
if(len < 0){
printf("Failed to decode base64 from server.\n");
if(len < 0) {
Curl_failf(data, "Failed to decode base64 from server");
return AUTH_ERROR;
}
adat.length = len;
ret = krb_rd_safe(adat.dat, adat.length, &d->key,
(struct sockaddr_in *)hisctladdr,
(struct sockaddr_in *)myctladdr, &msg_data);
if(ret){
printf("Error reading reply from server: %s.\n",
krb_get_err_text(ret));
if(ret) {
Curl_failf(data, "Error reading reply from server: %s",
krb_get_err_text(ret));
return AUTH_ERROR;
}
krb_get_int(msg_data.app_data, &cs, 4, 0);
if(cs - checksum != 1){
printf("Bad checksum returned from server.\n");
if(cs - checksum != 1) {
Curl_failf(data, "Bad checksum returned from server");
return AUTH_ERROR;
}
return AUTH_OK;
@@ -321,15 +321,14 @@ void Curl_krb_kauth(struct connectdata *conn)
if(nread < 0)
return /*CURLE_OPERATION_TIMEOUTED*/;
if(/*ret != CONTINUE*/conn->data->state.buffer[0] != '3'){
if(conn->data->state.buffer[0] != '3'){
Curl_set_command_prot(conn, save);
/*code = -1;***/
return;
}
p = strstr(conn->data->state.buffer, "T=");
if(!p) {
printf("Bad reply from server.\n");
Curl_failf(conn->data, "Bad reply from server");
Curl_set_command_prot(conn, save);
return;
}
@@ -337,7 +336,7 @@ void Curl_krb_kauth(struct connectdata *conn)
p += 2;
tmp = Curl_base64_decode(p, &tkt.dat);
if(tmp < 0) {
printf("Failed to decode base64 in reply.\n");
Curl_failf(conn->data, "Failed to decode base64 in reply.\n");
Curl_set_command_prot(conn, save);
return;
}
@@ -346,7 +345,7 @@ void Curl_krb_kauth(struct connectdata *conn)
p = strstr(conn->data->state.buffer, "P=");
if(!p) {
printf("Bad reply from server.\n");
Curl_failf(conn->data, "Bad reply from server");
Curl_set_command_prot(conn, save);
return;
}

168
lib/llist.c Normal file
View File

@@ -0,0 +1,168 @@
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include "setup.h"
#include <string.h>
#include <stdlib.h>
#include "llist.h"
#ifdef MALLOCDEBUG
/* this must be the last include file */
#include "memdebug.h"
#endif
void
curl_llist_init(curl_llist *l, curl_llist_dtor dtor)
{
l->size = 0;
l->dtor = dtor;
l->head = NULL;
l->tail = NULL;
}
curl_llist *
curl_llist_alloc(curl_llist_dtor dtor)
{
curl_llist *list;
list = (curl_llist *)malloc(sizeof(curl_llist));
if(NULL == list)
return NULL;
curl_llist_init(list, dtor);
return list;
}
int
curl_llist_insert_next(curl_llist *list, curl_llist_element *e, const void *p)
{
curl_llist_element *ne;
ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
ne->ptr = (void *) p;
if (list->size == 0) {
list->head = ne;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = ne;
} else {
ne->next = e->next;
ne->prev = e;
if (e->next) {
e->next->prev = ne;
} else {
list->tail = ne;
}
e->next = ne;
}
++list->size;
return 1;
}
int
curl_llist_insert_prev(curl_llist *list, curl_llist_element *e, const void *p)
{
curl_llist_element *ne;
ne = (curl_llist_element *) malloc(sizeof(curl_llist_element));
ne->ptr = (void *) p;
if (list->size == 0) {
list->head = ne;
list->head->prev = NULL;
list->head->next = NULL;
list->tail = ne;
} else {
ne->next = e;
ne->prev = e->prev;
if (e->prev)
e->prev->next = ne;
else
list->head = ne;
e->prev = ne;
}
++list->size;
return 1;
}
int
curl_llist_remove(curl_llist *list, curl_llist_element *e, void *user)
{
if (e == NULL || list->size == 0)
return 1;
if (e == list->head) {
list->head = e->next;
if (list->head == NULL)
list->tail = NULL;
else
e->next->prev = NULL;
} else {
e->prev->next = e->next;
if (!e->next)
list->tail = e->prev;
else
e->next->prev = e->prev;
}
list->dtor(user, e->ptr);
free(e);
--list->size;
return 1;
}
int
curl_llist_remove_next(curl_llist *list, curl_llist_element *e, void *user)
{
return curl_llist_remove(list, e->next, user);
}
int
curl_llist_remove_prev(curl_llist *list, curl_llist_element *e, void *user)
{
return curl_llist_remove(list, e->prev, user);
}
size_t
curl_llist_count(curl_llist *list)
{
return list->size;
}
void
curl_llist_destroy(curl_llist *list, void *user)
{
while (list->size > 0) {
curl_llist_remove(list, CURL_LLIST_TAIL(list), user);
}
free(list);
list = NULL;
}

64
lib/llist.h Normal file
View File

@@ -0,0 +1,64 @@
#ifndef __LLIST_H
#define __LLIST_H
/*****************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2001, Daniel Stenberg, <daniel@haxx.se>, et al
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the MPL or the MIT/X-derivate
* licenses. You may pick one of these licenses.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
* $Id$
*****************************************************************************/
#include "setup.h"
#include <stddef.h>
typedef void (*curl_llist_dtor)(void *, void *);
typedef struct _curl_llist_element {
void *ptr;
struct _curl_llist_element *prev;
struct _curl_llist_element *next;
} curl_llist_element;
typedef struct _curl_llist {
curl_llist_element *head;
curl_llist_element *tail;
curl_llist_dtor dtor;
size_t size;
} curl_llist;
void curl_llist_init(curl_llist *, curl_llist_dtor);
curl_llist *curl_llist_alloc(curl_llist_dtor);
int curl_llist_insert_next(curl_llist *, curl_llist_element *, const void *);
int curl_llist_insert_prev(curl_llist *, curl_llist_element *, const void *);
int curl_llist_remove(curl_llist *, curl_llist_element *, void *);
int curl_llist_remove_next(curl_llist *, curl_llist_element *, void *);
size_t curl_llist_count(curl_llist *);
void curl_llist_destroy(curl_llist *, void *);
#define CURL_LLIST_HEAD(__l) ((__l)->head)
#define CURL_LLIST_TAIL(__l) ((__l)->tail)
#define CURL_LLIST_NEXT(__e) ((__e)->next)
#define CURL_LLIST_PREV(__e) ((__e)->prev)
#define CURL_LLIST_VALP(__e) ((__e)->ptr)
#define CURL_LLIST_IS_TAIL(__e) ((__e)->next ? 0 : 1)
#define CURL_LLIST_IS_HEAD(__e) ((__e)->prev ? 0 : 1)
#endif

View File

@@ -168,7 +168,10 @@ int curl_fclose(FILE *file, int line, const char *source)
source, line, file);
return res;
}
#else
#ifdef VMS
int VOID_VAR_MEMDEBUG;
#endif
#endif /* MALLOCDEBUG */
/*

View File

@@ -24,73 +24,11 @@
* - Max 128 parameters
* - No 'long double' support.
*
*************************************************************************
*
*
* 1998/01/10 (v2.8)
* Daniel
* - Updated version number.
* - Corrected a static non-zero prefixed width problem.
*
* 1998/11/17 - Daniel
* Added daprintf() and dvaprintf() for allocated printf() and vprintf().
* They return an allocated buffer with the result inside. The result must
* be free()ed!
*
* 1998/08/23 - breese
*
* Converted all non-printable (and non-whitespace) characters into
* their decimal ASCII value preceeded by a '\' character
* (this only applies to snprintf family so far)
*
* Added %S (which is the same as %#s)
*
* 1998/05/05 (v2.7)
*
* Fixed precision and width qualifiers (%.*s)
*
* Added support for snprintf()
*
* Quoting (%#s) is disabled for the (nil) pointer
*
* 1997/06/09 (v2.6)
*
* %#s means that the string will be quoted with "
* (I was getting tired of writing \"%s\" all the time)
*
* [ERR] for strings changed to (nil)
*
* v2.5
* - Added C++ support
* - Prepended all internal functions with dprintf_
* - Defined the booleans
*
* v2.4
* - Added dvsprintf(), dvfprintf() and dvprintf().
* - Made the formatting function available with the name _formatf() to enable
* other *printf()-inspired functions. (I considered adding a dmsprintf()
* that works like sprintf() but allocates the destination string and
* possibly enlarges it itself, but things like that should be done with the
* new _formatf() instead.)
*
* v2.3
* - Small modifications to make it compile nicely at both Daniel's and
* Bjorn's place.
*
* v2.2
* - Made it work with text to the right of the last %!
* - Introduced dprintf(), dsprintf() and dfprintf().
* - Float/double support enabled. This system is currently using the ordinary
* sprintf() function. NOTE that positional parameters, widths and precisions
* will still work like it should since the d-system takes care of that and
* passes that information re-formatted to the old sprintf().
*
* v2.1
* - Fixed space padding (i.e %d was extra padded previously)
* - long long output is supported
* - alternate output is done correct like in %#08x
*
****************************************************************************/
* If you ever want truly portable and good *printf() clones, the project that
* took on from here is named 'Trio' and you find more details on the trio web
* page at http://daniel.haxx.se/trio/
*/
#include "setup.h"
#include <sys/types.h>
@@ -100,6 +38,15 @@
#include <ctype.h>
#include <string.h>
#ifndef SIZEOF_LONG_LONG
/* prevents warnings on picky compilers */
#define SIZEOF_LONG_LONG 0
#endif
#ifndef SIZEOF_LONG_DOUBLE
#define SIZEOF_LONG_DOUBLE 0
#endif
/* The last #include file should be: */
#ifdef MALLOCDEBUG
#include "memdebug.h"
@@ -752,9 +699,8 @@ static int dprintf_formatf(
#if SIZEOF_LONG_LONG
if(p->flags & FLAGS_LONGLONG) {
/* long long */
num = p->data.lnum;
is_neg = num < 0;
num = is_neg ? (- num) : num;
is_neg = p->data.lnum < 0;
num = is_neg ? (- p->data.lnum) : p->data.lnum;
}
else
#endif
@@ -1191,7 +1137,7 @@ int main()
{
char buffer[129];
char *ptr;
#ifdef SIZEOF_LONG_LONG
#if SIZEOF_LONG_LONG>0
long long hullo;
dprintf("%3$12s %1$s %2$qd %4$d\n", "daniel", hullo, "stenberg", 65);
#endif

View File

@@ -22,10 +22,16 @@
*****************************************************************************/
#include "setup.h"
#include <stdlib.h>
#include <string.h>
#include <curl/curl.h>
#include "multi.h" /* will become <curl/multi.h> soon */
#include "urldata.h"
#include "transfer.h"
#include "url.h"
struct Curl_message {
/* the 'CURLMsg' is the part that is visible to the external user */
struct CURLMsg extmsg;
@@ -48,7 +54,9 @@ struct Curl_one_easy {
struct Curl_one_easy *next;
struct Curl_one_easy *prev;
CURL *easy_handle; /* this is the easy handle for this unit */
struct SessionHandle *easy_handle; /* the easy handle for this unit */
struct connectdata *easy_conn; /* the "unit's" connection */
CURLMstate state; /* the handle's state */
CURLcode result; /* previous result */
};
@@ -74,7 +82,8 @@ struct Curl_multi {
struct Curl_message *msgs;
/* amount of messages in the queue */
int num_msgs;
/* Hostname cache */
curl_hash *hostcache;
};
@@ -134,7 +143,7 @@ CURLMcode curl_multi_add_handle(CURLM *multi_handle,
/* increase the node-counter */
multi->num_easy++;
return CURLM_OK;
return CURLM_CALL_MULTI_PERFORM;
}
CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
@@ -190,23 +199,30 @@ CURLMcode curl_multi_fdset(CURLM *multi_handle,
and then we must make sure that is done. */
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
struct Curl_one_easy *easy;
int this_max_fd=-1;
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
*max_fd = -1; /* so far none! */
easy=multi->easy.next;
while(easy) {
switch(easy->state) {
case CURLM_STATE_INIT:
case CURLM_STATE_CONNECT:
case CURLM_STATE_DO:
case CURLM_STATE_DONE:
/* we want curl_multi_perform() to get called, but we don't have any
file descriptors to set */
default:
break;
case CURLM_STATE_PERFORM:
/* This should have a set of file descriptors for us to set. */
/* after the transfer is done, go DONE */
Curl_single_fdset(easy->easy_conn,
read_fd_set, write_fd_set,
exc_fd_set, &this_max_fd);
/* remember the maximum file descriptor */
if(this_max_fd > *max_fd)
*max_fd = this_max_fd;
break;
}
easy = easy->next; /* check next handle */
@@ -222,12 +238,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
bool done;
CURLMcode result=CURLM_OK;
*running_handles = 0; /* bump this once for every living handle */
if(!GOOD_MULTI_HANDLE(multi))
return CURLM_BAD_HANDLE;
easy=multi->easy.next;
while(easy) {
switch(easy->state) {
case CURLM_STATE_INIT:
/* init this transfer. */
@@ -239,8 +256,20 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
}
break;
case CURLM_STATE_CONNECT:
/* connect */
easy->result = Curl_connect(easy->easy_handle);
if (Curl_global_host_cache_use(easy->easy_handle)) {
easy->easy_handle->hostcache = Curl_global_host_cache_get();
}
else {
if (multi->hostcache == NULL) {
multi->hostcache = curl_hash_alloc(7, Curl_freeaddrinfo);
}
easy->easy_handle->hostcache = multi->hostcache;
}
/* Connect. We get a connection identifier filled in. */
easy->result = Curl_connect(easy->easy_handle, &easy->easy_conn);
/* after connect, go DO */
if(CURLE_OK == easy->result) {
easy->state = CURLM_STATE_DO;
@@ -249,15 +278,18 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
break;
case CURLM_STATE_DO:
/* Do the fetch or put request */
easy->result = Curl_do(easy->easy_handle);
easy->result = Curl_do(&easy->easy_conn);
/* after do, go PERFORM */
if(CURLE_OK == easy->result) {
easy->state = CURLM_STATE_PERFORM;
if(CURLE_OK == Curl_readwrite_init(easy->easy_conn)) {
easy->state = CURLM_STATE_PERFORM;
result = CURLM_CALL_MULTI_PERFORM;
}
}
break;
case CURLM_STATE_PERFORM:
/* read/write data if it is ready to do so */
easy->result = Curl_readwrite(easy->easy_handle, &done);
easy->result = Curl_readwrite(easy->easy_conn, &done);
/* hm, when we follow redirects, we may need to go back to the CONNECT
state */
/* after the transfer is done, go DONE */
@@ -265,11 +297,12 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
/* call this even if the readwrite function returned error */
easy->result = Curl_posttransfer(easy->easy_handle);
easy->state = CURLM_STATE_DONE;
result = CURLM_CALL_MULTI_PERFORM;
}
break;
case CURLM_STATE_DONE:
/* post-transfer command */
easy->result = Curl_done(easy->easy_handle);
easy->result = Curl_done(easy->easy_conn);
/* after we have DONE what we're supposed to do, go COMPLETED */
if(CURLE_OK == easy->result)
easy->state = CURLM_STATE_COMPLETED;
@@ -280,7 +313,10 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
/* This node should be delinked from the list now and we should post
an information message that we are complete. */
break;
default:
return CURLM_INTERNAL_ERROR;
}
if((CURLM_STATE_COMPLETED != easy->state) &&
(CURLE_OK != easy->result)) {
/*
@@ -289,10 +325,13 @@ CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
*/
easy->state = CURLM_STATE_COMPLETED;
}
else if(CURLM_STATE_COMPLETED != easy->state)
/* this one still lives! */
(*running_handles)++;
easy = easy->next; /* operate on next handle */
}
return CURLM_OK;
return result;
}
CURLMcode curl_multi_cleanup(CURLM *multi_handle)
@@ -300,7 +339,7 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
if(GOOD_MULTI_HANDLE(multi)) {
multi->type = 0; /* not good anymore */
curl_hash_destroy(multi->hostcache);
/* remove all easy handles */
free(multi);
@@ -313,3 +352,10 @@ CURLMcode curl_multi_cleanup(CURLM *multi_handle)
CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue);
/*
* local variables:
* eval: (load-file "../curl-mode.el")
* end:
* vim600: fdm=marker
* vim: et sw=2 ts=2 sts=2 tw=78
*/

View File

@@ -44,13 +44,17 @@
o Enable the application to select() on its own file descriptors and curl's
file descriptors simultaneous easily.
Example source using this interface: http://curl.haxx.se/dev/multi-app.c
Example sources using this interface is here: ../multi/
*/
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
#include <curl/types.h>
#if defined(WIN32) && !defined(__GNUC__) || defined(__MINGW32__)
#include <winsock.h>
#endif
#include <curl/curl.h>
typedef void CURLM;
@@ -60,6 +64,7 @@ typedef enum {
CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
CURLM_INTERNAL_ERROR, /* this is a libcurl bug */
CURLM_LAST
} CURLMcode;

View File

@@ -157,7 +157,7 @@ int Curl_parsenetrc(char *host,
}
else if(state_password) {
strncpy(password, tok, PASSWORDSIZE-1);
#if _NETRC_DEBUG
#ifdef _NETRC_DEBUG
printf("PASSWORD: %s\n", password);
#endif
state_password=0;

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
@@ -26,6 +26,8 @@
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <errno.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
@@ -160,7 +162,7 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
const char *fmt, ...)
{
struct SessionHandle *data = conn->data;
size_t bytes_written;
ssize_t bytes_written;
CURLcode result;
char *s;
va_list ap;
@@ -187,26 +189,32 @@ CURLcode Curl_sendf(int sockfd, struct connectdata *conn,
*/
CURLcode Curl_write(struct connectdata *conn, int sockfd,
void *mem, size_t len,
size_t *written)
ssize_t *written)
{
size_t bytes_written;
ssize_t bytes_written;
#ifdef USE_SSLEAY
/* SSL_write() is said to return 'int' while write() and send() returns
'size_t' */
int ssl_bytes;
if (conn->ssl.use) {
int loop=100; /* just a precaution to never loop endlessly */
while(loop--) {
ssl_bytes = SSL_write(conn->ssl.handle, mem, len);
if((0 >= ssl_bytes) ||
(SSL_ERROR_WANT_WRITE != SSL_get_error(conn->ssl.handle,
ssl_bytes) )) {
/* this converts from signed to unsigned... */
bytes_written = ssl_bytes;
break;
int err;
int rc = SSL_write(conn->ssl.handle, mem, len);
if(rc < 0) {
err = SSL_get_error(conn->ssl.handle, rc);
switch(err) {
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* this is basicly the EWOULDBLOCK equivalent */
*written = 0;
return CURLE_OK;
}
/* a true error */
failf(conn->data, "SSL_write() return error %d\n", err);
return CURLE_WRITE_ERROR;
}
bytes_written = rc;
}
else {
#endif
@@ -216,13 +224,27 @@ CURLcode Curl_write(struct connectdata *conn, int sockfd,
}
else
#endif /* KRB4 */
{
bytes_written = swrite(sockfd, mem, len);
}
if(-1 == bytes_written) {
#ifdef WIN32
if(WSAEWOULDBLOCK == GetLastError())
#else
if(EWOULDBLOCK == errno)
#endif
{
/* this is just a case of EWOULDBLOCK */
*written=0;
return CURLE_OK;
}
}
#ifdef USE_SSLEAY
}
#endif
*written = bytes_written;
return (bytes_written==len)?CURLE_OK:CURLE_WRITE_ERROR;
return (-1 != bytes_written)?CURLE_OK:CURLE_WRITE_ERROR;
}
/* client_write() sends data to the write callback(s)
@@ -266,26 +288,47 @@ CURLcode Curl_client_write(struct SessionHandle *data,
return CURLE_OK;
}
/*
* Internal read-from-socket function. This is meant to deal with plain
* sockets, SSL sockets and kerberos sockets.
*
* If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
* a regular CURLcode value.
*/
CURLcode Curl_read(struct connectdata *conn, int sockfd,
char *buf, size_t buffersize,
ssize_t *n)
int Curl_read(struct connectdata *conn,
int sockfd,
char *buf,
size_t buffersize,
ssize_t *n)
{
ssize_t nread;
#ifdef USE_SSLEAY
if (conn->ssl.use) {
int loop=100; /* just a precaution to never loop endlessly */
while(loop--) {
bool loop=TRUE;
int err;
do {
nread = SSL_read(conn->ssl.handle, buf, buffersize);
if((-1 != nread) ||
(SSL_ERROR_WANT_READ != SSL_get_error(conn->ssl.handle, nread) ))
if(nread >= 0)
/* successful read */
break;
}
err = SSL_get_error(conn->ssl.handle, nread);
switch(err) {
case SSL_ERROR_NONE: /* this is not an error */
case SSL_ERROR_ZERO_RETURN: /* no more data */
loop=0; /* get out of loop */
break;
case SSL_ERROR_WANT_READ:
case SSL_ERROR_WANT_WRITE:
/* if there's data pending, then we re-invoke SSL_read() */
break;
}
} while(loop);
if(loop && SSL_pending(conn->ssl.handle))
return -1; /* basicly EWOULDBLOCK */
}
else {
#endif
@@ -295,6 +338,16 @@ CURLcode Curl_read(struct connectdata *conn, int sockfd,
else
#endif
nread = sread (sockfd, buf, buffersize);
if(-1 == nread) {
#ifdef WIN32
if(WSAEWOULDBLOCK == GetLastError())
#else
if(EWOULDBLOCK == errno)
#endif
return -1;
}
#ifdef USE_SSLEAY
}
#endif /* USE_SSLEAY */

View File

@@ -45,12 +45,12 @@ CURLcode Curl_client_write(struct SessionHandle *data, int type, char *ptr,
size_t len);
/* internal read-function, does plain socket, SSL and krb4 */
CURLcode Curl_read(struct connectdata *conn, int sockfd,
char *buf, size_t buffersize,
ssize_t *n);
int Curl_read(struct connectdata *conn, int sockfd,
char *buf, size_t buffersize,
ssize_t *n);
/* internal write-function, does plain socket, SSL and krb4 */
CURLcode Curl_write(struct connectdata *conn, int sockfd,
void *mem, size_t len,
size_t *written);
ssize_t *written);
#endif

View File

@@ -34,25 +34,25 @@
#ifdef HAVE_CONFIG_H
#ifdef VMS
#include "../config-vms.h"
#include "config-vms.h"
#else
#include "../config.h" /* the configure script results */
#include "config.h" /* the configure script results */
#endif
#else
#ifdef WIN32
/* hand-modified win32 config.h! */
#include "../config-win32.h"
#include "config-win32.h"
#endif
#ifdef macintosh
/* hand-modified MacOS config.h! */
#include "../config-mac.h"
#include "config-mac.h"
#endif
#endif
#ifndef __cplusplus /* (rabe) */
typedef char bool;
typedef unsigned char bool;
#define typedef_bool
#endif /* (rabe) */
@@ -94,11 +94,12 @@ defined(HAVE_LIBSSL) && defined(HAVE_LIBCRYPTO)
#ifdef VMS
#include "../include/curl/stdcheaders.h"
#else
#include "curl/stdcheaders.h"
#include <curl/stdcheaders.h>
#endif
#else
#ifdef _AIX
#include "curl/stdcheaders.h"
#include <curl/stdcheaders.h>
#endif
#endif

View File

@@ -43,6 +43,12 @@
#include "memdebug.h"
#endif
#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
#define HAVE_SSL_GET1_SESSION 1
#else
#undef HAVE_SSL_GET1_SESSION
#endif
#if OPENSSL_VERSION_NUMBER >= 0x00904100L
#define HAVE_USERDATA_IN_PWD_CALLBACK 1
#else
@@ -74,10 +80,8 @@ static int passwd_callback(char *buf, int num, int verify
}
static
bool seed_enough(struct connectdata *conn, /* unused for now */
int nread)
bool seed_enough(int nread)
{
conn = NULL; /* to prevent compiler warnings */
#ifdef HAVE_RAND_STATUS
nread = 0; /* to prevent compiler warnings */
@@ -93,11 +97,10 @@ bool seed_enough(struct connectdata *conn, /* unused for now */
}
static
int random_the_seed(struct connectdata *conn)
int random_the_seed(struct SessionHandle *data)
{
char *buf = conn->data->state.buffer; /* point to the big buffer */
char *buf = data->state.buffer; /* point to the big buffer */
int nread=0;
struct SessionHandle *data=conn->data;
/* Q: should we add support for a random file name as a libcurl option?
A: Yes, it is here */
@@ -113,7 +116,7 @@ int random_the_seed(struct connectdata *conn)
nread += RAND_load_file((data->set.ssl.random_file?
data->set.ssl.random_file:RANDOM_FILE),
16384);
if(seed_enough(conn, nread))
if(seed_enough(nread))
return nread;
}
@@ -132,7 +135,7 @@ int random_the_seed(struct connectdata *conn)
int ret = RAND_egd(data->set.ssl.egdsocket?data->set.ssl.egdsocket:EGD_SOCKET);
if(-1 != ret) {
nread += ret;
if(seed_enough(conn, nread))
if(seed_enough(nread))
return nread;
}
}
@@ -164,11 +167,11 @@ int random_the_seed(struct connectdata *conn)
if ( buf[0] ) {
/* we got a file name to try */
nread += RAND_load_file(buf, 16384);
if(seed_enough(conn, nread))
if(seed_enough(nread))
return nread;
}
infof(conn->data, "Your connection is using a weak random seed!\n");
infof(data, "libcurl is now using a weak random seed!\n");
return nread;
}
@@ -357,6 +360,10 @@ int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
#ifdef USE_SSLEAY
/* "global" init done? */
static int init_ssl=0;
/* we have the "SSL is seeded" boolean global for the application to
prevent multiple time-consuming seedings in vain */
static bool ssl_seeded = FALSE;
#endif
/* Global init */
@@ -552,23 +559,39 @@ int Curl_SSL_Close_All(struct SessionHandle *data)
static int Store_SSL_Session(struct connectdata *conn)
{
SSL_SESSION *ssl_sessionid;
struct curl_ssl_session *store;
int i;
struct SessionHandle *data=conn->data; /* the mother of all structs */
struct curl_ssl_session *store = &data->state.session[0];
int oldest_age=data->state.session[0].age; /* zero if unused */
/* ask OpenSSL, say please */
#ifdef HAVE_SSL_GET1_SESSION
ssl_sessionid = SSL_get1_session(conn->ssl.handle);
/* SSL_get1_session() will increment the reference
count and the session will stay in memory until explicitly freed with
SSL_SESSION_free(3), regardless of its state. */
SSL_SESSION_free(3), regardless of its state.
This function was introduced in openssl 0.9.5a. */
#else
ssl_sessionid = SSL_get_session(conn->ssl.handle);
/* if SSL_get1_session() is unavailable, use SSL_get_session().
This is an inferior option because the session can be flushed
at any time by openssl. It is included only so curl compiles
under versions of openssl < 0.9.5a.
WARNING: How curl behaves if it's session is flushed is
untested.
*/
#endif
/* Now we should add the session ID and the host name to the cache, (remove
the oldest if necessary) */
/* find an empty slot for us, or find the oldest */
for(i=0; (i<data->set.ssl.numsessions) && data->state.session[i].sessionid; i++) {
for(i=1; (i<data->set.ssl.numsessions) &&
data->state.session[i].sessionid; i++) {
if(data->state.session[i].age < oldest_age) {
oldest_age = data->state.session[i].age;
store = &data->state.session[i];
@@ -655,8 +678,12 @@ Curl_SSLConnect(struct connectdata *conn)
/* mark this is being ssl enabled from here on out. */
conn->ssl.use = TRUE;
/* Make funny stuff to get random input */
random_the_seed(conn);
if(!ssl_seeded || data->set.ssl.random_file || data->set.ssl.egdsocket) {
/* Make funny stuff to get random input */
random_the_seed(data);
ssl_seeded = TRUE;
}
/* check to see if we've been told to use an explicit SSL/TLS version */
switch(data->set.ssl.version) {
@@ -736,8 +763,80 @@ Curl_SSLConnect(struct connectdata *conn)
}
/* pass the raw socket into the SSL layers */
SSL_set_fd (conn->ssl.handle, conn->firstsocket);
err = SSL_connect (conn->ssl.handle);
SSL_set_fd(conn->ssl.handle, conn->firstsocket);
do {
int what;
fd_set writefd;
fd_set readfd;
struct timeval interval;
long timeout_ms;
err = SSL_connect(conn->ssl.handle);
what = SSL_get_error(conn->ssl.handle, err);
FD_ZERO(&writefd);
FD_ZERO(&readfd);
if(SSL_ERROR_WANT_READ == what)
FD_SET(conn->firstsocket, &readfd);
else if(SSL_ERROR_WANT_WRITE == what)
FD_SET(conn->firstsocket, &writefd);
else
break; /* untreated error */
/* Find out if any timeout is set. If not, use 300 seconds.
Otherwise, figure out the most strict timeout of the two possible one
and then how much time that has elapsed to know how much time we
allow for the connect call */
if(data->set.timeout || data->set.connecttimeout) {
double has_passed;
/* Evaluate in milliseconds how much time that has passed */
has_passed = Curl_tvdiff(Curl_tvnow(), data->progress.start);
#ifndef min
#define min(a, b) ((a) < (b) ? (a) : (b))
#endif
/* get the most strict timeout of the ones converted to milliseconds */
if(data->set.timeout &&
(data->set.timeout>data->set.connecttimeout))
timeout_ms = data->set.timeout*1000;
else
timeout_ms = data->set.connecttimeout*1000;
/* subtract the passed time */
timeout_ms -= (long)has_passed;
if(timeout_ms < 0) {
/* a precaution, no need to continue if time already is up */
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEOUTED;
}
}
else
/* no particular time-out has been set */
timeout_ms=300000; /* milliseconds, default to five minutes */
interval.tv_sec = timeout_ms/1000;
timeout_ms -= interval.tv_sec*1000;
interval.tv_usec = timeout_ms*1000;
what = select(conn->firstsocket+1, &readfd, &writefd, NULL, &interval);
if(what > 0)
/* reabable or writable, go loop yourself */
continue;
else if(0 == what) {
/* timeout */
failf(data, "SSL connection timeout");
return CURLE_OPERATION_TIMEOUTED;
}
else
break; /* get out of loop */
} while(1);
/* 1 is fine
0 is "not successful but was shut down controlled"

View File

@@ -226,9 +226,9 @@ static void printoption(struct SessionHandle *data,
if (cmd == IAC)
{
if (TELCMD_OK(option))
printf("%s IAC %s\n", direction, TELCMD(option));
Curl_infof(data, "%s IAC %s\n", direction, TELCMD(option));
else
printf("%s IAC %d\n", direction, option);
Curl_infof(data, "%s IAC %d\n", direction, option);
}
else
{
@@ -244,12 +244,12 @@ static void printoption(struct SessionHandle *data,
opt = NULL;
if(opt)
printf("%s %s %s\n", direction, fmt, opt);
Curl_infof(data, "%s %s %s\n", direction, fmt, opt);
else
printf("%s %s %d\n", direction, fmt, option);
Curl_infof(data, "%s %s %d\n", direction, fmt, option);
}
else
printf("%s %d %d\n", direction, cmd, option);
Curl_infof(data, "%s %d %d\n", direction, cmd, option);
}
}
}
@@ -638,7 +638,7 @@ static void printsub(struct SessionHandle *data,
{
if (direction)
{
printf("%s IAC SB ", (direction == '<')? "RCVD":"SENT");
Curl_infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
if (length >= 3)
{
int j;
@@ -648,27 +648,27 @@ static void printsub(struct SessionHandle *data,
if (i != IAC || j != SE)
{
printf("(terminated by ");
Curl_infof(data, "(terminated by ");
if (TELOPT_OK(i))
printf("%s ", TELOPT(i));
Curl_infof(data, "%s ", TELOPT(i));
else if (TELCMD_OK(i))
printf("%s ", TELCMD(i));
Curl_infof(data, "%s ", TELCMD(i));
else
printf("%d ", i);
Curl_infof(data, "%d ", i);
if (TELOPT_OK(j))
printf("%s", TELOPT(j));
Curl_infof(data, "%s", TELOPT(j));
else if (TELCMD_OK(j))
printf("%s", TELCMD(j));
Curl_infof(data, "%s", TELCMD(j));
else
printf("%d", j);
printf(", not IAC SE!) ");
Curl_infof(data, "%d", j);
Curl_infof(data, ", not IAC SE!) ");
}
}
length -= 2;
}
if (length < 1)
{
printf("(Empty suboption?)");
Curl_infof(data, "(Empty suboption?)");
return;
}
@@ -677,28 +677,28 @@ static void printsub(struct SessionHandle *data,
case TELOPT_TTYPE:
case TELOPT_XDISPLOC:
case TELOPT_NEW_ENVIRON:
printf("%s", TELOPT(pointer[0]));
Curl_infof(data, "%s", TELOPT(pointer[0]));
break;
default:
printf("%s (unsupported)", TELOPT(pointer[0]));
Curl_infof(data, "%s (unsupported)", TELOPT(pointer[0]));
break;
}
}
else
printf("%d (unknown)", pointer[i]);
Curl_infof(data, "%d (unknown)", pointer[i]);
switch(pointer[1]) {
case TELQUAL_IS:
printf(" IS");
Curl_infof(data, " IS");
break;
case TELQUAL_SEND:
printf(" SEND");
Curl_infof(data, " SEND");
break;
case TELQUAL_INFO:
printf(" INFO/REPLY");
Curl_infof(data, " INFO/REPLY");
break;
case TELQUAL_NAME:
printf(" NAME");
Curl_infof(data, " NAME");
break;
}
@@ -706,21 +706,21 @@ static void printsub(struct SessionHandle *data,
case TELOPT_TTYPE:
case TELOPT_XDISPLOC:
pointer[length] = 0;
printf(" \"%s\"", &pointer[2]);
Curl_infof(data, " \"%s\"", &pointer[2]);
break;
case TELOPT_NEW_ENVIRON:
if(pointer[1] == TELQUAL_IS) {
printf(" ");
Curl_infof(data, " ");
for(i = 3;i < length;i++) {
switch(pointer[i]) {
case NEW_ENV_VAR:
printf(", ");
Curl_infof(data, ", ");
break;
case NEW_ENV_VALUE:
printf(" = ");
Curl_infof(data, " = ");
break;
default:
printf("%c", pointer[i]);
Curl_infof(data, "%c", pointer[i]);
break;
}
}
@@ -728,13 +728,13 @@ static void printsub(struct SessionHandle *data,
break;
default:
for (i = 2; i < length; i++)
printf(" %.2x", pointer[i]);
Curl_infof(data, " %.2x", pointer[i]);
break;
}
if (direction)
{
printf("\n");
Curl_infof(data, "\n");
}
}
}
@@ -1090,7 +1090,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
{
unsigned char outbuf[2];
int out_count = 0;
size_t bytes_written;
ssize_t bytes_written;
char *buffer = buf;
if(!ReadFile(stdin_handle, buf, 255, &nread, NULL)) {
@@ -1116,6 +1116,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
{
if(events.lNetworkEvents & FD_READ)
{
/* This reallu OUGHT to check its return code. */
Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
telrcv(conn, (unsigned char *)buf, nread);
@@ -1159,7 +1160,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
if(FD_ISSET(0, &readfd)) { /* read from stdin */
unsigned char outbuf[2];
int out_count = 0;
size_t bytes_written;
ssize_t bytes_written;
char *buffer = buf;
nread = read(0, buf, 255);
@@ -1176,6 +1177,7 @@ CURLcode Curl_telnet(struct connectdata *conn)
}
if(FD_ISSET(sockfd, &readfd)) {
/* This OUGHT to check the return code... */
Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
/* if we receive 0 or less here, the server closed the connection and

File diff suppressed because it is too large Load Diff

View File

@@ -7,7 +7,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,6 +24,17 @@
*****************************************************************************/
CURLcode Curl_perform(struct SessionHandle *data);
CURLcode Curl_pretransfer(struct SessionHandle *data);
CURLcode Curl_posttransfer(struct SessionHandle *data);
CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
void Curl_single_fdset(struct connectdata *conn,
fd_set *read_fd_set,
fd_set *write_fd_set,
fd_set *exc_fd_set,
int *max_fd);
CURLcode Curl_readwrite_init(struct connectdata *conn);
/* This sets up a forthcoming transfer */
CURLcode
Curl_Transfer (struct connectdata *data,

109
lib/url.c
View File

@@ -110,6 +110,10 @@
#include <curl/types.h>
#if defined(HAVE_INET_NTOA_R) && !defined(HAVE_INET_NTOA_R_DECL)
#include "inet_ntoa_r.h"
#endif
#define _MPRINTF_REPLACE /* use our functions only */
#include <curl/mprintf.h>
@@ -187,6 +191,9 @@ CURLcode Curl_close(struct SessionHandle *data)
/* free the connection cache */
free(data->state.connects);
if(data->info.contenttype)
free(data->info.contenttype);
free(data);
return CURLE_OK;
}
@@ -247,6 +254,8 @@ CURLcode Curl_open(struct SessionHandle **curl)
data->set.httpreq = HTTPREQ_GET; /* Default HTTP request */
data->set.ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
data->set.dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
/* make libcurl quiet by default: */
data->set.hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
data->progress.flags |= PGRS_HIDE;
@@ -280,6 +289,19 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
va_start(param, option);
switch(option) {
case CURLOPT_DNS_CACHE_TIMEOUT:
data->set.dns_cache_timeout = va_arg(param, int);
break;
case CURLOPT_DNS_USE_GLOBAL_CACHE:
{
int use_cache = va_arg(param, int);
if (use_cache) {
Curl_global_host_cache_init();
}
data->set.global_dns_cache = use_cache;
}
break;
case CURLOPT_SSL_CIPHER_LIST:
/* set a list of cipher we want to use in the SSL connection */
data->set.ssl.cipher_list = va_arg(param, char *);
@@ -540,8 +562,11 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
* Set a custom string to use as request
*/
data->set.customrequest = va_arg(param, char *);
if(data->set.customrequest)
data->set.httpreq = HTTPREQ_CUSTOM;
/* we don't set
data->set.httpreq = HTTPREQ_CUSTOM;
here, we continue as if we were using the already set type
and this just changes the actual request keyword */
break;
case CURLOPT_HTTPPOST:
/*
@@ -940,9 +965,6 @@ CURLcode Curl_disconnect(struct connectdata *conn)
if(conn->proto.generic)
free(conn->proto.generic);
if(conn->hostent_buf) /* host name info */
Curl_freeaddrinfo(conn->hostent_buf);
if(conn->newurl)
free(conn->newurl);
@@ -1217,8 +1239,7 @@ static CURLcode ConnectPlease(struct connectdata *conn)
}
static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata **in_connect,
bool allow_port) /* allow set.use_port? */
struct connectdata **in_connect)
{
char *tmp;
char *buf;
@@ -1228,6 +1249,9 @@ static CURLcode CreateConnection(struct SessionHandle *data,
struct connectdata *conn_temp;
char endbracket;
int urllen;
#ifdef HAVE_INET_NTOA_R
char ntoa_buf[64];
#endif
#ifdef HAVE_ALARM
unsigned int prev_alarm;
#endif
@@ -1268,7 +1292,6 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* and we setup a few fields in case we end up actually using this struct */
conn->data = data; /* remember our daddy */
conn->upload_bufsize = UPLOAD_BUFSIZE; /* default upload buffer size */
conn->firstsocket = -1; /* no file descriptor */
conn->secondarysocket = -1; /* no file descriptor */
conn->connectindex = -1; /* no index */
@@ -1617,7 +1640,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
*************************************************************/
if (strequal(conn->protostr, "HTTP")) {
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_HTTP;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTP;
conn->remote_port = PORT_HTTP;
conn->protocol |= PROT_HTTP;
conn->curl_do = Curl_http;
@@ -1627,7 +1651,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
else if (strequal(conn->protostr, "HTTPS")) {
#ifdef USE_SSLEAY
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_HTTPS;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_HTTPS;
conn->remote_port = PORT_HTTPS;
conn->protocol |= PROT_HTTP|PROT_HTTPS|PROT_SSL;
@@ -1642,7 +1667,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#endif /* !USE_SSLEAY */
}
else if (strequal(conn->protostr, "GOPHER")) {
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_GOPHER;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_GOPHER;
conn->remote_port = PORT_GOPHER;
/* Skip /<item-type>/ in path if present */
if (isdigit((int)conn->path[1])) {
@@ -1668,7 +1694,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
#endif /* !USE_SSLEAY */
}
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_FTP;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_FTP;
conn->remote_port = PORT_FTP;
conn->protocol |= PROT_FTP;
@@ -1723,21 +1750,24 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* telnet testing factory */
conn->protocol |= PROT_TELNET;
conn->port = (data->set.use_port && allow_port)?data->set.use_port: PORT_TELNET;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port: PORT_TELNET;
conn->remote_port = PORT_TELNET;
conn->curl_do = Curl_telnet;
conn->curl_done = Curl_telnet_done;
}
else if (strequal(conn->protostr, "DICT")) {
conn->protocol |= PROT_DICT;
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_DICT;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_DICT;
conn->remote_port = PORT_DICT;
conn->curl_do = Curl_dict;
conn->curl_done = NULL; /* no DICT-specific done */
}
else if (strequal(conn->protostr, "LDAP")) {
conn->protocol |= PROT_LDAP;
conn->port = (data->set.use_port && allow_port)?data->set.use_port:PORT_LDAP;
conn->port = (data->set.use_port && data->state.allow_port)?
data->set.use_port:PORT_LDAP;
conn->remote_port = PORT_LDAP;
conn->curl_do = Curl_ldap;
conn->curl_done = NULL; /* no LDAP-specific done */
@@ -1954,6 +1984,7 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* we need these pointers if we speak over a proxy */
conn->hostname = old_conn->gname;
conn->name = old_conn->name;
free(conn->path); /* free the previously allocated path pointer */
@@ -2060,8 +2091,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* Resolve target host right on */
if(!conn->hostaddr) {
/* it might already be set if reusing a connection */
conn->hostaddr = Curl_getaddrinfo(data, conn->name, conn->port,
&conn->hostent_buf);
conn->hostaddr = Curl_resolv(data, conn->name, conn->port,
&conn->hostent_buf);
}
if(!conn->hostaddr) {
failf(data, "Couldn't resolve host '%s'", conn->name);
@@ -2075,8 +2106,8 @@ static CURLcode CreateConnection(struct SessionHandle *data,
/* resolve proxy */
/* it might already be set if reusing a connection */
conn->hostaddr = Curl_getaddrinfo(data, conn->proxyhost, conn->port,
&conn->hostent_buf);
conn->hostaddr = Curl_resolv(data, conn->proxyhost, conn->port,
&conn->hostent_buf);
if(!conn->hostaddr) {
failf(data, "Couldn't resolve proxy '%s'", conn->proxyhost);
@@ -2211,7 +2242,12 @@ static CURLcode CreateConnection(struct SessionHandle *data,
struct in_addr in;
(void) memcpy(&in.s_addr, &conn->serv_addr.sin_addr, sizeof (in.s_addr));
infof(data, "Connected to %s (%s)\n", conn->hostaddr->h_name,
inet_ntoa(in));
#if defined(HAVE_INET_NTOA_R)
inet_ntoa_r(in, ntoa_buf, sizeof(ntoa_buf))
#else
inet_ntoa(in)
#endif
);
}
#endif
@@ -2231,14 +2267,13 @@ static CURLcode CreateConnection(struct SessionHandle *data,
}
CURLcode Curl_connect(struct SessionHandle *data,
struct connectdata **in_connect,
bool allow_port)
struct connectdata **in_connect)
{
CURLcode code;
struct connectdata *conn;
/* call the stuff that needs to be called */
code = CreateConnection(data, in_connect, allow_port);
code = CreateConnection(data, in_connect);
if(CURLE_OK != code) {
/* We're not allowed to return failure with memory left allocated
@@ -2294,14 +2329,38 @@ CURLcode Curl_done(struct connectdata *conn)
return result;
}
CURLcode Curl_do(struct connectdata *conn)
CURLcode Curl_do(struct connectdata **connp)
{
CURLcode result=CURLE_OK;
struct connectdata *conn = *connp;
struct SessionHandle *data=conn->data;
if(conn->curl_do)
if(conn->curl_do) {
/* generic protocol-specific function pointer set in curl_connect() */
result = conn->curl_do(conn);
/* This was formerly done in transfer.c, but we better do it here */
if((CURLE_WRITE_ERROR == result) && conn->bits.reuse) {
/* This was a re-use of a connection and we got a write error in the
* DO-phase. Then we DISCONNECT this connection and have another attempt
* to CONNECT and then DO again! The retry cannot possibly find another
* connection to re-use, since we only keep one possible connection for
* each. */
infof(data, "Re-used connection seems dead, get a new one\n");
conn->bits.close = TRUE; /* enforce close of this connetion */
result = Curl_done(conn); /* we are so done with this */
if(CURLE_OK == result) {
/* Now, redo the connect and get a new connection */
result = Curl_connect(data, connp);
if(CURLE_OK == result)
/* ... finally back to actually retry the DO phase */
result = conn->curl_do(*connp);
}
}
}
return result;
}

View File

@@ -7,7 +7,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.
@@ -29,11 +29,9 @@
CURLcode Curl_open(struct SessionHandle **curl);
CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...);
CURLcode Curl_close(struct SessionHandle *data); /* the opposite of curl_open() */
CURLcode Curl_connect(struct SessionHandle *,
struct connectdata **,
bool allow_port);
CURLcode Curl_do(struct connectdata *);
CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
CURLcode Curl_connect(struct SessionHandle *, struct connectdata **);
CURLcode Curl_do(struct connectdata **);
CURLcode Curl_done(struct connectdata *);
CURLcode Curl_disconnect(struct connectdata *);

View File

@@ -27,6 +27,7 @@
#include "setup.h"
#include "hostip.h"
#include "hash.h"
#define PORT_FTP 21
#define PORT_TELNET 23
@@ -82,12 +83,7 @@
#include "http_chunks.h" /* for the structs and enum stuff */
/* Download buffer size, keep it fairly big for speed reasons */
#define BUFSIZE (1024*50)
/* Defaul upload buffer size, keep it smallish to get faster progress meter
updates. This is just default, it is dynamic and adjusts to the upload
speed. */
#define UPLOAD_BUFSIZE (1024*2)
#define BUFSIZE (1024*20)
/* Initial size of the buffer to store headers in, it'll be enlarged in case
of need. */
@@ -211,6 +207,58 @@ struct ConnectBits {
complete */
};
/*
* This struct is all the previously local variables from Curl_perform() moved
* to struct to allow the function to return and get re-invoked better without
* losing state.
*/
struct Curl_transfer_keeper {
int bytecount; /* total number of bytes read */
int writebytecount; /* number of bytes written */
long contentlength; /* size of incoming data */
struct timeval start; /* transfer started at this time */
struct timeval now; /* current time */
bool header; /* incoming data has HTTP header */
int headerline; /* counts header lines to better track the
first one */
char *hbufp; /* points at *end* of header line */
int hbuflen;
char *str; /* within buf */
char *str_start; /* within buf */
char *end_ptr; /* within buf */
char *p; /* within headerbuff */
bool content_range; /* set TRUE if Content-Range: was found */
int offset; /* possible resume offset read from the
Content-Range: header */
int httpcode; /* error code from the 'HTTP/1.? XXX' line */
int httpversion; /* the HTTP version*10 */
bool write_after_100_header; /* should we enable the write after
we received a 100-continue/timeout
or directly */
/* for the low speed checks: */
time_t timeofdoc;
long bodywrites;
int writetype;
/* the highest fd we use + 1 */
struct SessionHandle *data;
struct connectdata *conn;
char *buf;
char *uploadbuf;
int maxfd;
/* the file descriptors to play with */
fd_set readfd;
fd_set writefd;
fd_set rkeepfd;
fd_set wkeepfd;
int keepon;
};
/*
* The connectdata struct contains all fields and variables that should be
* unique for an entire connection.
@@ -264,10 +312,6 @@ struct connectdata {
struct timeval created; /* creation time */
int firstsocket; /* the main socket to use */
int secondarysocket; /* for i.e ftp transfers */
long upload_bufsize; /* adjust as you see fit, never bigger than BUFSIZE
never smaller than UPLOAD_BUFSIZE */
long maxdownload; /* in bytes, the maximum amount of data to fetch, 0
means unlimited */
@@ -355,6 +399,18 @@ struct connectdata {
void *generic;
} proto;
/* This struct is inited when needed */
struct Curl_transfer_keeper keep;
/* 'upload_present' is used to keep a byte counter of how much data there is
still left in the buffer, aimed for upload. */
int upload_present;
/* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
buffer, so the next read should read from where this pointer points to,
and the 'upload_present' contains the number of bytes available at this
position */
char *upload_fromhere;
};
/*
@@ -367,6 +423,8 @@ struct PureInfo {
the time was unretrievable */
long header_size; /* size of read header(s) in bytes */
long request_size; /* the amount of bytes sent in the request(s) */
char *contenttype; /* the content type of the object */
};
@@ -441,8 +499,8 @@ struct UrlState {
char *headerbuff; /* allocated buffer to store headers in */
int headersize; /* size of the allocation */
char buffer[BUFSIZE+1]; /* buffer with size BUFSIZE */
char buffer[BUFSIZE+1]; /* download buffer */
char uploadbuffer[BUFSIZE+1]; /* upload buffer */
double current_speed; /* the ProgressShow() funcion sets this */
bool this_is_a_follow; /* this is a followed Location: request */
@@ -460,6 +518,13 @@ struct UrlState {
bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
This must be set to FALSE every time _easy_perform() is
called. */
#ifdef HAVE_SIGNAL
/* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
void (*prev_signal)(int sig);
#endif
bool allow_port; /* Is set.use_port allowed to take effect or not. This
is always set TRUE when curl_easy_perform() is called. */
};
@@ -556,6 +621,8 @@ struct UserDefined {
char *krb4_level; /* what security level */
struct ssl_config_data ssl; /* user defined SSL stuff */
int dns_cache_timeout; /* DNS cache timeout */
/* Here follows boolean settings that define how to behave during
this session. They are STATIC, set by libcurl users or at least initially
and they don't change during operations. */
@@ -569,7 +636,6 @@ struct UserDefined {
bool hide_progress;
bool http_fail_on_error;
bool http_follow_location;
bool include_header;
#define http_include_header include_header /* former name */
@@ -585,6 +651,8 @@ struct UserDefined {
bool reuse_fresh; /* do not re-use an existing connection */
bool expect100header; /* TRUE if we added Expect: 100-continue */
bool ftp_use_epsv; /* if EPSV is to be attempted or not */
bool global_dns_cache;
};
/*
@@ -599,6 +667,7 @@ struct UserDefined {
* 'struct urlstate' instead. */
struct SessionHandle {
curl_hash *hostcache;
struct UserDefined set; /* values set by the libcurl user */
struct DynamicStatic change; /* possibly modified userdefined data */

View File

@@ -5,7 +5,7 @@
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 2000, Daniel Stenberg, <daniel@haxx.se>, et al.
* Copyright (C) 2002, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* In order to be useful for every potential user, curl and libcurl are
* dual-licensed under the MPL and the MIT/X-derivate licenses.
@@ -38,20 +38,28 @@ char *curl_version(void)
#ifdef USE_SSLEAY
#if (SSLEAY_VERSION_NUMBER >= 0x906000)
#if (SSLEAY_VERSION_NUMBER >= 0x905000)
{
char sub[2];
unsigned long ssleay_value;
sub[1]='\0';
if(SSLEAY_VERSION_NUMBER&0xff0) {
sub[0]=((SSLEAY_VERSION_NUMBER>>4)&0xff) + 'a' -1;
}
else
ssleay_value=SSLeay();
if(ssleay_value < 0x906000) {
ssleay_value=SSLEAY_VERSION_NUMBER;
sub[0]='\0';
}
else {
if(ssleay_value&0xff0) {
sub[0]=((ssleay_value>>4)&0xff) + 'a' -1;
}
else
sub[0]='\0';
}
sprintf(ptr, " (OpenSSL %lx.%lx.%lx%s)",
(SSLEAY_VERSION_NUMBER>>28)&0xf,
(SSLEAY_VERSION_NUMBER>>20)&0xff,
(SSLEAY_VERSION_NUMBER>>12)&0xff,
(ssleay_value>>28)&0xf,
(ssleay_value>>20)&0xff,
(ssleay_value>>12)&0xff,
sub);
}

21
multi/Makefile.am Normal file
View File

@@ -0,0 +1,21 @@
#
# $Id$
#
INCLUDES = -I$(top_srcdir)/include
noinst_PROGRAMS = app single double
app_SOURCES = app.c
app_LDADD = ../lib/libcurl.la
app_DEPENDENCIES = ../lib/libcurl.la
single_SOURCES = single.c
single_LDADD = ../lib/libcurl.la
single_DEPENDENCIES = ../lib/libcurl.la
double_SOURCES = double.c
double_LDADD = ../lib/libcurl.la
double_DEPENDENCIES = ../lib/libcurl.la
AUTOMAKE_OPTIONS = foreign no-dependencies

92
multi/app.c Normal file
View File

@@ -0,0 +1,92 @@
/*
* This is an example application source code using the multi interface.
*/
#include <stdio.h>
#include <string.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* To start with, we include the header from the lib directory. This should
later of course be moved to the proper include dir. */
#include "../lib/multi.h"
/*
* Download a HTTP file and upload an FTP file simultaneously.
*/
int main(int argc, char **argv)
{
CURL *http_handle;
CURL *ftp_handle;
CURLM *multi_handle;
int still_running; /* keep number of running handles */
http_handle = curl_easy_init();
ftp_handle = curl_easy_init();
/* set the options (I left out a few, you'll get the point anyway) */
curl_easy_setopt(http_handle, CURLOPT_URL, "http://website.com");
curl_easy_setopt(ftp_handle, CURLOPT_URL, "ftp://ftpsite.com");
curl_easy_setopt(ftp_handle, CURLOPT_UPLOAD, TRUE);
/* init a multi stack */
multi_handle = curl_multi_init();
/* add the individual transfers */
curl_multi_add_handle(multi_handle, http_handle);
curl_multi_add_handle(multi_handle, ftp_handle);
/* we start some action by calling perform right away */
while(CURLM_CALL_MULTI_PERFORM ==
curl_multi_perform(multi_handle, &still_running));
while(still_running) {
struct timeval timeout;
int rc; /* select() return code */
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a suitable timeout to play around with */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* get file descriptors from the transfers */
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
/* select error */
break;
case 0:
/* timeout, do something else */
break;
default:
/* one or more of curl's file descriptors say there's data to read
or write */
curl_multi_perform(multi_handle, &still_running);
break;
}
}
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(http_handle);
curl_easy_cleanup(ftp_handle);
return 0;
}

87
multi/double.c Normal file
View File

@@ -0,0 +1,87 @@
/*
* This is a simple example using the multi interface.
*/
#include <stdio.h>
#include <string.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* To start with, we include the header from the lib directory. This should
later of course be moved to the proper include dir. */
#include "../lib/multi.h"
/*
* Simply download two HTTP files!
*/
int main(int argc, char **argv)
{
CURL *http_handle;
CURL *http_handle2;
CURLM *multi_handle;
int still_running; /* keep number of running handles */
http_handle = curl_easy_init();
http_handle2 = curl_easy_init();
/* set options */
curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.haxx.se/");
/* set options */
curl_easy_setopt(http_handle2, CURLOPT_URL, "http://localhost/");
/* init a multi stack */
multi_handle = curl_multi_init();
/* add the individual transfers */
curl_multi_add_handle(multi_handle, http_handle);
curl_multi_add_handle(multi_handle, http_handle2);
/* we start some action by calling perform right away */
while(CURLM_CALL_MULTI_PERFORM ==
curl_multi_perform(multi_handle, &still_running));
while(still_running) {
struct timeval timeout;
int rc; /* select() return code */
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a suitable timeout to play around with */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* get file descriptors from the transfers */
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
/* select error */
break;
case 0:
default:
/* timeout or readable/writable sockets */
curl_multi_perform(multi_handle, &still_running);
break;
}
}
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(http_handle);
curl_easy_cleanup(http_handle2);
return 0;
}

80
multi/single.c Normal file
View File

@@ -0,0 +1,80 @@
/*
* This is a very simple example using the multi interface.
*/
#include <stdio.h>
#include <string.h>
/* somewhat unix-specific */
#include <sys/time.h>
#include <unistd.h>
/* To start with, we include the header from the lib directory. This should
later of course be moved to the proper include dir. */
#include "../lib/multi.h"
/*
* Simply download a HTTP file.
*/
int main(int argc, char **argv)
{
CURL *http_handle;
CURLM *multi_handle;
int still_running; /* keep number of running handles */
http_handle = curl_easy_init();
/* set the options (I left out a few, you'll get the point anyway) */
curl_easy_setopt(http_handle, CURLOPT_URL, "http://www.haxx.se/");
/* init a multi stack */
multi_handle = curl_multi_init();
/* add the individual transfers */
curl_multi_add_handle(multi_handle, http_handle);
/* we start some action by calling perform right away */
while(CURLM_CALL_MULTI_PERFORM ==
curl_multi_perform(multi_handle, &still_running));
while(still_running) {
struct timeval timeout;
int rc; /* select() return code */
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
int maxfd;
FD_ZERO(&fdread);
FD_ZERO(&fdwrite);
FD_ZERO(&fdexcep);
/* set a suitable timeout to play around with */
timeout.tv_sec = 1;
timeout.tv_usec = 0;
/* get file descriptors from the transfers */
curl_multi_fdset(multi_handle, &fdread, &fdwrite, &fdexcep, &maxfd);
rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
switch(rc) {
case -1:
/* select error */
break;
case 0:
default:
/* timeout or readable/writable sockets */
curl_multi_perform(multi_handle, &still_running);
break;
}
}
curl_multi_cleanup(multi_handle);
curl_easy_cleanup(http_handle);
return 0;
}

View File

@@ -2,25 +2,26 @@
# $Id$
#
# Some flags needed when trying to cause warnings ;-)
# CFLAGS = -g -DMALLOCDEBUG # -Wall -pedantic
#CPPFLAGS = -DGLOBURL -DCURL_SEPARATORS
AUTOMAKE_OPTIONS = foreign nostdinc
INCLUDES = -I$(top_srcdir)/include
bin_PROGRAMS = curl #memtest
noinst_HEADERS = setup.h \
config-win32.h \
config-mac.h \
urlglob.h \
version.h \
writeout.h
#memtest_SOURCES = memtest.c
#memtest_LDADD = $(top_srcdir)/lib/libcurl.la
curl_SOURCES = main.c hugehelp.c urlglob.c writeout.c
curl_SOURCES = main.c hugehelp.c urlglob.c writeout.c setup.h \
config-win32.h \
config-mac.h \
config-vms.h \
urlglob.h \
version.h \
writeout.h \
config-win32.h \
config-mac.h \
config-vms.h
curl_LDADD = ../lib/libcurl.la
curl_DEPENDENCIES = ../lib/libcurl.la
BUILT_SOURCES = hugehelp.c
@@ -34,8 +35,6 @@ EXTRA_DIST = mkhelp.pl curlmsg.msg \
macos/src/curl_GUSIConfig.cpp \
macos/src/macos_main.cpp
AUTOMAKE_OPTIONS = foreign no-dependencies
MANPAGE=$(top_srcdir)/docs/curl.1
README=$(top_srcdir)/docs/MANUAL
MKHELP=$(top_srcdir)/src/mkhelp.pl

View File

@@ -1,10 +1,13 @@
########################################################
## Makefile for building curl.exe with MSVC6
## Use: nmake -f makefile.vc6 [release | debug]
## Use: nmake -f makefile.vc6 [release | debug] [CFG=release-ssl]
## (default is release)
## "nmake -f makefile.vc6 CFG=release-ssl" statically links OpenSSL
## into curl.exe producing a standalone SSL-enabled executable.
##
## Comments to: Troy Engel <tengel@sonic.net>
## Updated by: Craig Davison <cd@securityfocus.com>
## release-ssl added by Miklos Nemeth <mnemeth@kfkisystems.com>
PROGRAM_NAME = curl.exe

21
src/config-vms.h Normal file
View File

@@ -0,0 +1,21 @@
/* src/config.h. Generated automatically by configure. */
/* Define cpu-machine-OS */
#define OS "ALPHA-COMPAQ-VMS"
/* Define if you have the <unistd.h> header file. */
#define HAVE_UNISTD_H 1
/* Define if you have the <io.h> header file. */
#undef HAVE_IO_H
/* Define if you have strdup() */
#define HAVE_STRDUP 1
/* Define if you have utime() */
#undef HAVE_UTIME
/* Define if you have the <utime.h> header file */
#undef HAVE_UTIME_H
/* Define if you have thhe <sys/utime.h> header file */
#undef HAVE_SYS_UTIME_H

View File

@@ -1176,8 +1176,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
config->postfields=postdata;
}
/* if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;*/
if(SetHTTPrequest(HTTPREQ_SIMPLEPOST, &config->httpreq))
return PARAM_BAD_USE;
break;
case 'D':
/* dump-header to given file name */
@@ -1450,10 +1450,8 @@ static ParameterError getparameter(char *flag, /* f or -long-flag */
GetStr(&config->proxy, nextarg);
break;
case 'X':
/* HTTP request */
/* set custom request */
GetStr(&config->customrequest, nextarg);
if(SetHTTPrequest(HTTPREQ_CUSTOM, &config->httpreq))
return PARAM_BAD_USE;
break;
case 'y':
/* low speed time */

View File

@@ -32,7 +32,11 @@
#endif
#ifdef HAVE_CONFIG_H
#ifdef VMS
#include "config-vms.h"
#else
#include "config.h" /* the configure script results */
#endif
#else
#ifdef WIN32
/* include the hand-modified win32 adjusted config.h! */

View File

@@ -1,3 +1,3 @@
#define CURL_NAME "curl"
#define CURL_VERSION "7.9.2"
#define CURL_VERSION "7.9.5-pre4"
#define CURL_ID CURL_NAME " " CURL_VERSION " (" OS ") "

View File

@@ -46,6 +46,7 @@ typedef enum {
VAR_HEADER_SIZE,
VAR_REQUEST_SIZE,
VAR_EFFECTIVE_URL,
VAR_CONTENT_TYPE,
VAR_NUM_OF_VARS /* must be the last */
} replaceid;
@@ -69,6 +70,7 @@ static struct variable replacements[]={
{"size_upload", VAR_SIZE_UPLOAD},
{"speed_download", VAR_SPEED_DOWNLOAD},
{"speed_upload", VAR_SPEED_UPLOAD},
{"content_type", VAR_CONTENT_TYPE},
{NULL, 0}
};
@@ -165,6 +167,11 @@ void ourWriteOut(CURL *curl, char *writeinfo)
curl_easy_getinfo(curl, CURLINFO_SPEED_UPLOAD, &doubleinfo))
fprintf(stream, "%.3f", doubleinfo);
break;
case VAR_CONTENT_TYPE:
if(CURLE_OK ==
curl_easy_getinfo(curl, CURLINFO_CONTENT_TYPE, &stringp))
fputs(stringp, stream);
break;
default:
break;
}

View File

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

View File

@@ -2,7 +2,7 @@ EXTRA_DIST = ftpserver.pl httpserver.pl httpsserver.pl runtests.pl \
ftpsserver.pl stunnel.pm getpart.pm FILEFORMAT README \
stunnel.pem
SUBDIRS = data
SUBDIRS = data server
PERLFLAGS = -I$(srcdir)
@@ -12,11 +12,11 @@ install:
curl:
@(cd ..; make)
test:
test: server/sws
@cd data && exec $(MAKE) test
srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl
quiet-test:
quiet-test: server/sws
@cd data && exec $(MAKE) test
srcdir=$(srcdir) $(PERL) $(PERLFLAGS) $(srcdir)/runtests.pl -s -a
@@ -24,3 +24,5 @@ clean:
rm -rf log
find . -name "*~" | xargs rm -f
server/sws:
cd server; make sws

View File

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

View File

@@ -26,7 +26,7 @@ simple HTTP GET
<command>
http://%HOSTIP:%HOSTPORT/1
</command>
</test>
</client>
#
# Verify data after the test has been "shot"

View File

@@ -10,7 +10,7 @@
use curl with multiple request methods
</name>
<command>
-I -X FOOO localhost
-I -d FOOO localhost
</command>
</test>

View File

@@ -28,7 +28,7 @@ HTTP POST with user and password
<strip>
^User-Agent:.*
</strip>
<protocol>
<protocol nonewline=yes>
POST /3 HTTP/1.1
Authorization: Basic ZmFrZTotdXNlcg==
Host: 127.0.0.1:8999

49
tests/data/test38 Normal file
View File

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

View File

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

View File

@@ -1,15 +1,6 @@
#!/usr/bin/perl
use Socket;
use Carp;
use FileHandle;
#!/usr/bin/env perl
#use strict;
require "getpart.pm";
sub spawn; # forward declaration
sub logmsg { #print "$0 $$: @_ at ", scalar localtime, "\n"
}
use strict;
my $verbose=0; # set to 1 for debugging
@@ -23,204 +14,4 @@ do {
}
} while(shift @ARGV);
my $proto = getprotobyname('tcp') || 6;
socket(Server, PF_INET, SOCK_STREAM, $proto)|| die "socket: $!";
setsockopt(Server, SOL_SOCKET, SO_REUSEADDR,
pack("l", 1)) || die "setsockopt: $!";
bind(Server, sockaddr_in($port, INADDR_ANY))|| die "bind: $!";
listen(Server,SOMAXCONN) || die "listen: $!";
if($verbose) {
print "HTTP server started on port $port\n";
}
open(PID, ">.http.pid");
print PID $$;
close(PID);
my $PID=$$;
my $waitedpid = 0;
my $paddr;
sub REAPER {
$waitedpid = wait;
$SIG{CHLD} = \&REAPER; # loathe sysV
logmsg "reaped $waitedpid" . ($? ? " with exit $?" : '');
}
sub performcmd {
my @cmd = @_;
for(@cmd) {
if($_ =~ /^ *wait *(\d*)/) {
# instructed to sleep!
sleep($1);
}
}
}
$SIG{CHLD} = \&REAPER;
for ( $waitedpid = 0;
($paddr = accept(Client,Server)) || $waitedpid;
$waitedpid = 0, close Client)
{
next if $waitedpid and not $paddr;
my($port,$iaddr) = sockaddr_in($paddr);
my $name = gethostbyaddr($iaddr,AF_INET);
logmsg "connection from $name [", inet_ntoa($iaddr), "] at port $port";
# this code is forked and run
spawn sub {
my ($request, $path, $ver, $left, $cl);
my @headers;
while(<STDIN>) {
if($_ =~ /([A-Z]*) (.*) HTTP\/1.(\d)/) {
$request=$1;
$path=$2;
$ver=$3;
}
elsif($_ =~ /^Content-Length: (\d*)/) {
$cl=$1;
}
if($verbose) {
print STDERR "IN: $_";
}
push @headers, $_;
if($left > 0) {
$left -= length($_);
if($left == 0) {
$left = -1; # just to force a loop break here
}
}
# print STDERR "RCV ($left): $_";
if(!$left &&
($_ eq "\r\n") or ($_ eq "")) {
if($request =~ /^(POST|PUT)$/) {
$left=$cl;
}
elsif($request =~ /^CONNECT$/) {
if($verbose) {
print STDERR "We're emulating a SSL proxy!\n";
}
$left = -1;
}
else {
$left = -1; # force abort
}
}
if($left < 0) {
last;
}
}
if($request =~ /^CONNECT$/) {
# ssl proxy mode
print "HTTP/1.1 400 WE CANNOT ROOL NOW\r\n",
"Server: bahoooba\r\n\r\n";
exit;
}
elsif($path =~ /verifiedserver/) {
# this is a hard-coded query-string for the test script
# to verify that this is the server actually running!
print "HTTP/1.1 999 WE ROOLZ: $PID\r\n";
exit;
}
else {
#
# we always start the path with a number, this is the
# test number that this server will use to know what
# contents to pass back to the client
#
my $testnum;
if($path =~ /.*\/(\d*)/) {
$testnum=$1;
}
else {
$testnum=0;
}
open(INPUT, ">>log/server.input");
binmode(INPUT,":raw"); # this makes it work better on cygwin
for(@headers) {
print INPUT $_;
}
close(INPUT);
if(0 == $testnum ) {
print "HTTP/1.1 200 OK\r\n",
"header: yes\r\n",
"\r\n",
"You must enter a test number to get good data back\r\n";
}
else {
my $part="";
if($testnum > 10000) {
$part = $testnum % 10000;
$testnum = sprintf("%d", $testnum/10000);
}
if($verbose) {
print STDERR "OUT: sending reply $testnum (part $part)\n";
}
loadtest("data/test$testnum");
my @cmd = getpart("reply", "cmd");
performcmd(@cmd);
# flush data:
$| = 1;
# send a custom reply to the client
my @data = getpart("reply", "data$part");
for(@data) {
print $_;
if($verbose) {
print STDERR "OUT: $_";
}
}
my @postcmd = getpart("reply", "postcmd");
performcmd(@postcmd);
}
}
# print "Hello there, $name, it's now ", scalar localtime, "\r\n";
};
}
sub spawn {
my $coderef = shift;
unless (@_ == 0 && $coderef && ref($coderef) eq 'CODE') {
confess "usage: spawn CODEREF";
}
my $pid;
if (!defined($pid = fork)) {
logmsg "cannot fork: $!";
return;
} elsif ($pid) {
logmsg "begat $pid";
return; # I'm the parent
}
# else I'm the child -- go spawn
open(STDIN, "<&Client") || die "can't dup client to stdin";
open(STDOUT, ">&Client") || die "can't dup client to stdout";
## open(STDERR, ">&STDOUT") || die "can't dup stdout to stderr";
exit &$coderef();
}
exec("server/sws $port");

View File

@@ -1,4 +1,4 @@
#!/usr/bin/perl
#!/usr/bin/env perl
# $Id$
#
# Main curl test script, in perl to run on more platforms
@@ -68,6 +68,8 @@ my $debugprotocol;
my $anyway;
my $gdbthis; # run test case with gdb debugger
my $keepoutfiles; # keep stdout and stderr files after tests
my $listonly; # only list the tests
my $pwd; # current working directory
chomp($pwd = `pwd`);
@@ -138,16 +140,27 @@ sub runhttpserver {
my $RUNNING;
my $pid;
$pid = checkserver ($HTTPPIDFILE);
# verify if our/any server is running on this port
my $data=`$CURL --silent -i $HOSTIP:$HOSTPORT/verifiedserver`;
if ( $data =~ /WE ROOLZ(: |)(\d*)/ ) {
$pid = 0+$2;
if($2) {
$pid = 0+$2;
}
if(!$pid) {
print "Test server already running with unknown pid! Use it...\n";
return;
}
if($verbose) {
print "Test server already running with pid $pid, killing it...\n";
}
}
elsif($data ne "") {
print "GOT: $data\n";
print "An alien HTTP server is running on port $HOSTPORT\n",
"Edit runtests.pl to use another port and rerun the test script\n";
exit;
@@ -427,14 +440,6 @@ sub singletest {
my $CURLOUT="$LOGDIR/curl$testnum.out"; # curl output if not stdout
# remove previous server output logfile
unlink($SERVERIN);
if(@ftpservercmd) {
# write the instructions to file
writearray($FTPDCMD, \@ftpservercmd);
}
# name of the test
my @testname= getpart("client", "name");
@@ -445,6 +450,18 @@ sub singletest {
print "[$name]\n";
}
if($listonly) {
return 0; # look successful
}
# remove previous server output logfile
unlink($SERVERIN);
if(@ftpservercmd) {
# write the instructions to file
writearray($FTPDCMD, \@ftpservercmd);
}
# get the command line options to use
my ($cmd, @blaha)= getpart("client", "command");
@@ -477,9 +494,17 @@ sub singletest {
writearray($filename, \@inputfile);
}
my %cmdhash = getpartattr("client", "command");
my $out="";
if (!@validstdout) {
$out="--output $CURLOUT ";
if($cmdhash{'option'} eq "no-output") {
#print "*** We don't slap on --output\n";
}
else {
if (!@validstdout) {
$out="--output $CURLOUT ";
}
}
# run curl, add -v for debug information output
@@ -588,6 +613,15 @@ sub singletest {
my @protstrip=@protocol;
# check if there's any attributes on the verify/protocol section
my %hash = getpartattr("verify", "protocol");
if($hash{'nonewline'}) {
# Yes, we must cut off the final newline from the final line
# of the protocol data
chomp($protstrip[$#protstrip]);
}
for(@strip) {
# strip all patterns from both arrays
@out = striparray( $_, \@out);
@@ -775,6 +809,10 @@ do {
# continue anyway, even if a test fail
$anyway=1;
}
elsif($ARGV[0] eq "-l") {
# lists the test case names only
$listonly=1;
}
elsif($ARGV[0] eq "-k") {
# keep stdout and stderr files after tests
$keepoutfiles=1;
@@ -788,6 +826,7 @@ Usage: runtests.pl [options]
-g run the test case with gdb
-h this help text
-k keep stdout and stderr files present after tests
-l list all test case names/descriptions
-s short output
-v verbose output
[num] like "5 6 9" or " 5 to 22 " to run those tests only
@@ -816,12 +855,13 @@ if($testthis[0] ne "") {
$TESTCASES=join(" ", @testthis);
}
#######################################################################
# Output curl version and host info being tested
#
displaydata();
if(!$listonly) {
displaydata();
}
#######################################################################
# clear and create logging directory:

12
tests/server/Makefile.am Normal file
View File

@@ -0,0 +1,12 @@
# sws is the Silly Web Server
#
# Original http server code contributed by Georg Horn. Heavily modified since.
#
AUTOMAKE_OPTIONS = foreign
noinst_PROGRAMS = sws
sws_SOURCES= sws.c getpart.c
extra_DIST = config.h.in

2
tests/server/config.h.in Normal file
View File

@@ -0,0 +1,2 @@
#undef HAVE_SIGNAL

153
tests/server/getpart.c Normal file
View File

@@ -0,0 +1,153 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define EAT_SPACE(ptr) while( ptr && *ptr && isspace(*ptr) ) ptr++
#define EAT_WORD(ptr) while( ptr && *ptr && !isspace(*ptr) && ('>' != *ptr)) ptr++
#ifdef DEBUG
#define show(x) printf x
#else
#define show(x)
#endif
static
char *appendstring(char *string, /* original string */
char *buffer, /* to append */
int *stringlen, int *stralloc)
{
int len = strlen(buffer);
if((len + *stringlen) > *stralloc) {
char *newptr= realloc(string, *stralloc*2);
if(newptr) {
string = newptr;
*stralloc *= 2;
}
else
return NULL;
}
strcpy(&string[*stringlen], buffer);
*stringlen += len;
return string;
}
char *spitout(FILE *stream, char *main, char *sub, int *size)
{
char buffer[8192]; /* big enough for anything */
char cmain[128]=""; /* current main section */
char csub[128]=""; /* current sub section */
char *ptr;
char *end;
char display = 0;
char *string;
int stringlen=0;
int stralloc=256;
enum {
STATE_OUTSIDE,
STATE_INMAIN,
STATE_INSUB,
STATE_ILLEGAL
} state = STATE_OUTSIDE;
string = (char *)malloc(stralloc);
while(fgets(buffer, sizeof(buffer), stream)) {
ptr = buffer;
/* pass white spaces */
EAT_SPACE(ptr);
if('<' != *ptr) {
if(display) {
show(("=> %s", buffer));
string = appendstring(string, buffer, &stringlen, &stralloc);
show(("* %s\n", buffer));
}
continue;
}
ptr++;
EAT_SPACE(ptr);
if('/' == *ptr) {
/* end of a section */
ptr++;
EAT_SPACE(ptr);
end = ptr;
EAT_WORD(end);
*end = 0;
if((state == STATE_INSUB) &&
!strcmp(csub, ptr)) {
/* this is the end of the currently read sub section */
state--;
csub[0]=0; /* no sub anymore */
display=0;
}
else if((state == STATE_INMAIN) &&
!strcmp(cmain, ptr)) {
/* this is the end of the currently read main section */
state--;
cmain[0]=0; /* no main anymore */
display=0;
}
}
else if(!display) {
/* this is the beginning of a section */
end = ptr;
EAT_WORD(end);
*end = 0;
switch(state) {
case STATE_OUTSIDE:
strcpy(cmain, ptr);
state = STATE_INMAIN;
break;
case STATE_INMAIN:
strcpy(csub, ptr);
state = STATE_INSUB;
break;
}
}
if(display) {
string = appendstring(string, buffer, &stringlen, &stralloc);
show(("* %s\n", buffer));
}
if((STATE_INSUB == state) &&
!strcmp(cmain, main) &&
!strcmp(csub, sub)) {
show(("* (%d bytes) %s\n", stringlen, buffer));
display = 1; /* start displaying */
}
else {
show(("%d (%s/%s): %s\n", state, cmain, csub, buffer));
display = 0; /* no display */
}
}
*size = stringlen;
return string;
}
#ifdef TEST
int main(int argc, char **argv)
{
if(argc< 3) {
printf("./moo main sub\n");
}
else {
int size;
char *buffer = spitout(stdin, argv[1], argv[2], &size);
}
return 0;
}
#endif

425
tests/server/sws.c Normal file
View File

@@ -0,0 +1,425 @@
/* sws.c: simple (silly?) web server */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
char *spitout(FILE *stream, char *main, char *sub, int *size);
#define DEFAULT_PORT 8999
#ifndef DEFAULT_LOGFILE
#define DEFAULT_LOGFILE "log/sws.log"
#endif
#define DOCBUFSIZE 4
#define BUFFERSIZE (DOCBUFSIZE * 1024)
#define VERSION "cURL test suite HTTP server/0.1"
#define REQUEST_DUMP "log/server.input"
#define TEST_DATA_PATH "data/test%d"
static char *docfriends = "HTTP/1.1 200 Mighty fine indeed\r\n\r\nWE ROOLZ\r\n";
static char *doc404 = "HTTP/1.1 404 Not Found\n"
"Server: " VERSION "\n"
"Connection: close\n"
"Content-Type: text/html\n"
"\n"
"<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\">\n"
"<HTML><HEAD>\n"
"<TITLE>404 Not Found</TITLE>\n"
"</HEAD><BODY>\n"
"<H1>Not Found</H1>\n"
"The requested URL was not found on this server.\n"
"<P><HR><ADDRESS>" VERSION "</ADDRESS>\n" "</BODY></HTML>\n";
static volatile int sigpipe, sigterm;
static FILE *logfp;
static void logmsg(const char *msg)
{
time_t t = time(NULL);
struct tm *curr_time = localtime(&t);
char loctime[80];
strcpy(loctime, asctime(curr_time));
loctime[strlen(loctime) - 1] = '\0';
fprintf(logfp, "%s: pid %d: %s\n", loctime, getpid(), msg);
#ifdef DEBUG
fprintf(stderr, "%s: pid %d: %s\n", loctime, getpid(), msg);
#endif
fflush(logfp);
}
static void sigpipe_handler(int sig)
{
sigpipe = 1;
}
static void sigterm_handler(int sig)
{
char logbuf[100];
snprintf(logbuf, 100, "Got signal %d, terminating", sig);
logmsg(logbuf);
sigterm = 1;
}
int ProcessRequest(char *request)
{
char *line=request;
unsigned long contentlength=0;
#define END_OF_HEADERS "\r\n\r\n"
char *end;
end = strstr(request, END_OF_HEADERS);
if(!end)
/* we don't have a complete request yet! */
return 0;
/* **** Persistancy ****
*
* If the request is a HTTP/1.0 one, we close the connection unconditionally
* when we're done.
*
* If the request is a HTTP/1.1 one, we MUST check for a "Connection:"
* header that might say "close". If it does, we close a connection when
* this request is processed. Otherwise, we keep the connection alive for X
* seconds.
*/
do {
if(!strncasecmp("Content-Length:", line, 15))
contentlength = strtol(line+15, &line, 10);
line = strchr(line, '\n');
if(line)
line++;
} while(line);
if(contentlength > 0 ) {
if(contentlength <= strlen(end+strlen(END_OF_HEADERS)))
return 1; /* done */
else
return 0; /* not complete yet */
}
return 1; /* done */
}
/* store the entire request in a file */
void storerequest(char *reqbuf)
{
FILE *dump;
dump = fopen(REQUEST_DUMP, "ab"); /* b is for windows-preparing */
if(dump) {
fwrite(reqbuf, 1, strlen(reqbuf), dump);
fclose(dump);
}
}
#define REQBUFSIZ 50000
#define REQBUFSIZ_TXT "49999"
/* very-big-path support */
#define MAXDOCNAMELEN 40000
#define MAXDOCNAMELEN_TXT "39999"
#define REQUEST_KEYWORD_SIZE 256
static int get_request(int sock, int *part)
{
static char reqbuf[REQBUFSIZ], doc[MAXDOCNAMELEN];
static char request[REQUEST_KEYWORD_SIZE];
unsigned int offset = 0;
int prot_major, prot_minor;
char logbuf[256];
*part = 0; /* part zero equals none */
while (offset < REQBUFSIZ) {
int got = recv(sock, reqbuf + offset, REQBUFSIZ - offset, 0);
if (got <= 0) {
if (got < 0) {
perror("recv");
return -1;
}
logmsg("Connection closed by client");
return -1;
}
offset += got;
reqbuf[offset] = 0;
if(ProcessRequest(reqbuf))
break;
}
if (offset >= REQBUFSIZ) {
logmsg("Request buffer overflow, closing connection");
return -1;
}
reqbuf[offset]=0;
logmsg("Received a request");
/* dump the request to an external file */
storerequest(reqbuf);
if (sscanf(reqbuf, "%" REQBUFSIZ_TXT"s %" MAXDOCNAMELEN_TXT "s HTTP/%d.%d",
request,
doc,
&prot_major,
&prot_minor) == 4) {
char *ptr;
int test_no=0;
/* find the last slash */
ptr = strrchr(doc, '/');
/* get the number after it */
if(ptr) {
if((strlen(doc) + strlen(request)) < 200)
sprintf(logbuf, "Got request: %s %s HTTP/%d.%d",
request, doc, prot_major, prot_minor);
else
sprintf(logbuf, "Got a *HUGE* request HTTP/%d.%d",
prot_major, prot_minor);
logmsg(logbuf);
if(!strncmp("/verifiedserver", ptr, 15)) {
logmsg("Are-we-friendly question received");
return -2;
}
ptr++; /* skip the slash */
test_no = strtol(ptr, &ptr, 10);
if(test_no > 10000) {
*part = test_no % 10000;
test_no /= 10000;
}
sprintf(logbuf, "Found test number %d in path", test_no);
logmsg(logbuf);
}
else {
logmsg("Did not find test number in PATH");
}
return test_no;
}
logmsg("Got illegal request");
fprintf(stderr, "Got illegal request\n");
return -1;
}
static int send_doc(int sock, int doc, int part_no)
{
int written;
int count;
char *buffer;
char *ptr;
FILE *stream;
char *cmd=NULL;
int cmdsize;
char filename[256];
char partbuf[80]="data";
if(doc < 0) {
if(-2 == doc)
/* we got a "friends?" question, reply back that we sure are */
buffer = docfriends;
else
buffer = doc404;
ptr = NULL;
stream=NULL;
count = strlen(buffer);
}
else {
if(0 != part_no) {
sprintf(partbuf, "data%d", part_no);
}
sprintf(filename, TEST_DATA_PATH, doc);
stream=fopen(filename, "rb");
if(!stream) {
logmsg("Couldn't open test file");
return 0;
}
else {
ptr = buffer = spitout(stream, "reply", partbuf, &count);
fclose(stream);
}
/* re-open the same file again */
stream=fopen(filename, "rb");
if(!stream) {
logmsg("Couldn't open test file");
return 0;
}
else {
/* get the custom server control "commands" */
cmd = spitout(stream, "reply", "postcmd", &cmdsize);
fclose(stream);
}
}
do {
written = send(sock, buffer, count, 0);
if (written < 0) {
return -1;
}
count -= written;
buffer += written;
} while(count>0);
if(ptr)
free(ptr);
if(cmdsize > 0 ) {
char command[32];
int num;
char *ptr=cmd;
do {
if(2 == sscanf(ptr, "%31s %d", command, &num)) {
if(!strcmp("wait", command))
sleep(num); /* wait this many seconds */
else {
logmsg("Unknown command in reply command section");
}
}
ptr = strchr(ptr, '\n');
if(ptr)
ptr++;
else
ptr = NULL;
} while(ptr && *ptr);
}
if(cmd)
free(cmd);
return 0;
}
int main(int argc, char *argv[])
{
struct sockaddr_in me;
int sock, msgsock, flag;
unsigned short port = DEFAULT_PORT;
char *logfile = DEFAULT_LOGFILE;
int part_no;
FILE *pidfile;
if(argc>1)
port = atoi(argv[1]);
/* FIX: write our pid to a file name */
logfp = fopen(logfile, "a");
if (!logfp) {
perror(logfile);
exit(1);
}
#ifdef HAVE_SIGNAL
/* FIX: make a more portable signal handler */
signal(SIGPIPE, sigpipe_handler);
signal(SIGINT, sigterm_handler);
signal(SIGTERM, sigterm_handler);
siginterrupt(SIGPIPE, 1);
siginterrupt(SIGINT, 1);
siginterrupt(SIGTERM, 1);
#endif
sock = socket(AF_INET, SOCK_STREAM, 0);
if (sock < 0) {
perror("opening stream socket");
fprintf(logfp, "Error opening socket -- aborting\n");
fclose(logfp);
exit(1);
}
flag = 1;
if (setsockopt
(sock, SOL_SOCKET, SO_REUSEADDR, (const void *) &flag,
sizeof(int)) < 0) {
perror("setsockopt(SO_REUSEADDR)");
}
me.sin_family = AF_INET;
me.sin_addr.s_addr = INADDR_ANY;
me.sin_port = htons(port);
if (bind(sock, (struct sockaddr *) &me, sizeof me) < 0) {
perror("binding stream socket");
fprintf(logfp, "Error binding socket -- aborting\n");
fclose(logfp);
exit(1);
}
pidfile = fopen(".http.pid", "w");
if(pidfile) {
fprintf(pidfile, "%d\n", (int)getpid());
fclose(pidfile);
}
else
fprintf(stderr, "Couldn't write pid file\n");
/* start accepting connections */
listen(sock, 5);
fprintf(stderr, "*** %s listening on port %u ***\n", VERSION, port);
while (!sigterm) {
int doc;
msgsock = accept(sock, NULL, NULL);
if (msgsock == -1) {
if (sigterm) {
break;
}
/* perror("accept"); */
continue;
}
logmsg("New client connected");
doc = get_request(msgsock, &part_no);
send_doc(msgsock, doc, part_no);
close(msgsock);
}
close(sock);
fclose(logfp);
return 0;
}