|
dvander@2518
|
1 |
.\" ************************************************************************** |
|
dvander@2518
|
2 |
.\" * _ _ ____ _ |
|
dvander@2518
|
3 |
.\" * Project ___| | | | _ \| | |
|
dvander@2518
|
4 |
.\" * / __| | | | |_) | | |
|
dvander@2518
|
5 |
.\" * | (__| |_| | _ <| |___ |
|
dvander@2518
|
6 |
.\" * \___|\___/|_| \_\_____| |
|
dvander@2518
|
7 |
.\" * |
|
asherkin@3839
|
8 |
.\" * Copyright (C) 1998 - 2011, Daniel Stenberg, <[email protected]>, et al. |
|
dvander@2518
|
9 |
.\" * |
|
dvander@2518
|
10 |
.\" * This software is licensed as described in the file COPYING, which |
|
dvander@2518
|
11 |
.\" * you should have received as part of this distribution. The terms |
|
dvander@2518
|
12 |
.\" * are also available at http://curl.haxx.se/docs/copyright.html. |
|
dvander@2518
|
13 |
.\" * |
|
dvander@2518
|
14 |
.\" * You may opt to use, copy, modify, merge, publish, distribute and/or sell |
|
dvander@2518
|
15 |
.\" * copies of the Software, and permit persons to whom the Software is |
|
dvander@2518
|
16 |
.\" * furnished to do so, under the terms of the COPYING file. |
|
dvander@2518
|
17 |
.\" * |
|
dvander@2518
|
18 |
.\" * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY |
|
dvander@2518
|
19 |
.\" * KIND, either express or implied. |
|
dvander@2518
|
20 |
.\" * |
|
dvander@2518
|
21 |
.\" ************************************************************************** |
|
dvander@2518
|
22 |
.\" |
|
asherkin@3839
|
23 |
.TH libcurl-tutorial 3 "4 Mar 2009" "libcurl" "libcurl programming" |
|
dvander@2518
|
24 |
.SH NAME |
|
dvander@2518
|
25 |
libcurl-tutorial \- libcurl programming tutorial |
|
dvander@2518
|
26 |
.SH "Objective" |
|
dvander@2518
|
27 |
This document attempts to describe the general principles and some basic |
|
dvander@2518
|
28 |
approaches to consider when programming with libcurl. The text will focus |
|
dvander@2518
|
29 |
mainly on the C interface but might apply fairly well on other interfaces as |
|
dvander@2518
|
30 |
well as they usually follow the C one pretty closely. |
|
dvander@2518
|
31 |
|
|
dvander@2518
|
32 |
This document will refer to 'the user' as the person writing the source code |
|
dvander@2518
|
33 |
that uses libcurl. That would probably be you or someone in your position. |
|
dvander@2518
|
34 |
What will be generally referred to as 'the program' will be the collected |
|
dvander@2518
|
35 |
source code that you write that is using libcurl for transfers. The program |
|
dvander@2518
|
36 |
is outside libcurl and libcurl is outside of the program. |
|
dvander@2518
|
37 |
|
|
asherkin@3839
|
38 |
To get more details on all options and functions described herein, please |
|
dvander@2518
|
39 |
refer to their respective man pages. |
|
dvander@2518
|
40 |
|
|
dvander@2518
|
41 |
.SH "Building" |
|
dvander@2518
|
42 |
There are many different ways to build C programs. This chapter will assume a |
|
asherkin@3839
|
43 |
UNIX-style build process. If you use a different build system, you can still |
|
dvander@2518
|
44 |
read this to get general information that may apply to your environment as |
|
dvander@2518
|
45 |
well. |
|
dvander@2518
|
46 |
.IP "Compiling the Program" |
|
dvander@2518
|
47 |
Your compiler needs to know where the libcurl headers are located. Therefore |
|
dvander@2518
|
48 |
you must set your compiler's include path to point to the directory where you |
|
dvander@2518
|
49 |
installed them. The 'curl-config'[3] tool can be used to get this information: |
|
dvander@2518
|
50 |
|
|
dvander@2518
|
51 |
$ curl-config --cflags |
|
dvander@2518
|
52 |
|
|
dvander@2518
|
53 |
.IP "Linking the Program with libcurl" |
|
dvander@2518
|
54 |
When having compiled the program, you need to link your object files to create |
|
dvander@2518
|
55 |
a single executable. For that to succeed, you need to link with libcurl and |
|
dvander@2518
|
56 |
possibly also with other libraries that libcurl itself depends on. Like the |
|
dvander@2518
|
57 |
OpenSSL libraries, but even some standard OS libraries may be needed on the |
|
dvander@2518
|
58 |
command line. To figure out which flags to use, once again the 'curl-config' |
|
dvander@2518
|
59 |
tool comes to the rescue: |
|
dvander@2518
|
60 |
|
|
dvander@2518
|
61 |
$ curl-config --libs |
|
dvander@2518
|
62 |
|
|
dvander@2518
|
63 |
.IP "SSL or Not" |
|
dvander@2518
|
64 |
libcurl can be built and customized in many ways. One of the things that |
|
dvander@2518
|
65 |
varies from different libraries and builds is the support for SSL-based |
|
dvander@2518
|
66 |
transfers, like HTTPS and FTPS. If a supported SSL library was detected |
|
dvander@2518
|
67 |
properly at build-time, libcurl will be built with SSL support. To figure out |
|
dvander@2518
|
68 |
if an installed libcurl has been built with SSL support enabled, use |
|
dvander@2518
|
69 |
\&'curl-config' like this: |
|
dvander@2518
|
70 |
|
|
dvander@2518
|
71 |
$ curl-config --feature |
|
dvander@2518
|
72 |
|
|
dvander@2518
|
73 |
And if SSL is supported, the keyword 'SSL' will be written to stdout, |
|
asherkin@3839
|
74 |
possibly together with a few other features that could be either on or off on |
|
asherkin@3839
|
75 |
for different libcurls. |
|
dvander@2518
|
76 |
|
|
dvander@2518
|
77 |
See also the "Features libcurl Provides" further down. |
|
dvander@2518
|
78 |
.IP "autoconf macro" |
|
dvander@2518
|
79 |
When you write your configure script to detect libcurl and setup variables |
|
dvander@2518
|
80 |
accordingly, we offer a prewritten macro that probably does everything you |
|
dvander@2518
|
81 |
need in this area. See docs/libcurl/libcurl.m4 file - it includes docs on how |
|
dvander@2518
|
82 |
to use it. |
|
dvander@2518
|
83 |
|
|
dvander@2518
|
84 |
.SH "Portable Code in a Portable World" |
|
dvander@2518
|
85 |
The people behind libcurl have put a considerable effort to make libcurl work |
|
dvander@2518
|
86 |
on a large amount of different operating systems and environments. |
|
dvander@2518
|
87 |
|
|
dvander@2518
|
88 |
You program libcurl the same way on all platforms that libcurl runs on. There |
|
asherkin@3839
|
89 |
are only very few minor considerations that differ. If you just make sure to |
|
dvander@2518
|
90 |
write your code portable enough, you may very well create yourself a very |
|
dvander@2518
|
91 |
portable program. libcurl shouldn't stop you from that. |
|
dvander@2518
|
92 |
|
|
dvander@2518
|
93 |
.SH "Global Preparation" |
|
dvander@2518
|
94 |
The program must initialize some of the libcurl functionality globally. That |
|
dvander@2518
|
95 |
means it should be done exactly once, no matter how many times you intend to |
|
dvander@2518
|
96 |
use the library. Once for your program's entire life time. This is done using |
|
dvander@2518
|
97 |
|
|
dvander@2518
|
98 |
curl_global_init() |
|
dvander@2518
|
99 |
|
|
dvander@2518
|
100 |
and it takes one parameter which is a bit pattern that tells libcurl what to |
|
dvander@2518
|
101 |
initialize. Using \fICURL_GLOBAL_ALL\fP will make it initialize all known |
|
dvander@2518
|
102 |
internal sub modules, and might be a good default option. The current two bits |
|
dvander@2518
|
103 |
that are specified are: |
|
dvander@2518
|
104 |
.RS |
|
dvander@2518
|
105 |
.IP "CURL_GLOBAL_WIN32" |
|
dvander@2518
|
106 |
which only does anything on Windows machines. When used on |
|
dvander@2518
|
107 |
a Windows machine, it'll make libcurl initialize the win32 socket |
|
dvander@2518
|
108 |
stuff. Without having that initialized properly, your program cannot use |
|
dvander@2518
|
109 |
sockets properly. You should only do this once for each application, so if |
|
dvander@2518
|
110 |
your program already does this or of another library in use does it, you |
|
dvander@2518
|
111 |
should not tell libcurl to do this as well. |
|
dvander@2518
|
112 |
.IP CURL_GLOBAL_SSL |
|
dvander@2518
|
113 |
which only does anything on libcurls compiled and built SSL-enabled. On these |
|
dvander@2518
|
114 |
systems, this will make libcurl initialize the SSL library properly for this |
|
asherkin@3839
|
115 |
application. This only needs to be done once for each application so if your |
|
dvander@2518
|
116 |
program or another library already does this, this bit should not be needed. |
|
dvander@2518
|
117 |
.RE |
|
dvander@2518
|
118 |
|
|
dvander@2518
|
119 |
libcurl has a default protection mechanism that detects if |
|
dvander@2518
|
120 |
\fIcurl_global_init(3)\fP hasn't been called by the time |
|
dvander@2518
|
121 |
\fIcurl_easy_perform(3)\fP is called and if that is the case, libcurl runs the |
|
dvander@2518
|
122 |
function itself with a guessed bit pattern. Please note that depending solely |
|
dvander@2518
|
123 |
on this is not considered nice nor very good. |
|
dvander@2518
|
124 |
|
|
dvander@2518
|
125 |
When the program no longer uses libcurl, it should call |
|
dvander@2518
|
126 |
\fIcurl_global_cleanup(3)\fP, which is the opposite of the init call. It will |
|
dvander@2518
|
127 |
then do the reversed operations to cleanup the resources the |
|
dvander@2518
|
128 |
\fIcurl_global_init(3)\fP call initialized. |
|
dvander@2518
|
129 |
|
|
dvander@2518
|
130 |
Repeated calls to \fIcurl_global_init(3)\fP and \fIcurl_global_cleanup(3)\fP |
|
dvander@2518
|
131 |
should be avoided. They should only be called once each. |
|
dvander@2518
|
132 |
|
|
dvander@2518
|
133 |
.SH "Features libcurl Provides" |
|
dvander@2518
|
134 |
It is considered best-practice to determine libcurl features at run-time |
|
dvander@2518
|
135 |
rather than at build-time (if possible of course). By calling |
|
dvander@2518
|
136 |
\fIcurl_version_info(3)\fP and checking out the details of the returned |
|
dvander@2518
|
137 |
struct, your program can figure out exactly what the currently running libcurl |
|
dvander@2518
|
138 |
supports. |
|
dvander@2518
|
139 |
|
|
dvander@2518
|
140 |
.SH "Handle the Easy libcurl" |
|
dvander@2518
|
141 |
libcurl first introduced the so called easy interface. All operations in the |
|
dvander@2518
|
142 |
easy interface are prefixed with 'curl_easy'. |
|
dvander@2518
|
143 |
|
|
dvander@2518
|
144 |
Recent libcurl versions also offer the multi interface. More about that |
|
dvander@2518
|
145 |
interface, what it is targeted for and how to use it is detailed in a separate |
|
dvander@2518
|
146 |
chapter further down. You still need to understand the easy interface first, |
|
dvander@2518
|
147 |
so please continue reading for better understanding. |
|
dvander@2518
|
148 |
|
|
dvander@2518
|
149 |
To use the easy interface, you must first create yourself an easy handle. You |
|
dvander@2518
|
150 |
need one handle for each easy session you want to perform. Basically, you |
|
dvander@2518
|
151 |
should use one handle for every thread you plan to use for transferring. You |
|
dvander@2518
|
152 |
must never share the same handle in multiple threads. |
|
dvander@2518
|
153 |
|
|
dvander@2518
|
154 |
Get an easy handle with |
|
dvander@2518
|
155 |
|
|
dvander@2518
|
156 |
easyhandle = curl_easy_init(); |
|
dvander@2518
|
157 |
|
|
dvander@2518
|
158 |
It returns an easy handle. Using that you proceed to the next step: setting |
|
dvander@2518
|
159 |
up your preferred actions. A handle is just a logic entity for the upcoming |
|
dvander@2518
|
160 |
transfer or series of transfers. |
|
dvander@2518
|
161 |
|
|
dvander@2518
|
162 |
You set properties and options for this handle using |
|
dvander@2518
|
163 |
\fIcurl_easy_setopt(3)\fP. They control how the subsequent transfer or |
|
dvander@2518
|
164 |
transfers will be made. Options remain set in the handle until set again to |
|
dvander@2518
|
165 |
something different. Alas, multiple requests using the same handle will use |
|
dvander@2518
|
166 |
the same options. |
|
dvander@2518
|
167 |
|
|
dvander@2518
|
168 |
Many of the options you set in libcurl are "strings", pointers to data |
|
asherkin@3839
|
169 |
terminated with a zero byte. When you set strings with |
|
asherkin@3839
|
170 |
\fIcurl_easy_setopt(3)\fP, libcurl makes its own copy so that they don't |
|
asherkin@3839
|
171 |
need to be kept around in your application after being set[4]. |
|
dvander@2518
|
172 |
|
|
dvander@2518
|
173 |
One of the most basic properties to set in the handle is the URL. You set |
|
dvander@2518
|
174 |
your preferred URL to transfer with CURLOPT_URL in a manner similar to: |
|
dvander@2518
|
175 |
|
|
dvander@2518
|
176 |
.nf |
|
dvander@2518
|
177 |
curl_easy_setopt(handle, CURLOPT_URL, "http://domain.com/"); |
|
dvander@2518
|
178 |
.fi |
|
dvander@2518
|
179 |
|
|
dvander@2518
|
180 |
Let's assume for a while that you want to receive data as the URL identifies a |
|
dvander@2518
|
181 |
remote resource you want to get here. Since you write a sort of application |
|
dvander@2518
|
182 |
that needs this transfer, I assume that you would like to get the data passed |
|
dvander@2518
|
183 |
to you directly instead of simply getting it passed to stdout. So, you write |
|
dvander@2518
|
184 |
your own function that matches this prototype: |
|
dvander@2518
|
185 |
|
|
dvander@2518
|
186 |
size_t write_data(void *buffer, size_t size, size_t nmemb, void *userp); |
|
dvander@2518
|
187 |
|
|
dvander@2518
|
188 |
You tell libcurl to pass all data to this function by issuing a function |
|
dvander@2518
|
189 |
similar to this: |
|
dvander@2518
|
190 |
|
|
dvander@2518
|
191 |
curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, write_data); |
|
dvander@2518
|
192 |
|
|
asherkin@3839
|
193 |
You can control what data your callback function gets in the fourth argument |
|
asherkin@3839
|
194 |
by setting another property: |
|
dvander@2518
|
195 |
|
|
dvander@2518
|
196 |
curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, &internal_struct); |
|
dvander@2518
|
197 |
|
|
dvander@2518
|
198 |
Using that property, you can easily pass local data between your application |
|
dvander@2518
|
199 |
and the function that gets invoked by libcurl. libcurl itself won't touch the |
|
dvander@2518
|
200 |
data you pass with \fICURLOPT_WRITEDATA\fP. |
|
dvander@2518
|
201 |
|
|
asherkin@3839
|
202 |
libcurl offers its own default internal callback that will take care of the data |
|
dvander@2518
|
203 |
if you don't set the callback with \fICURLOPT_WRITEFUNCTION\fP. It will then |
|
dvander@2518
|
204 |
simply output the received data to stdout. You can have the default callback |
|
dvander@2518
|
205 |
write the data to a different file handle by passing a 'FILE *' to a file |
|
dvander@2518
|
206 |
opened for writing with the \fICURLOPT_WRITEDATA\fP option. |
|
dvander@2518
|
207 |
|
|
dvander@2518
|
208 |
Now, we need to take a step back and have a deep breath. Here's one of those |
|
dvander@2518
|
209 |
rare platform-dependent nitpicks. Did you spot it? On some platforms[2], |
|
dvander@2518
|
210 |
libcurl won't be able to operate on files opened by the program. Thus, if you |
|
dvander@2518
|
211 |
use the default callback and pass in an open file with |
|
dvander@2518
|
212 |
\fICURLOPT_WRITEDATA\fP, it will crash. You should therefore avoid this to |
|
dvander@2518
|
213 |
make your program run fine virtually everywhere. |
|
dvander@2518
|
214 |
|
|
dvander@2518
|
215 |
(\fICURLOPT_WRITEDATA\fP was formerly known as \fICURLOPT_FILE\fP. Both names |
|
dvander@2518
|
216 |
still work and do the same thing). |
|
dvander@2518
|
217 |
|
|
dvander@2518
|
218 |
If you're using libcurl as a win32 DLL, you MUST use the |
|
dvander@2518
|
219 |
\fICURLOPT_WRITEFUNCTION\fP if you set \fICURLOPT_WRITEDATA\fP - or you will |
|
dvander@2518
|
220 |
experience crashes. |
|
dvander@2518
|
221 |
|
|
dvander@2518
|
222 |
There are of course many more options you can set, and we'll get back to a few |
|
dvander@2518
|
223 |
of them later. Let's instead continue to the actual transfer: |
|
dvander@2518
|
224 |
|
|
dvander@2518
|
225 |
success = curl_easy_perform(easyhandle); |
|
dvander@2518
|
226 |
|
|
dvander@2518
|
227 |
\fIcurl_easy_perform(3)\fP will connect to the remote site, do the necessary |
|
dvander@2518
|
228 |
commands and receive the transfer. Whenever it receives data, it calls the |
|
dvander@2518
|
229 |
callback function we previously set. The function may get one byte at a time, |
|
dvander@2518
|
230 |
or it may get many kilobytes at once. libcurl delivers as much as possible as |
|
dvander@2518
|
231 |
often as possible. Your callback function should return the number of bytes it |
|
dvander@2518
|
232 |
\&"took care of". If that is not the exact same amount of bytes that was |
|
dvander@2518
|
233 |
passed to it, libcurl will abort the operation and return with an error code. |
|
dvander@2518
|
234 |
|
|
dvander@2518
|
235 |
When the transfer is complete, the function returns a return code that informs |
|
dvander@2518
|
236 |
you if it succeeded in its mission or not. If a return code isn't enough for |
|
dvander@2518
|
237 |
you, you can use the CURLOPT_ERRORBUFFER to point libcurl to a buffer of yours |
|
dvander@2518
|
238 |
where it'll store a human readable error message as well. |
|
dvander@2518
|
239 |
|
|
dvander@2518
|
240 |
If you then want to transfer another file, the handle is ready to be used |
|
dvander@2518
|
241 |
again. Mind you, it is even preferred that you re-use an existing handle if |
|
dvander@2518
|
242 |
you intend to make another transfer. libcurl will then attempt to re-use the |
|
dvander@2518
|
243 |
previous connection. |
|
dvander@2518
|
244 |
|
|
asherkin@3839
|
245 |
For some protocols, downloading a file can involve a complicated process of |
|
asherkin@3839
|
246 |
logging in, setting the transfer mode, changing the current directory and |
|
asherkin@3839
|
247 |
finally transferring the file data. libcurl takes care of all that |
|
asherkin@3839
|
248 |
complication for you. Given simply the URL to a file, libcurl will take care |
|
asherkin@3839
|
249 |
of all the details needed to get the file moved from one machine to another. |
|
asherkin@3839
|
250 |
|
|
dvander@2518
|
251 |
.SH "Multi-threading Issues" |
|
asherkin@3839
|
252 |
The first basic rule is that you must \fBnever\fP simultaneously share a |
|
asherkin@3839
|
253 |
libcurl handle (be it easy or multi or whatever) between multiple |
|
asherkin@3839
|
254 |
threads. Only use one handle in one thread at any time. You can pass the |
|
asherkin@3839
|
255 |
handles around among threads, but you must never use a single handle from more |
|
asherkin@3839
|
256 |
than one thread at any given time. |
|
dvander@2518
|
257 |
|
|
dvander@2518
|
258 |
libcurl is completely thread safe, except for two issues: signals and SSL/TLS |
|
asherkin@3839
|
259 |
handlers. Signals are used for timing out name resolves (during DNS lookup) - |
|
asherkin@3839
|
260 |
when built without c-ares support and not on Windows. |
|
dvander@2518
|
261 |
|
|
dvander@2518
|
262 |
If you are accessing HTTPS or FTPS URLs in a multi-threaded manner, you are |
|
dvander@2518
|
263 |
then of course using the underlying SSL library multi-threaded and those libs |
|
dvander@2518
|
264 |
might have their own requirements on this issue. Basically, you need to |
|
dvander@2518
|
265 |
provide one or two functions to allow it to function properly. For all |
|
dvander@2518
|
266 |
details, see this: |
|
dvander@2518
|
267 |
|
|
dvander@2518
|
268 |
OpenSSL |
|
dvander@2518
|
269 |
|
|
dvander@2518
|
270 |
http://www.openssl.org/docs/crypto/threads.html#DESCRIPTION |
|
dvander@2518
|
271 |
|
|
dvander@2518
|
272 |
GnuTLS |
|
dvander@2518
|
273 |
|
|
dvander@2518
|
274 |
http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html |
|
dvander@2518
|
275 |
|
|
dvander@2518
|
276 |
NSS |
|
asherkin@3839
|
277 |
|
|
asherkin@3839
|
278 |
is claimed to be thread-safe already without anything required. |
|
asherkin@3839
|
279 |
|
|
asherkin@3839
|
280 |
PolarSSL |
|
asherkin@3839
|
281 |
|
|
asherkin@3839
|
282 |
Required actions unknown. |
|
dvander@2518
|
283 |
|
|
dvander@2518
|
284 |
yassl |
|
dvander@2518
|
285 |
|
|
asherkin@3839
|
286 |
Required actions unknown. |
|
asherkin@3839
|
287 |
|
|
asherkin@3839
|
288 |
axTLS |
|
asherkin@3839
|
289 |
|
|
asherkin@3839
|
290 |
Required actions unknown. |
|
dvander@2518
|
291 |
|
|
dvander@2518
|
292 |
When using multiple threads you should set the CURLOPT_NOSIGNAL option to 1 |
|
dvander@2518
|
293 |
for all handles. Everything will or might work fine except that timeouts are |
|
dvander@2518
|
294 |
not honored during the DNS lookup - which you can work around by building |
|
dvander@2518
|
295 |
libcurl with c-ares support. c-ares is a library that provides asynchronous |
|
asherkin@3839
|
296 |
name resolves. On some platforms, libcurl simply will not function properly |
|
asherkin@3839
|
297 |
multi-threaded unless this option is set. |
|
dvander@2518
|
298 |
|
|
dvander@2518
|
299 |
Also, note that CURLOPT_DNS_USE_GLOBAL_CACHE is not thread-safe. |
|
dvander@2518
|
300 |
|
|
dvander@2518
|
301 |
.SH "When It Doesn't Work" |
|
dvander@2518
|
302 |
There will always be times when the transfer fails for some reason. You might |
|
dvander@2518
|
303 |
have set the wrong libcurl option or misunderstood what the libcurl option |
|
dvander@2518
|
304 |
actually does, or the remote server might return non-standard replies that |
|
dvander@2518
|
305 |
confuse the library which then confuses your program. |
|
dvander@2518
|
306 |
|
|
dvander@2518
|
307 |
There's one golden rule when these things occur: set the CURLOPT_VERBOSE |
|
dvander@2518
|
308 |
option to 1. It'll cause the library to spew out the entire protocol |
|
dvander@2518
|
309 |
details it sends, some internal info and some received protocol data as well |
|
dvander@2518
|
310 |
(especially when using FTP). If you're using HTTP, adding the headers in the |
|
dvander@2518
|
311 |
received output to study is also a clever way to get a better understanding |
|
dvander@2518
|
312 |
why the server behaves the way it does. Include headers in the normal body |
|
dvander@2518
|
313 |
output with CURLOPT_HEADER set 1. |
|
dvander@2518
|
314 |
|
|
asherkin@3839
|
315 |
Of course, there are bugs left. We need to know about them to be able |
|
dvander@2518
|
316 |
to fix them, so we're quite dependent on your bug reports! When you do report |
|
asherkin@3839
|
317 |
suspected bugs in libcurl, please include as many details as you possibly can: a |
|
dvander@2518
|
318 |
protocol dump that CURLOPT_VERBOSE produces, library version, as much as |
|
dvander@2518
|
319 |
possible of your code that uses libcurl, operating system name and version, |
|
dvander@2518
|
320 |
compiler name and version etc. |
|
dvander@2518
|
321 |
|
|
dvander@2518
|
322 |
If CURLOPT_VERBOSE is not enough, you increase the level of debug data your |
|
dvander@2518
|
323 |
application receive by using the CURLOPT_DEBUGFUNCTION. |
|
dvander@2518
|
324 |
|
|
dvander@2518
|
325 |
Getting some in-depth knowledge about the protocols involved is never wrong, |
|
dvander@2518
|
326 |
and if you're trying to do funny things, you might very well understand |
|
dvander@2518
|
327 |
libcurl and how to use it better if you study the appropriate RFC documents |
|
dvander@2518
|
328 |
at least briefly. |
|
dvander@2518
|
329 |
|
|
dvander@2518
|
330 |
.SH "Upload Data to a Remote Site" |
|
dvander@2518
|
331 |
libcurl tries to keep a protocol independent approach to most transfers, thus |
|
dvander@2518
|
332 |
uploading to a remote FTP site is very similar to uploading data to a HTTP |
|
dvander@2518
|
333 |
server with a PUT request. |
|
dvander@2518
|
334 |
|
|
dvander@2518
|
335 |
Of course, first you either create an easy handle or you re-use one existing |
|
dvander@2518
|
336 |
one. Then you set the URL to operate on just like before. This is the remote |
|
dvander@2518
|
337 |
URL, that we now will upload. |
|
dvander@2518
|
338 |
|
|
dvander@2518
|
339 |
Since we write an application, we most likely want libcurl to get the upload |
|
dvander@2518
|
340 |
data by asking us for it. To make it do that, we set the read callback and |
|
dvander@2518
|
341 |
the custom pointer libcurl will pass to our read callback. The read callback |
|
dvander@2518
|
342 |
should have a prototype similar to: |
|
dvander@2518
|
343 |
|
|
dvander@2518
|
344 |
size_t function(char *bufptr, size_t size, size_t nitems, void *userp); |
|
dvander@2518
|
345 |
|
|
dvander@2518
|
346 |
Where bufptr is the pointer to a buffer we fill in with data to upload and |
|
dvander@2518
|
347 |
size*nitems is the size of the buffer and therefore also the maximum amount |
|
dvander@2518
|
348 |
of data we can return to libcurl in this call. The 'userp' pointer is the |
|
dvander@2518
|
349 |
custom pointer we set to point to a struct of ours to pass private data |
|
dvander@2518
|
350 |
between the application and the callback. |
|
dvander@2518
|
351 |
|
|
dvander@2518
|
352 |
curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function); |
|
dvander@2518
|
353 |
|
|
dvander@2518
|
354 |
curl_easy_setopt(easyhandle, CURLOPT_READDATA, &filedata); |
|
dvander@2518
|
355 |
|
|
dvander@2518
|
356 |
Tell libcurl that we want to upload: |
|
dvander@2518
|
357 |
|
|
dvander@2518
|
358 |
curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, 1L); |
|
dvander@2518
|
359 |
|
|
dvander@2518
|
360 |
A few protocols won't behave properly when uploads are done without any prior |
|
dvander@2518
|
361 |
knowledge of the expected file size. So, set the upload file size using the |
|
dvander@2518
|
362 |
CURLOPT_INFILESIZE_LARGE for all known file sizes like this[1]: |
|
dvander@2518
|
363 |
|
|
dvander@2518
|
364 |
.nf |
|
asherkin@3839
|
365 |
/* in this example, file_size must be an curl_off_t variable */ |
|
dvander@2518
|
366 |
curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE_LARGE, file_size); |
|
dvander@2518
|
367 |
.fi |
|
dvander@2518
|
368 |
|
|
dvander@2518
|
369 |
When you call \fIcurl_easy_perform(3)\fP this time, it'll perform all the |
|
dvander@2518
|
370 |
necessary operations and when it has invoked the upload it'll call your |
|
dvander@2518
|
371 |
supplied callback to get the data to upload. The program should return as much |
|
dvander@2518
|
372 |
data as possible in every invoke, as that is likely to make the upload perform |
|
dvander@2518
|
373 |
as fast as possible. The callback should return the number of bytes it wrote |
|
dvander@2518
|
374 |
in the buffer. Returning 0 will signal the end of the upload. |
|
dvander@2518
|
375 |
|
|
dvander@2518
|
376 |
.SH "Passwords" |
|
dvander@2518
|
377 |
Many protocols use or even require that user name and password are provided |
|
dvander@2518
|
378 |
to be able to download or upload the data of your choice. libcurl offers |
|
dvander@2518
|
379 |
several ways to specify them. |
|
dvander@2518
|
380 |
|
|
dvander@2518
|
381 |
Most protocols support that you specify the name and password in the URL |
|
dvander@2518
|
382 |
itself. libcurl will detect this and use them accordingly. This is written |
|
dvander@2518
|
383 |
like this: |
|
dvander@2518
|
384 |
|
|
dvander@2518
|
385 |
protocol://user:[email protected]/path/ |
|
dvander@2518
|
386 |
|
|
dvander@2518
|
387 |
If you need any odd letters in your user name or password, you should enter |
|
dvander@2518
|
388 |
them URL encoded, as %XX where XX is a two-digit hexadecimal number. |
|
dvander@2518
|
389 |
|
|
dvander@2518
|
390 |
libcurl also provides options to set various passwords. The user name and |
|
dvander@2518
|
391 |
password as shown embedded in the URL can instead get set with the |
|
dvander@2518
|
392 |
CURLOPT_USERPWD option. The argument passed to libcurl should be a char * to |
|
asherkin@3839
|
393 |
a string in the format "user:password". In a manner like this: |
|
dvander@2518
|
394 |
|
|
dvander@2518
|
395 |
curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret"); |
|
dvander@2518
|
396 |
|
|
dvander@2518
|
397 |
Another case where name and password might be needed at times, is for those |
|
dvander@2518
|
398 |
users who need to authenticate themselves to a proxy they use. libcurl offers |
|
dvander@2518
|
399 |
another option for this, the CURLOPT_PROXYUSERPWD. It is used quite similar |
|
dvander@2518
|
400 |
to the CURLOPT_USERPWD option like this: |
|
dvander@2518
|
401 |
|
|
dvander@2518
|
402 |
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret"); |
|
asherkin@3839
|
403 |
|
|
asherkin@3839
|
404 |
There's a long time UNIX "standard" way of storing ftp user names and |
|
dvander@2518
|
405 |
passwords, namely in the $HOME/.netrc file. The file should be made private |
|
dvander@2518
|
406 |
so that only the user may read it (see also the "Security Considerations" |
|
dvander@2518
|
407 |
chapter), as it might contain the password in plain text. libcurl has the |
|
dvander@2518
|
408 |
ability to use this file to figure out what set of user name and password to |
|
dvander@2518
|
409 |
use for a particular host. As an extension to the normal functionality, |
|
dvander@2518
|
410 |
libcurl also supports this file for non-FTP protocols such as HTTP. To make |
|
dvander@2518
|
411 |
curl use this file, use the CURLOPT_NETRC option: |
|
dvander@2518
|
412 |
|
|
dvander@2518
|
413 |
curl_easy_setopt(easyhandle, CURLOPT_NETRC, 1L); |
|
dvander@2518
|
414 |
|
|
dvander@2518
|
415 |
And a very basic example of how such a .netrc file may look like: |
|
dvander@2518
|
416 |
|
|
dvander@2518
|
417 |
.nf |
|
dvander@2518
|
418 |
machine myhost.mydomain.com |
|
dvander@2518
|
419 |
login userlogin |
|
dvander@2518
|
420 |
password secretword |
|
dvander@2518
|
421 |
.fi |
|
dvander@2518
|
422 |
|
|
dvander@2518
|
423 |
All these examples have been cases where the password has been optional, or |
|
dvander@2518
|
424 |
at least you could leave it out and have libcurl attempt to do its job |
|
dvander@2518
|
425 |
without it. There are times when the password isn't optional, like when |
|
dvander@2518
|
426 |
you're using an SSL private key for secure transfers. |
|
dvander@2518
|
427 |
|
|
dvander@2518
|
428 |
To pass the known private key password to libcurl: |
|
dvander@2518
|
429 |
|
|
dvander@2518
|
430 |
curl_easy_setopt(easyhandle, CURLOPT_KEYPASSWD, "keypassword"); |
|
dvander@2518
|
431 |
|
|
dvander@2518
|
432 |
.SH "HTTP Authentication" |
|
dvander@2518
|
433 |
The previous chapter showed how to set user name and password for getting |
|
dvander@2518
|
434 |
URLs that require authentication. When using the HTTP protocol, there are |
|
dvander@2518
|
435 |
many different ways a client can provide those credentials to the server and |
|
asherkin@3839
|
436 |
you can control which way libcurl will (attempt to) use them. The default HTTP |
|
dvander@2518
|
437 |
authentication method is called 'Basic', which is sending the name and |
|
dvander@2518
|
438 |
password in clear-text in the HTTP request, base64-encoded. This is insecure. |
|
dvander@2518
|
439 |
|
|
asherkin@3839
|
440 |
At the time of this writing, libcurl can be built to use: Basic, Digest, NTLM, |
|
dvander@2518
|
441 |
Negotiate, GSS-Negotiate and SPNEGO. You can tell libcurl which one to use |
|
dvander@2518
|
442 |
with CURLOPT_HTTPAUTH as in: |
|
dvander@2518
|
443 |
|
|
dvander@2518
|
444 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); |
|
dvander@2518
|
445 |
|
|
dvander@2518
|
446 |
And when you send authentication to a proxy, you can also set authentication |
|
dvander@2518
|
447 |
type the same way but instead with CURLOPT_PROXYAUTH: |
|
dvander@2518
|
448 |
|
|
dvander@2518
|
449 |
curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM); |
|
dvander@2518
|
450 |
|
|
dvander@2518
|
451 |
Both these options allow you to set multiple types (by ORing them together), |
|
dvander@2518
|
452 |
to make libcurl pick the most secure one out of the types the server/proxy |
|
dvander@2518
|
453 |
claims to support. This method does however add a round-trip since libcurl |
|
dvander@2518
|
454 |
must first ask the server what it supports: |
|
dvander@2518
|
455 |
|
|
dvander@2518
|
456 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, |
|
dvander@2518
|
457 |
CURLAUTH_DIGEST|CURLAUTH_BASIC); |
|
dvander@2518
|
458 |
|
|
dvander@2518
|
459 |
For convenience, you can use the 'CURLAUTH_ANY' define (instead of a list |
|
dvander@2518
|
460 |
with specific types) which allows libcurl to use whatever method it wants. |
|
dvander@2518
|
461 |
|
|
dvander@2518
|
462 |
When asking for multiple types, libcurl will pick the available one it |
|
dvander@2518
|
463 |
considers "best" in its own internal order of preference. |
|
dvander@2518
|
464 |
|
|
dvander@2518
|
465 |
.SH "HTTP POSTing" |
|
dvander@2518
|
466 |
We get many questions regarding how to issue HTTP POSTs with libcurl the |
|
dvander@2518
|
467 |
proper way. This chapter will thus include examples using both different |
|
dvander@2518
|
468 |
versions of HTTP POST that libcurl supports. |
|
dvander@2518
|
469 |
|
|
dvander@2518
|
470 |
The first version is the simple POST, the most common version, that most HTML |
|
dvander@2518
|
471 |
pages using the <form> tag uses. We provide a pointer to the data and tell |
|
dvander@2518
|
472 |
libcurl to post it all to the remote site: |
|
dvander@2518
|
473 |
|
|
dvander@2518
|
474 |
.nf |
|
dvander@2518
|
475 |
char *data="name=daniel&project=curl"; |
|
dvander@2518
|
476 |
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data); |
|
dvander@2518
|
477 |
curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/"); |
|
dvander@2518
|
478 |
|
|
dvander@2518
|
479 |
curl_easy_perform(easyhandle); /* post away! */ |
|
dvander@2518
|
480 |
.fi |
|
dvander@2518
|
481 |
|
|
dvander@2518
|
482 |
Simple enough, huh? Since you set the POST options with the |
|
dvander@2518
|
483 |
CURLOPT_POSTFIELDS, this automatically switches the handle to use POST in the |
|
dvander@2518
|
484 |
upcoming request. |
|
dvander@2518
|
485 |
|
|
dvander@2518
|
486 |
Ok, so what if you want to post binary data that also requires you to set the |
|
asherkin@3839
|
487 |
Content-Type: header of the post? Well, binary posts prevent libcurl from |
|
dvander@2518
|
488 |
being able to do strlen() on the data to figure out the size, so therefore we |
|
dvander@2518
|
489 |
must tell libcurl the size of the post data. Setting headers in libcurl |
|
dvander@2518
|
490 |
requests are done in a generic way, by building a list of our own headers and |
|
dvander@2518
|
491 |
then passing that list to libcurl. |
|
dvander@2518
|
492 |
|
|
dvander@2518
|
493 |
.nf |
|
dvander@2518
|
494 |
struct curl_slist *headers=NULL; |
|
dvander@2518
|
495 |
headers = curl_slist_append(headers, "Content-Type: text/xml"); |
|
dvander@2518
|
496 |
|
|
dvander@2518
|
497 |
/* post binary data */ |
|
dvander@2518
|
498 |
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, binaryptr); |
|
dvander@2518
|
499 |
|
|
dvander@2518
|
500 |
/* set the size of the postfields data */ |
|
dvander@2518
|
501 |
curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDSIZE, 23L); |
|
dvander@2518
|
502 |
|
|
dvander@2518
|
503 |
/* pass our list of custom made headers */ |
|
dvander@2518
|
504 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); |
|
dvander@2518
|
505 |
|
|
dvander@2518
|
506 |
curl_easy_perform(easyhandle); /* post away! */ |
|
dvander@2518
|
507 |
|
|
dvander@2518
|
508 |
curl_slist_free_all(headers); /* free the header list */ |
|
dvander@2518
|
509 |
.fi |
|
dvander@2518
|
510 |
|
|
dvander@2518
|
511 |
While the simple examples above cover the majority of all cases where HTTP |
|
dvander@2518
|
512 |
POST operations are required, they don't do multi-part formposts. Multi-part |
|
dvander@2518
|
513 |
formposts were introduced as a better way to post (possibly large) binary data |
|
asherkin@3839
|
514 |
and were first documented in the RFC1867 (updated in RFC2388). They're called |
|
asherkin@3839
|
515 |
multi-part because they're built by a chain of parts, each part being a single |
|
asherkin@3839
|
516 |
unit of data. Each part has its own name and contents. You can in fact create |
|
asherkin@3839
|
517 |
and post a multi-part formpost with the regular libcurl POST support described |
|
asherkin@3839
|
518 |
above, but that would require that you build a formpost yourself and provide |
|
asherkin@3839
|
519 |
to libcurl. To make that easier, libcurl provides \fIcurl_formadd(3)\fP. Using |
|
asherkin@3839
|
520 |
this function, you add parts to the form. When you're done adding parts, you |
|
asherkin@3839
|
521 |
post the whole form. |
|
dvander@2518
|
522 |
|
|
dvander@2518
|
523 |
The following example sets two simple text parts with plain textual contents, |
|
asherkin@3839
|
524 |
and then a file with binary contents and uploads the whole thing. |
|
dvander@2518
|
525 |
|
|
dvander@2518
|
526 |
.nf |
|
dvander@2518
|
527 |
struct curl_httppost *post=NULL; |
|
dvander@2518
|
528 |
struct curl_httppost *last=NULL; |
|
dvander@2518
|
529 |
curl_formadd(&post, &last, |
|
dvander@2518
|
530 |
CURLFORM_COPYNAME, "name", |
|
dvander@2518
|
531 |
CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); |
|
dvander@2518
|
532 |
curl_formadd(&post, &last, |
|
dvander@2518
|
533 |
CURLFORM_COPYNAME, "project", |
|
dvander@2518
|
534 |
CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); |
|
dvander@2518
|
535 |
curl_formadd(&post, &last, |
|
dvander@2518
|
536 |
CURLFORM_COPYNAME, "logotype-image", |
|
dvander@2518
|
537 |
CURLFORM_FILECONTENT, "curl.png", CURLFORM_END); |
|
dvander@2518
|
538 |
|
|
dvander@2518
|
539 |
/* Set the form info */ |
|
dvander@2518
|
540 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPPOST, post); |
|
dvander@2518
|
541 |
|
|
dvander@2518
|
542 |
curl_easy_perform(easyhandle); /* post away! */ |
|
dvander@2518
|
543 |
|
|
dvander@2518
|
544 |
/* free the post data again */ |
|
dvander@2518
|
545 |
curl_formfree(post); |
|
dvander@2518
|
546 |
.fi |
|
dvander@2518
|
547 |
|
|
dvander@2518
|
548 |
Multipart formposts are chains of parts using MIME-style separators and |
|
dvander@2518
|
549 |
headers. It means that each one of these separate parts get a few headers set |
|
dvander@2518
|
550 |
that describe the individual content-type, size etc. To enable your |
|
dvander@2518
|
551 |
application to handicraft this formpost even more, libcurl allows you to |
|
dvander@2518
|
552 |
supply your own set of custom headers to such an individual form part. You can |
|
asherkin@3839
|
553 |
of course supply headers to as many parts as you like, but this little example |
|
dvander@2518
|
554 |
will show how you set headers to one specific part when you add that to the |
|
dvander@2518
|
555 |
post handle: |
|
dvander@2518
|
556 |
|
|
dvander@2518
|
557 |
.nf |
|
dvander@2518
|
558 |
struct curl_slist *headers=NULL; |
|
dvander@2518
|
559 |
headers = curl_slist_append(headers, "Content-Type: text/xml"); |
|
dvander@2518
|
560 |
|
|
dvander@2518
|
561 |
curl_formadd(&post, &last, |
|
dvander@2518
|
562 |
CURLFORM_COPYNAME, "logotype-image", |
|
dvander@2518
|
563 |
CURLFORM_FILECONTENT, "curl.xml", |
|
dvander@2518
|
564 |
CURLFORM_CONTENTHEADER, headers, |
|
dvander@2518
|
565 |
CURLFORM_END); |
|
dvander@2518
|
566 |
|
|
dvander@2518
|
567 |
curl_easy_perform(easyhandle); /* post away! */ |
|
dvander@2518
|
568 |
|
|
dvander@2518
|
569 |
curl_formfree(post); /* free post */ |
|
asherkin@3839
|
570 |
curl_slist_free_all(headers); /* free custom header list */ |
|
dvander@2518
|
571 |
.fi |
|
dvander@2518
|
572 |
|
|
dvander@2518
|
573 |
Since all options on an easyhandle are "sticky", they remain the same until |
|
dvander@2518
|
574 |
changed even if you do call \fIcurl_easy_perform(3)\fP, you may need to tell |
|
asherkin@3839
|
575 |
curl to go back to a plain GET request if you intend to do one as your |
|
asherkin@3839
|
576 |
next request. You force an easyhandle to go back to GET by using the |
|
dvander@2518
|
577 |
CURLOPT_HTTPGET option: |
|
dvander@2518
|
578 |
|
|
dvander@2518
|
579 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPGET, 1L); |
|
dvander@2518
|
580 |
|
|
dvander@2518
|
581 |
Just setting CURLOPT_POSTFIELDS to "" or NULL will *not* stop libcurl from |
|
dvander@2518
|
582 |
doing a POST. It will just make it POST without any data to send! |
|
dvander@2518
|
583 |
|
|
dvander@2518
|
584 |
.SH "Showing Progress" |
|
dvander@2518
|
585 |
|
|
dvander@2518
|
586 |
For historical and traditional reasons, libcurl has a built-in progress meter |
|
asherkin@3839
|
587 |
that can be switched on and then makes it present a progress meter in your |
|
dvander@2518
|
588 |
terminal. |
|
dvander@2518
|
589 |
|
|
asherkin@3839
|
590 |
Switch on the progress meter by, oddly enough, setting CURLOPT_NOPROGRESS to |
|
dvander@2518
|
591 |
zero. This option is set to 1 by default. |
|
dvander@2518
|
592 |
|
|
dvander@2518
|
593 |
For most applications however, the built-in progress meter is useless and |
|
dvander@2518
|
594 |
what instead is interesting is the ability to specify a progress |
|
dvander@2518
|
595 |
callback. The function pointer you pass to libcurl will then be called on |
|
dvander@2518
|
596 |
irregular intervals with information about the current transfer. |
|
dvander@2518
|
597 |
|
|
dvander@2518
|
598 |
Set the progress callback by using CURLOPT_PROGRESSFUNCTION. And pass a |
|
dvander@2518
|
599 |
pointer to a function that matches this prototype: |
|
dvander@2518
|
600 |
|
|
dvander@2518
|
601 |
.nf |
|
dvander@2518
|
602 |
int progress_callback(void *clientp, |
|
dvander@2518
|
603 |
double dltotal, |
|
dvander@2518
|
604 |
double dlnow, |
|
dvander@2518
|
605 |
double ultotal, |
|
dvander@2518
|
606 |
double ulnow); |
|
dvander@2518
|
607 |
.fi |
|
dvander@2518
|
608 |
|
|
dvander@2518
|
609 |
If any of the input arguments is unknown, a 0 will be passed. The first |
|
dvander@2518
|
610 |
argument, the 'clientp' is the pointer you pass to libcurl with |
|
dvander@2518
|
611 |
CURLOPT_PROGRESSDATA. libcurl won't touch it. |
|
dvander@2518
|
612 |
|
|
dvander@2518
|
613 |
.SH "libcurl with C++" |
|
dvander@2518
|
614 |
|
|
dvander@2518
|
615 |
There's basically only one thing to keep in mind when using C++ instead of C |
|
dvander@2518
|
616 |
when interfacing libcurl: |
|
dvander@2518
|
617 |
|
|
dvander@2518
|
618 |
The callbacks CANNOT be non-static class member functions |
|
dvander@2518
|
619 |
|
|
dvander@2518
|
620 |
Example C++ code: |
|
dvander@2518
|
621 |
|
|
dvander@2518
|
622 |
.nf |
|
dvander@2518
|
623 |
class AClass { |
|
dvander@2518
|
624 |
static size_t write_data(void *ptr, size_t size, size_t nmemb, |
|
dvander@2518
|
625 |
void *ourpointer) |
|
dvander@2518
|
626 |
{ |
|
dvander@2518
|
627 |
/* do what you want with the data */ |
|
dvander@2518
|
628 |
} |
|
dvander@2518
|
629 |
} |
|
dvander@2518
|
630 |
.fi |
|
dvander@2518
|
631 |
|
|
dvander@2518
|
632 |
.SH "Proxies" |
|
dvander@2518
|
633 |
|
|
dvander@2518
|
634 |
What "proxy" means according to Merriam-Webster: "a person authorized to act |
|
dvander@2518
|
635 |
for another" but also "the agency, function, or office of a deputy who acts as |
|
dvander@2518
|
636 |
a substitute for another". |
|
dvander@2518
|
637 |
|
|
dvander@2518
|
638 |
Proxies are exceedingly common these days. Companies often only offer Internet |
|
dvander@2518
|
639 |
access to employees through their proxies. Network clients or user-agents ask |
|
dvander@2518
|
640 |
the proxy for documents, the proxy does the actual request and then it returns |
|
dvander@2518
|
641 |
them. |
|
dvander@2518
|
642 |
|
|
dvander@2518
|
643 |
libcurl supports SOCKS and HTTP proxies. When a given URL is wanted, libcurl |
|
dvander@2518
|
644 |
will ask the proxy for it instead of trying to connect to the actual host |
|
dvander@2518
|
645 |
identified in the URL. |
|
dvander@2518
|
646 |
|
|
dvander@2518
|
647 |
If you're using a SOCKS proxy, you may find that libcurl doesn't quite support |
|
dvander@2518
|
648 |
all operations through it. |
|
dvander@2518
|
649 |
|
|
dvander@2518
|
650 |
For HTTP proxies: the fact that the proxy is a HTTP proxy puts certain |
|
dvander@2518
|
651 |
restrictions on what can actually happen. A requested URL that might not be a |
|
dvander@2518
|
652 |
HTTP URL will be still be passed to the HTTP proxy to deliver back to |
|
dvander@2518
|
653 |
libcurl. This happens transparently, and an application may not need to |
|
dvander@2518
|
654 |
know. I say "may", because at times it is very important to understand that |
|
asherkin@3839
|
655 |
all operations over a HTTP proxy use the HTTP protocol. For example, you |
|
dvander@2518
|
656 |
can't invoke your own custom FTP commands or even proper FTP directory |
|
dvander@2518
|
657 |
listings. |
|
dvander@2518
|
658 |
|
|
dvander@2518
|
659 |
.IP "Proxy Options" |
|
dvander@2518
|
660 |
|
|
dvander@2518
|
661 |
To tell libcurl to use a proxy at a given port number: |
|
dvander@2518
|
662 |
|
|
dvander@2518
|
663 |
curl_easy_setopt(easyhandle, CURLOPT_PROXY, "proxy-host.com:8080"); |
|
dvander@2518
|
664 |
|
|
dvander@2518
|
665 |
Some proxies require user authentication before allowing a request, and you |
|
dvander@2518
|
666 |
pass that information similar to this: |
|
dvander@2518
|
667 |
|
|
dvander@2518
|
668 |
curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "user:password"); |
|
dvander@2518
|
669 |
|
|
dvander@2518
|
670 |
If you want to, you can specify the host name only in the CURLOPT_PROXY |
|
dvander@2518
|
671 |
option, and set the port number separately with CURLOPT_PROXYPORT. |
|
dvander@2518
|
672 |
|
|
dvander@2518
|
673 |
Tell libcurl what kind of proxy it is with CURLOPT_PROXYTYPE (if not, it will |
|
dvander@2518
|
674 |
default to assume a HTTP proxy): |
|
dvander@2518
|
675 |
|
|
dvander@2518
|
676 |
curl_easy_setopt(easyhandle, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS4); |
|
dvander@2518
|
677 |
|
|
dvander@2518
|
678 |
.IP "Environment Variables" |
|
dvander@2518
|
679 |
|
|
asherkin@3839
|
680 |
libcurl automatically checks and uses a set of environment variables to know |
|
asherkin@3839
|
681 |
what proxies to use for certain protocols. The names of the variables are |
|
asherkin@3839
|
682 |
following an ancient de facto standard and are built up as "[protocol]_proxy" |
|
asherkin@3839
|
683 |
(note the lower casing). Which makes the variable \&'http_proxy' checked for a |
|
asherkin@3839
|
684 |
name of a proxy to use when the input URL is HTTP. Following the same rule, |
|
asherkin@3839
|
685 |
the variable named 'ftp_proxy' is checked for FTP URLs. Again, the proxies are |
|
asherkin@3839
|
686 |
always HTTP proxies, the different names of the variables simply allows |
|
asherkin@3839
|
687 |
different HTTP proxies to be used. |
|
dvander@2518
|
688 |
|
|
dvander@2518
|
689 |
The proxy environment variable contents should be in the format |
|
dvander@2518
|
690 |
\&"[protocol://][user:password@]machine[:port]". Where the protocol:// part is |
|
dvander@2518
|
691 |
simply ignored if present (so http://proxy and bluerk://proxy will do the |
|
dvander@2518
|
692 |
same) and the optional port number specifies on which port the proxy operates |
|
dvander@2518
|
693 |
on the host. If not specified, the internal default port number will be used |
|
dvander@2518
|
694 |
and that is most likely *not* the one you would like it to be. |
|
dvander@2518
|
695 |
|
|
dvander@2518
|
696 |
There are two special environment variables. 'all_proxy' is what sets proxy |
|
dvander@2518
|
697 |
for any URL in case the protocol specific variable wasn't set, and |
|
dvander@2518
|
698 |
\&'no_proxy' defines a list of hosts that should not use a proxy even though a |
|
dvander@2518
|
699 |
variable may say so. If 'no_proxy' is a plain asterisk ("*") it matches all |
|
dvander@2518
|
700 |
hosts. |
|
dvander@2518
|
701 |
|
|
dvander@2518
|
702 |
To explicitly disable libcurl's checking for and using the proxy environment |
|
dvander@2518
|
703 |
variables, set the proxy name to "" - an empty string - with CURLOPT_PROXY. |
|
dvander@2518
|
704 |
.IP "SSL and Proxies" |
|
dvander@2518
|
705 |
|
|
dvander@2518
|
706 |
SSL is for secure point-to-point connections. This involves strong encryption |
|
dvander@2518
|
707 |
and similar things, which effectively makes it impossible for a proxy to |
|
dvander@2518
|
708 |
operate as a "man in between" which the proxy's task is, as previously |
|
dvander@2518
|
709 |
discussed. Instead, the only way to have SSL work over a HTTP proxy is to ask |
|
dvander@2518
|
710 |
the proxy to tunnel trough everything without being able to check or fiddle |
|
dvander@2518
|
711 |
with the traffic. |
|
dvander@2518
|
712 |
|
|
dvander@2518
|
713 |
Opening an SSL connection over a HTTP proxy is therefor a matter of asking the |
|
dvander@2518
|
714 |
proxy for a straight connection to the target host on a specified port. This |
|
dvander@2518
|
715 |
is made with the HTTP request CONNECT. ("please mr proxy, connect me to that |
|
dvander@2518
|
716 |
remote host"). |
|
dvander@2518
|
717 |
|
|
dvander@2518
|
718 |
Because of the nature of this operation, where the proxy has no idea what kind |
|
dvander@2518
|
719 |
of data that is passed in and out through this tunnel, this breaks some of the |
|
dvander@2518
|
720 |
very few advantages that come from using a proxy, such as caching. Many |
|
dvander@2518
|
721 |
organizations prevent this kind of tunneling to other destination port numbers |
|
dvander@2518
|
722 |
than 443 (which is the default HTTPS port number). |
|
dvander@2518
|
723 |
|
|
dvander@2518
|
724 |
.IP "Tunneling Through Proxy" |
|
dvander@2518
|
725 |
As explained above, tunneling is required for SSL to work and often even |
|
dvander@2518
|
726 |
restricted to the operation intended for SSL; HTTPS. |
|
dvander@2518
|
727 |
|
|
dvander@2518
|
728 |
This is however not the only time proxy-tunneling might offer benefits to |
|
dvander@2518
|
729 |
you or your application. |
|
dvander@2518
|
730 |
|
|
dvander@2518
|
731 |
As tunneling opens a direct connection from your application to the remote |
|
dvander@2518
|
732 |
machine, it suddenly also re-introduces the ability to do non-HTTP |
|
dvander@2518
|
733 |
operations over a HTTP proxy. You can in fact use things such as FTP |
|
dvander@2518
|
734 |
upload or FTP custom commands this way. |
|
dvander@2518
|
735 |
|
|
dvander@2518
|
736 |
Again, this is often prevented by the administrators of proxies and is |
|
dvander@2518
|
737 |
rarely allowed. |
|
dvander@2518
|
738 |
|
|
dvander@2518
|
739 |
Tell libcurl to use proxy tunneling like this: |
|
dvander@2518
|
740 |
|
|
dvander@2518
|
741 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPPROXYTUNNEL, 1L); |
|
dvander@2518
|
742 |
|
|
dvander@2518
|
743 |
In fact, there might even be times when you want to do plain HTTP |
|
dvander@2518
|
744 |
operations using a tunnel like this, as it then enables you to operate on |
|
dvander@2518
|
745 |
the remote server instead of asking the proxy to do so. libcurl will not |
|
dvander@2518
|
746 |
stand in the way for such innovative actions either! |
|
dvander@2518
|
747 |
|
|
dvander@2518
|
748 |
.IP "Proxy Auto-Config" |
|
dvander@2518
|
749 |
|
|
dvander@2518
|
750 |
Netscape first came up with this. It is basically a web page (usually using a |
|
asherkin@3839
|
751 |
\&.pac extension) with a Javascript that when executed by the browser with the |
|
dvander@2518
|
752 |
requested URL as input, returns information to the browser on how to connect |
|
dvander@2518
|
753 |
to the URL. The returned information might be "DIRECT" (which means no proxy |
|
dvander@2518
|
754 |
should be used), "PROXY host:port" (to tell the browser where the proxy for |
|
dvander@2518
|
755 |
this particular URL is) or "SOCKS host:port" (to direct the browser to a SOCKS |
|
dvander@2518
|
756 |
proxy). |
|
dvander@2518
|
757 |
|
|
asherkin@3839
|
758 |
libcurl has no means to interpret or evaluate Javascript and thus it doesn't |
|
dvander@2518
|
759 |
support this. If you get yourself in a position where you face this nasty |
|
dvander@2518
|
760 |
invention, the following advice have been mentioned and used in the past: |
|
dvander@2518
|
761 |
|
|
asherkin@3839
|
762 |
- Depending on the Javascript complexity, write up a script that translates it |
|
dvander@2518
|
763 |
to another language and execute that. |
|
dvander@2518
|
764 |
|
|
asherkin@3839
|
765 |
- Read the Javascript code and rewrite the same logic in another language. |
|
dvander@2518
|
766 |
|
|
asherkin@3839
|
767 |
- Implement a Javascript interpreter; people have successfully used the |
|
asherkin@3839
|
768 |
Mozilla Javascript engine in the past. |
|
dvander@2518
|
769 |
|
|
dvander@2518
|
770 |
- Ask your admins to stop this, for a static proxy setup or similar. |
|
dvander@2518
|
771 |
|
|
dvander@2518
|
772 |
.SH "Persistence Is The Way to Happiness" |
|
dvander@2518
|
773 |
|
|
dvander@2518
|
774 |
Re-cycling the same easy handle several times when doing multiple requests is |
|
dvander@2518
|
775 |
the way to go. |
|
dvander@2518
|
776 |
|
|
dvander@2518
|
777 |
After each single \fIcurl_easy_perform(3)\fP operation, libcurl will keep the |
|
dvander@2518
|
778 |
connection alive and open. A subsequent request using the same easy handle to |
|
dvander@2518
|
779 |
the same host might just be able to use the already open connection! This |
|
dvander@2518
|
780 |
reduces network impact a lot. |
|
dvander@2518
|
781 |
|
|
dvander@2518
|
782 |
Even if the connection is dropped, all connections involving SSL to the same |
|
dvander@2518
|
783 |
host again, will benefit from libcurl's session ID cache that drastically |
|
dvander@2518
|
784 |
reduces re-connection time. |
|
dvander@2518
|
785 |
|
|
asherkin@3839
|
786 |
FTP connections that are kept alive save a lot of time, as the command- |
|
dvander@2518
|
787 |
response round-trips are skipped, and also you don't risk getting blocked |
|
dvander@2518
|
788 |
without permission to login again like on many FTP servers only allowing N |
|
dvander@2518
|
789 |
persons to be logged in at the same time. |
|
dvander@2518
|
790 |
|
|
dvander@2518
|
791 |
libcurl caches DNS name resolving results, to make lookups of a previously |
|
dvander@2518
|
792 |
looked up name a lot faster. |
|
dvander@2518
|
793 |
|
|
dvander@2518
|
794 |
Other interesting details that improve performance for subsequent requests |
|
dvander@2518
|
795 |
may also be added in the future. |
|
dvander@2518
|
796 |
|
|
dvander@2518
|
797 |
Each easy handle will attempt to keep the last few connections alive for a |
|
dvander@2518
|
798 |
while in case they are to be used again. You can set the size of this "cache" |
|
asherkin@3839
|
799 |
with the CURLOPT_MAXCONNECTS option. Default is 5. There is very seldom any |
|
dvander@2518
|
800 |
point in changing this value, and if you think of changing this it is often |
|
dvander@2518
|
801 |
just a matter of thinking again. |
|
dvander@2518
|
802 |
|
|
dvander@2518
|
803 |
To force your upcoming request to not use an already existing connection (it |
|
dvander@2518
|
804 |
will even close one first if there happens to be one alive to the same host |
|
dvander@2518
|
805 |
you're about to operate on), you can do that by setting CURLOPT_FRESH_CONNECT |
|
dvander@2518
|
806 |
to 1. In a similar spirit, you can also forbid the upcoming request to be |
|
dvander@2518
|
807 |
"lying" around and possibly get re-used after the request by setting |
|
dvander@2518
|
808 |
CURLOPT_FORBID_REUSE to 1. |
|
dvander@2518
|
809 |
|
|
dvander@2518
|
810 |
.SH "HTTP Headers Used by libcurl" |
|
dvander@2518
|
811 |
When you use libcurl to do HTTP requests, it'll pass along a series of headers |
|
asherkin@3839
|
812 |
automatically. It might be good for you to know and understand these. You |
|
dvander@2518
|
813 |
can replace or remove them by using the CURLOPT_HTTPHEADER option. |
|
dvander@2518
|
814 |
|
|
dvander@2518
|
815 |
.IP "Host" |
|
dvander@2518
|
816 |
This header is required by HTTP 1.1 and even many 1.0 servers and should be |
|
dvander@2518
|
817 |
the name of the server we want to talk to. This includes the port number if |
|
dvander@2518
|
818 |
anything but default. |
|
dvander@2518
|
819 |
|
|
dvander@2518
|
820 |
.IP "Accept" |
|
dvander@2518
|
821 |
\&"*/*". |
|
dvander@2518
|
822 |
|
|
dvander@2518
|
823 |
.IP "Expect" |
|
dvander@2518
|
824 |
When doing POST requests, libcurl sets this header to \&"100-continue" to ask |
|
dvander@2518
|
825 |
the server for an "OK" message before it proceeds with sending the data part |
|
dvander@2518
|
826 |
of the post. If the POSTed data amount is deemed "small", libcurl will not use |
|
dvander@2518
|
827 |
this header. |
|
dvander@2518
|
828 |
|
|
dvander@2518
|
829 |
.SH "Customizing Operations" |
|
dvander@2518
|
830 |
There is an ongoing development today where more and more protocols are built |
|
dvander@2518
|
831 |
upon HTTP for transport. This has obvious benefits as HTTP is a tested and |
|
asherkin@3839
|
832 |
reliable protocol that is widely deployed and has excellent proxy-support. |
|
dvander@2518
|
833 |
|
|
dvander@2518
|
834 |
When you use one of these protocols, and even when doing other kinds of |
|
dvander@2518
|
835 |
programming you may need to change the traditional HTTP (or FTP or...) |
|
dvander@2518
|
836 |
manners. You may need to change words, headers or various data. |
|
dvander@2518
|
837 |
|
|
dvander@2518
|
838 |
libcurl is your friend here too. |
|
dvander@2518
|
839 |
|
|
dvander@2518
|
840 |
.IP CUSTOMREQUEST |
|
dvander@2518
|
841 |
If just changing the actual HTTP request keyword is what you want, like when |
|
dvander@2518
|
842 |
GET, HEAD or POST is not good enough for you, CURLOPT_CUSTOMREQUEST is there |
|
dvander@2518
|
843 |
for you. It is very simple to use: |
|
dvander@2518
|
844 |
|
|
asherkin@3839
|
845 |
curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "MYOWNREQUEST"); |
|
dvander@2518
|
846 |
|
|
dvander@2518
|
847 |
When using the custom request, you change the request keyword of the actual |
|
asherkin@3839
|
848 |
request you are performing. Thus, by default you make a GET request but you can |
|
dvander@2518
|
849 |
also make a POST operation (as described before) and then replace the POST |
|
dvander@2518
|
850 |
keyword if you want to. You're the boss. |
|
dvander@2518
|
851 |
|
|
dvander@2518
|
852 |
.IP "Modify Headers" |
|
dvander@2518
|
853 |
HTTP-like protocols pass a series of headers to the server when doing the |
|
dvander@2518
|
854 |
request, and you're free to pass any amount of extra headers that you |
|
asherkin@3839
|
855 |
think fit. Adding headers is this easy: |
|
dvander@2518
|
856 |
|
|
dvander@2518
|
857 |
.nf |
|
dvander@2518
|
858 |
struct curl_slist *headers=NULL; /* init to NULL is important */ |
|
dvander@2518
|
859 |
|
|
dvander@2518
|
860 |
headers = curl_slist_append(headers, "Hey-server-hey: how are you?"); |
|
dvander@2518
|
861 |
headers = curl_slist_append(headers, "X-silly-content: yes"); |
|
dvander@2518
|
862 |
|
|
dvander@2518
|
863 |
/* pass our list of custom made headers */ |
|
dvander@2518
|
864 |
curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); |
|
dvander@2518
|
865 |
|
|
dvander@2518
|
866 |
curl_easy_perform(easyhandle); /* transfer http */ |
|
dvander@2518
|
867 |
|
|
dvander@2518
|
868 |
curl_slist_free_all(headers); /* free the header list */ |
|
dvander@2518
|
869 |
.fi |
|
dvander@2518
|
870 |
|
|
dvander@2518
|
871 |
\&... and if you think some of the internally generated headers, such as |
|
dvander@2518
|
872 |
Accept: or Host: don't contain the data you want them to contain, you can |
|
dvander@2518
|
873 |
replace them by simply setting them too: |
|
dvander@2518
|
874 |
|
|
dvander@2518
|
875 |
.nf |
|
dvander@2518
|
876 |
headers = curl_slist_append(headers, "Accept: Agent-007"); |
|
dvander@2518
|
877 |
headers = curl_slist_append(headers, "Host: munged.host.line"); |
|
dvander@2518
|
878 |
.fi |
|
dvander@2518
|
879 |
|
|
dvander@2518
|
880 |
.IP "Delete Headers" |
|
dvander@2518
|
881 |
If you replace an existing header with one with no contents, you will prevent |
|
asherkin@3839
|
882 |
the header from being sent. For instance, if you want to completely prevent the |
|
asherkin@3839
|
883 |
\&"Accept:" header from being sent, you can disable it with code similar to this: |
|
dvander@2518
|
884 |
|
|
dvander@2518
|
885 |
headers = curl_slist_append(headers, "Accept:"); |
|
dvander@2518
|
886 |
|
|
dvander@2518
|
887 |
Both replacing and canceling internal headers should be done with careful |
|
dvander@2518
|
888 |
consideration and you should be aware that you may violate the HTTP protocol |
|
dvander@2518
|
889 |
when doing so. |
|
dvander@2518
|
890 |
|
|
dvander@2518
|
891 |
.IP "Enforcing chunked transfer-encoding" |
|
dvander@2518
|
892 |
|
|
dvander@2518
|
893 |
By making sure a request uses the custom header "Transfer-Encoding: chunked" |
|
dvander@2518
|
894 |
when doing a non-GET HTTP operation, libcurl will switch over to "chunked" |
|
dvander@2518
|
895 |
upload, even though the size of the data to upload might be known. By default, |
|
dvander@2518
|
896 |
libcurl usually switches over to chunked upload automatically if the upload |
|
dvander@2518
|
897 |
data size is unknown. |
|
dvander@2518
|
898 |
|
|
dvander@2518
|
899 |
.IP "HTTP Version" |
|
dvander@2518
|
900 |
|
|
dvander@2518
|
901 |
All HTTP requests includes the version number to tell the server which version |
|
asherkin@3839
|
902 |
we support. libcurl speaks HTTP 1.1 by default. Some very old servers don't |
|
dvander@2518
|
903 |
like getting 1.1-requests and when dealing with stubborn old things like that, |
|
dvander@2518
|
904 |
you can tell libcurl to use 1.0 instead by doing something like this: |
|
dvander@2518
|
905 |
|
|
dvander@2518
|
906 |
curl_easy_setopt(easyhandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0); |
|
dvander@2518
|
907 |
|
|
dvander@2518
|
908 |
.IP "FTP Custom Commands" |
|
dvander@2518
|
909 |
|
|
dvander@2518
|
910 |
Not all protocols are HTTP-like, and thus the above may not help you when |
|
asherkin@3839
|
911 |
you want to make, for example, your FTP transfers to behave differently. |
|
dvander@2518
|
912 |
|
|
dvander@2518
|
913 |
Sending custom commands to a FTP server means that you need to send the |
|
dvander@2518
|
914 |
commands exactly as the FTP server expects them (RFC959 is a good guide |
|
dvander@2518
|
915 |
here), and you can only use commands that work on the control-connection |
|
asherkin@3839
|
916 |
alone. All kinds of commands that require data interchange and thus need |
|
asherkin@3839
|
917 |
a data-connection must be left to libcurl's own judgement. Also be aware |
|
dvander@2518
|
918 |
that libcurl will do its very best to change directory to the target |
|
dvander@2518
|
919 |
directory before doing any transfer, so if you change directory (with CWD |
|
dvander@2518
|
920 |
or similar) you might confuse libcurl and then it might not attempt to |
|
dvander@2518
|
921 |
transfer the file in the correct remote directory. |
|
dvander@2518
|
922 |
|
|
dvander@2518
|
923 |
A little example that deletes a given file before an operation: |
|
dvander@2518
|
924 |
|
|
dvander@2518
|
925 |
.nf |
|
dvander@2518
|
926 |
headers = curl_slist_append(headers, "DELE file-to-remove"); |
|
dvander@2518
|
927 |
|
|
dvander@2518
|
928 |
/* pass the list of custom commands to the handle */ |
|
dvander@2518
|
929 |
curl_easy_setopt(easyhandle, CURLOPT_QUOTE, headers); |
|
dvander@2518
|
930 |
|
|
dvander@2518
|
931 |
curl_easy_perform(easyhandle); /* transfer ftp data! */ |
|
dvander@2518
|
932 |
|
|
dvander@2518
|
933 |
curl_slist_free_all(headers); /* free the header list */ |
|
dvander@2518
|
934 |
.fi |
|
dvander@2518
|
935 |
|
|
dvander@2518
|
936 |
If you would instead want this operation (or chain of operations) to happen |
|
dvander@2518
|
937 |
_after_ the data transfer took place the option to \fIcurl_easy_setopt(3)\fP |
|
dvander@2518
|
938 |
would instead be called CURLOPT_POSTQUOTE and used the exact same way. |
|
dvander@2518
|
939 |
|
|
dvander@2518
|
940 |
The custom FTP command will be issued to the server in the same order they are |
|
dvander@2518
|
941 |
added to the list, and if a command gets an error code returned back from the |
|
dvander@2518
|
942 |
server, no more commands will be issued and libcurl will bail out with an |
|
dvander@2518
|
943 |
error code (CURLE_QUOTE_ERROR). Note that if you use CURLOPT_QUOTE to send |
|
dvander@2518
|
944 |
commands before a transfer, no transfer will actually take place when a quote |
|
dvander@2518
|
945 |
command has failed. |
|
dvander@2518
|
946 |
|
|
dvander@2518
|
947 |
If you set the CURLOPT_HEADER to 1, you will tell libcurl to get |
|
dvander@2518
|
948 |
information about the target file and output "headers" about it. The headers |
|
dvander@2518
|
949 |
will be in "HTTP-style", looking like they do in HTTP. |
|
dvander@2518
|
950 |
|
|
dvander@2518
|
951 |
The option to enable headers or to run custom FTP commands may be useful to |
|
dvander@2518
|
952 |
combine with CURLOPT_NOBODY. If this option is set, no actual file content |
|
dvander@2518
|
953 |
transfer will be performed. |
|
dvander@2518
|
954 |
|
|
dvander@2518
|
955 |
.IP "FTP Custom CUSTOMREQUEST" |
|
asherkin@3839
|
956 |
If you do want to list the contents of a FTP directory using your own defined FTP |
|
dvander@2518
|
957 |
command, CURLOPT_CUSTOMREQUEST will do just that. "NLST" is the default one |
|
dvander@2518
|
958 |
for listing directories but you're free to pass in your idea of a good |
|
dvander@2518
|
959 |
alternative. |
|
dvander@2518
|
960 |
|
|
dvander@2518
|
961 |
.SH "Cookies Without Chocolate Chips" |
|
dvander@2518
|
962 |
In the HTTP sense, a cookie is a name with an associated value. A server sends |
|
dvander@2518
|
963 |
the name and value to the client, and expects it to get sent back on every |
|
dvander@2518
|
964 |
subsequent request to the server that matches the particular conditions |
|
dvander@2518
|
965 |
set. The conditions include that the domain name and path match and that the |
|
dvander@2518
|
966 |
cookie hasn't become too old. |
|
dvander@2518
|
967 |
|
|
asherkin@3839
|
968 |
In real-world cases, servers send new cookies to replace existing ones to |
|
dvander@2518
|
969 |
update them. Server use cookies to "track" users and to keep "sessions". |
|
dvander@2518
|
970 |
|
|
dvander@2518
|
971 |
Cookies are sent from server to clients with the header Set-Cookie: and |
|
dvander@2518
|
972 |
they're sent from clients to servers with the Cookie: header. |
|
dvander@2518
|
973 |
|
|
dvander@2518
|
974 |
To just send whatever cookie you want to a server, you can use CURLOPT_COOKIE |
|
dvander@2518
|
975 |
to set a cookie string like this: |
|
dvander@2518
|
976 |
|
|
dvander@2518
|
977 |
curl_easy_setopt(easyhandle, CURLOPT_COOKIE, "name1=var1; name2=var2;"); |
|
dvander@2518
|
978 |
|
|
dvander@2518
|
979 |
In many cases, that is not enough. You might want to dynamically save |
|
dvander@2518
|
980 |
whatever cookies the remote server passes to you, and make sure those cookies |
|
asherkin@3839
|
981 |
are then used accordingly on later requests. |
|
dvander@2518
|
982 |
|
|
dvander@2518
|
983 |
One way to do this, is to save all headers you receive in a plain file and |
|
dvander@2518
|
984 |
when you make a request, you tell libcurl to read the previous headers to |
|
asherkin@3839
|
985 |
figure out which cookies to use. Set the header file to read cookies from with |
|
dvander@2518
|
986 |
CURLOPT_COOKIEFILE. |
|
dvander@2518
|
987 |
|
|
dvander@2518
|
988 |
The CURLOPT_COOKIEFILE option also automatically enables the cookie parser in |
|
dvander@2518
|
989 |
libcurl. Until the cookie parser is enabled, libcurl will not parse or |
|
dvander@2518
|
990 |
understand incoming cookies and they will just be ignored. However, when the |
|
dvander@2518
|
991 |
parser is enabled the cookies will be understood and the cookies will be kept |
|
dvander@2518
|
992 |
in memory and used properly in subsequent requests when the same handle is |
|
dvander@2518
|
993 |
used. Many times this is enough, and you may not have to save the cookies to |
|
asherkin@3839
|
994 |
disk at all. Note that the file you specify to CURLOPT_COOKIEFILE doesn't have |
|
asherkin@3839
|
995 |
to exist to enable the parser, so a common way to just enable the parser and |
|
asherkin@3839
|
996 |
not read any cookies is to use the name of a file you know doesn't exist. |
|
dvander@2518
|
997 |
|
|
asherkin@3839
|
998 |
If you would rather use existing cookies that you've previously received with |
|
asherkin@3839
|
999 |
your Netscape or Mozilla browsers, you can make libcurl use that cookie file |
|
asherkin@3839
|
1000 |
as input. The CURLOPT_COOKIEFILE is used for that too, as libcurl will |
|
dvander@2518
|
1001 |
automatically find out what kind of file it is and act accordingly. |
|
dvander@2518
|
1002 |
|
|
asherkin@3839
|
1003 |
Perhaps the most advanced cookie operation libcurl offers, is saving the |
|
dvander@2518
|
1004 |
entire internal cookie state back into a Netscape/Mozilla formatted cookie |
|
dvander@2518
|
1005 |
file. We call that the cookie-jar. When you set a file name with |
|
dvander@2518
|
1006 |
CURLOPT_COOKIEJAR, that file name will be created and all received cookies |
|
asherkin@3839
|
1007 |
will be stored in it when \fIcurl_easy_cleanup(3)\fP is called. This enables |
|
dvander@2518
|
1008 |
cookies to get passed on properly between multiple handles without any |
|
dvander@2518
|
1009 |
information getting lost. |
|
dvander@2518
|
1010 |
|
|
dvander@2518
|
1011 |
.SH "FTP Peculiarities We Need" |
|
dvander@2518
|
1012 |
|
|
dvander@2518
|
1013 |
FTP transfers use a second TCP/IP connection for the data transfer. This is |
|
dvander@2518
|
1014 |
usually a fact you can forget and ignore but at times this fact will come |
|
asherkin@3839
|
1015 |
back to haunt you. libcurl offers several different ways to customize how the |
|
dvander@2518
|
1016 |
second connection is being made. |
|
dvander@2518
|
1017 |
|
|
dvander@2518
|
1018 |
libcurl can either connect to the server a second time or tell the server to |
|
dvander@2518
|
1019 |
connect back to it. The first option is the default and it is also what works |
|
dvander@2518
|
1020 |
best for all the people behind firewalls, NATs or IP-masquerading setups. |
|
dvander@2518
|
1021 |
libcurl then tells the server to open up a new port and wait for a second |
|
dvander@2518
|
1022 |
connection. This is by default attempted with EPSV first, and if that doesn't |
|
dvander@2518
|
1023 |
work it tries PASV instead. (EPSV is an extension to the original FTP spec |
|
dvander@2518
|
1024 |
and does not exist nor work on all FTP servers.) |
|
dvander@2518
|
1025 |
|
|
dvander@2518
|
1026 |
You can prevent libcurl from first trying the EPSV command by setting |
|
dvander@2518
|
1027 |
CURLOPT_FTP_USE_EPSV to zero. |
|
dvander@2518
|
1028 |
|
|
dvander@2518
|
1029 |
In some cases, you will prefer to have the server connect back to you for the |
|
dvander@2518
|
1030 |
second connection. This might be when the server is perhaps behind a firewall |
|
dvander@2518
|
1031 |
or something and only allows connections on a single port. libcurl then |
|
dvander@2518
|
1032 |
informs the remote server which IP address and port number to connect to. |
|
dvander@2518
|
1033 |
This is made with the CURLOPT_FTPPORT option. If you set it to "-", libcurl |
|
dvander@2518
|
1034 |
will use your system's "default IP address". If you want to use a particular |
|
dvander@2518
|
1035 |
IP, you can set the full IP address, a host name to resolve to an IP address |
|
dvander@2518
|
1036 |
or even a local network interface name that libcurl will get the IP address |
|
dvander@2518
|
1037 |
from. |
|
dvander@2518
|
1038 |
|
|
dvander@2518
|
1039 |
When doing the "PORT" approach, libcurl will attempt to use the EPRT and the |
|
dvander@2518
|
1040 |
LPRT before trying PORT, as they work with more protocols. You can disable |
|
dvander@2518
|
1041 |
this behavior by setting CURLOPT_FTP_USE_EPRT to zero. |
|
dvander@2518
|
1042 |
|
|
dvander@2518
|
1043 |
.SH "Headers Equal Fun" |
|
dvander@2518
|
1044 |
|
|
dvander@2518
|
1045 |
Some protocols provide "headers", meta-data separated from the normal |
|
dvander@2518
|
1046 |
data. These headers are by default not included in the normal data stream, |
|
dvander@2518
|
1047 |
but you can make them appear in the data stream by setting CURLOPT_HEADER to |
|
dvander@2518
|
1048 |
1. |
|
dvander@2518
|
1049 |
|
|
dvander@2518
|
1050 |
What might be even more useful, is libcurl's ability to separate the headers |
|
dvander@2518
|
1051 |
from the data and thus make the callbacks differ. You can for example set a |
|
dvander@2518
|
1052 |
different pointer to pass to the ordinary write callback by setting |
|
dvander@2518
|
1053 |
CURLOPT_WRITEHEADER. |
|
dvander@2518
|
1054 |
|
|
dvander@2518
|
1055 |
Or, you can set an entirely separate function to receive the headers, by |
|
dvander@2518
|
1056 |
using CURLOPT_HEADERFUNCTION. |
|
dvander@2518
|
1057 |
|
|
dvander@2518
|
1058 |
The headers are passed to the callback function one by one, and you can |
|
dvander@2518
|
1059 |
depend on that fact. It makes it easier for you to add custom header parsers |
|
dvander@2518
|
1060 |
etc. |
|
dvander@2518
|
1061 |
|
|
dvander@2518
|
1062 |
\&"Headers" for FTP transfers equal all the FTP server responses. They aren't |
|
dvander@2518
|
1063 |
actually true headers, but in this case we pretend they are! ;-) |
|
dvander@2518
|
1064 |
|
|
dvander@2518
|
1065 |
.SH "Post Transfer Information" |
|
dvander@2518
|
1066 |
|
|
dvander@2518
|
1067 |
[ curl_easy_getinfo ] |
|
dvander@2518
|
1068 |
|
|
dvander@2518
|
1069 |
.SH "Security Considerations" |
|
dvander@2518
|
1070 |
|
|
asherkin@3839
|
1071 |
The libcurl project takes security seriously. The library is written with |
|
asherkin@3839
|
1072 |
caution and precautions are taken to mitigate many kinds of risks encountered |
|
asherkin@3839
|
1073 |
while operating with potentially malicious servers on the Internet. It is a |
|
asherkin@3839
|
1074 |
powerful library, however, which allows application writers to make trade offs |
|
asherkin@3839
|
1075 |
between ease of writing and exposure to potential risky operations. If |
|
asherkin@3839
|
1076 |
used the right way, you can use libcurl to transfer data pretty safely. |
|
dvander@2518
|
1077 |
|
|
asherkin@3839
|
1078 |
Many applications are used in closed networks where users and servers |
|
asherkin@3839
|
1079 |
can be trusted, but many others are used on arbitrary servers and are fed |
|
asherkin@3839
|
1080 |
input from potentially untrusted users. Following is a discussion about |
|
asherkin@3839
|
1081 |
some risks in the ways in which applications commonly use libcurl and |
|
asherkin@3839
|
1082 |
potential mitigations of those risks. It is by no means comprehensive, but |
|
asherkin@3839
|
1083 |
shows classes of attacks that robust applications should consider. The |
|
asherkin@3839
|
1084 |
Common Weakness Enumeration project at http://cwe.mitre.org/ is a good |
|
asherkin@3839
|
1085 |
reference for many of these and similar types of weaknesses of which |
|
asherkin@3839
|
1086 |
application writers should be aware. |
|
dvander@2518
|
1087 |
|
|
dvander@2518
|
1088 |
.IP "Command Lines" |
|
dvander@2518
|
1089 |
If you use a command line tool (such as curl) that uses libcurl, and you give |
|
asherkin@3839
|
1090 |
options to the tool on the command line those options can very likely get read |
|
dvander@2518
|
1091 |
by other users of your system when they use 'ps' or other tools to list |
|
dvander@2518
|
1092 |
currently running processes. |
|
dvander@2518
|
1093 |
|
|
dvander@2518
|
1094 |
To avoid this problem, never feed sensitive things to programs using command |
|
asherkin@3839
|
1095 |
line options. Write them to a protected file and use the \-K option to |
|
asherkin@3839
|
1096 |
avoid this. |
|
dvander@2518
|
1097 |
|
|
dvander@2518
|
1098 |
.IP ".netrc" |
|
dvander@2518
|
1099 |
\&.netrc is a pretty handy file/feature that allows you to login quickly and |
|
dvander@2518
|
1100 |
automatically to frequently visited sites. The file contains passwords in |
|
dvander@2518
|
1101 |
clear text and is a real security risk. In some cases, your .netrc is also |
|
dvander@2518
|
1102 |
stored in a home directory that is NFS mounted or used on another network |
|
dvander@2518
|
1103 |
based file system, so the clear text password will fly through your network |
|
dvander@2518
|
1104 |
every time anyone reads that file! |
|
dvander@2518
|
1105 |
|
|
dvander@2518
|
1106 |
To avoid this problem, don't use .netrc files and never store passwords in |
|
dvander@2518
|
1107 |
plain text anywhere. |
|
dvander@2518
|
1108 |
|
|
dvander@2518
|
1109 |
.IP "Clear Text Passwords" |
|
dvander@2518
|
1110 |
Many of the protocols libcurl supports send name and password unencrypted as |
|
dvander@2518
|
1111 |
clear text (HTTP Basic authentication, FTP, TELNET etc). It is very easy for |
|
asherkin@3839
|
1112 |
anyone on your network or a network nearby yours to just fire up a network |
|
dvander@2518
|
1113 |
analyzer tool and eavesdrop on your passwords. Don't let the fact that HTTP |
|
asherkin@3839
|
1114 |
Basic uses base64 encoded passwords fool you. They may not look readable at a |
|
asherkin@3839
|
1115 |
first glance, but they very easily "deciphered" by anyone within seconds. |
|
asherkin@3839
|
1116 |
|
|
asherkin@3839
|
1117 |
To avoid this problem, use HTTP authentication methods or other protocols that |
|
asherkin@3839
|
1118 |
don't let snoopers see your password: HTTP with Digest, NTLM or GSS |
|
asherkin@3839
|
1119 |
authentication, HTTPS, FTPS, SCP, SFTP and FTP-Kerberos are a few examples. |
|
asherkin@3839
|
1120 |
|
|
asherkin@3839
|
1121 |
.IP "Redirects" |
|
asherkin@3839
|
1122 |
The CURLOPT_FOLLOWLOCATION option automatically follows HTTP redirects sent |
|
asherkin@3839
|
1123 |
by a remote server. These redirects can refer to any kind of URL, not just |
|
asherkin@3839
|
1124 |
HTTP. A redirect to a file: URL would cause the libcurl to read (or write) |
|
asherkin@3839
|
1125 |
arbitrary files from the local filesystem. If the application returns |
|
asherkin@3839
|
1126 |
the data back to the user (as would happen in some kinds of CGI scripts), |
|
asherkin@3839
|
1127 |
an attacker could leverage this to read otherwise forbidden data (e.g. |
|
asherkin@3839
|
1128 |
file://localhost/etc/passwd). |
|
asherkin@3839
|
1129 |
|
|
asherkin@3839
|
1130 |
If authentication credentials are stored in the ~/.netrc file, or Kerberos |
|
asherkin@3839
|
1131 |
is in use, any other URL type (not just file:) that requires |
|
asherkin@3839
|
1132 |
authentication is also at risk. A redirect such as |
|
asherkin@3839
|
1133 |
ftp://some-internal-server/private-file would then return data even when |
|
asherkin@3839
|
1134 |
the server is password protected. |
|
asherkin@3839
|
1135 |
|
|
asherkin@3839
|
1136 |
In the same way, if an unencrypted SSH private key has been configured for |
|
asherkin@3839
|
1137 |
the user running the libcurl application, SCP: or SFTP: URLs could access |
|
asherkin@3839
|
1138 |
password or private-key protected resources, |
|
asherkin@3839
|
1139 |
e.g. sftp://user@some-internal-server/etc/passwd |
|
asherkin@3839
|
1140 |
|
|
asherkin@3839
|
1141 |
The CURLOPT_REDIR_PROTOCOLS and CURLOPT_NETRC options can be used to |
|
asherkin@3839
|
1142 |
mitigate against this kind of attack. |
|
asherkin@3839
|
1143 |
|
|
asherkin@3839
|
1144 |
A redirect can also specify a location available only on the machine running |
|
asherkin@3839
|
1145 |
libcurl, including servers hidden behind a firewall from the attacker. |
|
asherkin@3839
|
1146 |
e.g. http://127.0.0.1/ or http://intranet/delete-stuff.cgi?delete=all or |
|
asherkin@3839
|
1147 |
tftp://bootp-server/pc-config-data |
|
asherkin@3839
|
1148 |
|
|
asherkin@3839
|
1149 |
Apps can mitigate against this by disabling CURLOPT_FOLLOWLOCATION and |
|
asherkin@3839
|
1150 |
handling redirects itself, sanitizing URLs as necessary. Alternately, an |
|
asherkin@3839
|
1151 |
app could leave CURLOPT_FOLLOWLOCATION enabled but set CURLOPT_REDIR_PROTOCOLS |
|
asherkin@3839
|
1152 |
and install a CURLOPT_OPENSOCKETFUNCTION callback function in which addresses |
|
asherkin@3839
|
1153 |
are sanitized before use. |
|
asherkin@3839
|
1154 |
|
|
asherkin@3839
|
1155 |
.IP "Private Resources" |
|
asherkin@3839
|
1156 |
A user who can control the DNS server of a domain being passed in within |
|
asherkin@3839
|
1157 |
a URL can change the address of the host to a local, private address |
|
asherkin@3839
|
1158 |
which the libcurl application will then use. e.g. The innocuous URL |
|
asherkin@3839
|
1159 |
http://fuzzybunnies.example.com/ could actually resolve to the IP address |
|
asherkin@3839
|
1160 |
of a server behind a firewall, such as 127.0.0.1 or 10.1.2.3 |
|
asherkin@3839
|
1161 |
Apps can mitigate against this by setting a CURLOPT_OPENSOCKETFUNCTION |
|
asherkin@3839
|
1162 |
and checking the address before a connection. |
|
asherkin@3839
|
1163 |
|
|
asherkin@3839
|
1164 |
All the malicious scenarios regarding redirected URLs apply just as well |
|
asherkin@3839
|
1165 |
to non-redirected URLs, if the user is allowed to specify an arbitrary URL |
|
asherkin@3839
|
1166 |
that could point to a private resource. For example, a web app providing |
|
asherkin@3839
|
1167 |
a translation service might happily translate file://localhost/etc/passwd |
|
asherkin@3839
|
1168 |
and display the result. Apps can mitigate against this with the |
|
asherkin@3839
|
1169 |
CURLOPT_PROTOCOLS option as well as by similar mitigation techniques for |
|
asherkin@3839
|
1170 |
redirections. |
|
asherkin@3839
|
1171 |
|
|
asherkin@3839
|
1172 |
A malicious FTP server could in response to the PASV command return an |
|
asherkin@3839
|
1173 |
IP address and port number for a server local to the app running libcurl |
|
asherkin@3839
|
1174 |
but behind a firewall. Apps can mitigate against this by using the |
|
asherkin@3839
|
1175 |
CURLOPT_FTP_SKIP_PASV_IP option or CURLOPT_FTPPORT. |
|
asherkin@3839
|
1176 |
|
|
asherkin@3839
|
1177 |
.IP Uploads |
|
asherkin@3839
|
1178 |
When uploading, a redirect can cause a local (or remote) file to be |
|
asherkin@3839
|
1179 |
overwritten. Apps must not allow any unsanitized URL to be passed in |
|
asherkin@3839
|
1180 |
for uploads. Also, CURLOPT_FOLLOWLOCATION should not be used on uploads. |
|
asherkin@3839
|
1181 |
Instead, the app should handle redirects itself, sanitizing each URL first. |
|
dvander@2518
|
1182 |
|
|
asherkin@3839
|
1183 |
.IP Authentication |
|
asherkin@3839
|
1184 |
Use of CURLOPT_UNRESTRICTED_AUTH could cause authentication information to |
|
asherkin@3839
|
1185 |
be sent to an unknown second server. Apps can mitigate against this |
|
asherkin@3839
|
1186 |
by disabling CURLOPT_FOLLOWLOCATION and handling redirects itself, |
|
asherkin@3839
|
1187 |
sanitizing where necessary. |
|
asherkin@3839
|
1188 |
|
|
asherkin@3839
|
1189 |
Use of the CURLAUTH_ANY option to CURLOPT_HTTPAUTH could result in user |
|
asherkin@3839
|
1190 |
name and password being sent in clear text to an HTTP server. Instead, |
|
asherkin@3839
|
1191 |
use CURLAUTH_ANYSAFE which ensures that the password is encrypted over |
|
asherkin@3839
|
1192 |
the network, or else fail the request. |
|
asherkin@3839
|
1193 |
|
|
asherkin@3839
|
1194 |
Use of the CURLUSESSL_TRY option to CURLOPT_USE_SSL could result in user |
|
asherkin@3839
|
1195 |
name and password being sent in clear text to an FTP server. Instead, |
|
asherkin@3839
|
1196 |
use CURLUSESSL_CONTROL to ensure that an encrypted connection is used or |
|
asherkin@3839
|
1197 |
else fail the request. |
|
asherkin@3839
|
1198 |
|
|
asherkin@3839
|
1199 |
.IP Cookies |
|
asherkin@3839
|
1200 |
If cookies are enabled and cached, then a user could craft a URL which |
|
asherkin@3839
|
1201 |
performs some malicious action to a site whose authentication is already |
|
asherkin@3839
|
1202 |
stored in a cookie. e.g. http://mail.example.com/delete-stuff.cgi?delete=all |
|
asherkin@3839
|
1203 |
Apps can mitigate against this by disabling cookies or clearing them |
|
asherkin@3839
|
1204 |
between requests. |
|
asherkin@3839
|
1205 |
|
|
asherkin@3839
|
1206 |
.IP "Dangerous URLs" |
|
asherkin@3839
|
1207 |
SCP URLs can contain raw commands within the scp: URL, which is a side effect |
|
asherkin@3839
|
1208 |
of how the SCP protocol is designed. e.g. |
|
asherkin@3839
|
1209 |
scp://user:pass@host/a;date >/tmp/test; |
|
asherkin@3839
|
1210 |
Apps must not allow unsanitized SCP: URLs to be passed in for downloads. |
|
asherkin@3839
|
1211 |
|
|
asherkin@3839
|
1212 |
.IP "Denial of Service" |
|
asherkin@3839
|
1213 |
A malicious server could cause libcurl to effectively hang by sending |
|
asherkin@3839
|
1214 |
a trickle of data through, or even no data at all but just keeping the TCP |
|
asherkin@3839
|
1215 |
connection open. This could result in a denial-of-service attack. The |
|
asherkin@3839
|
1216 |
CURLOPT_TIMEOUT and/or CURLOPT_LOW_SPEED_LIMIT options can be used to |
|
asherkin@3839
|
1217 |
mitigate against this. |
|
asherkin@3839
|
1218 |
|
|
asherkin@3839
|
1219 |
A malicious server could cause libcurl to effectively hang by starting to |
|
asherkin@3839
|
1220 |
send data, then severing the connection without cleanly closing the |
|
asherkin@3839
|
1221 |
TCP connection. The app could install a CURLOPT_SOCKOPTFUNCTION callback |
|
asherkin@3839
|
1222 |
function and set the TCP SO_KEEPALIVE option to mitigate against this. |
|
asherkin@3839
|
1223 |
Setting one of the timeout options would also work against this attack. |
|
asherkin@3839
|
1224 |
|
|
asherkin@3839
|
1225 |
A malicious server could cause libcurl to download an infinite amount of |
|
asherkin@3839
|
1226 |
data, potentially causing all of memory or disk to be filled. Setting |
|
asherkin@3839
|
1227 |
the CURLOPT_MAXFILESIZE_LARGE option is not sufficient to guard against this. |
|
asherkin@3839
|
1228 |
Instead, the app should monitor the amount of data received within the |
|
asherkin@3839
|
1229 |
write or progress callback and abort once the limit is reached. |
|
asherkin@3839
|
1230 |
|
|
asherkin@3839
|
1231 |
A malicious HTTP server could cause an infinite redirection loop, causing a |
|
asherkin@3839
|
1232 |
denial-of-service. This can be mitigated by using the CURLOPT_MAXREDIRS |
|
asherkin@3839
|
1233 |
option. |
|
asherkin@3839
|
1234 |
|
|
asherkin@3839
|
1235 |
.IP "Arbitrary Headers" |
|
asherkin@3839
|
1236 |
User-supplied data must be sanitized when used in options like |
|
asherkin@3839
|
1237 |
CURLOPT_USERAGENT, CURLOPT_HTTPHEADER, CURLOPT_POSTFIELDS and others that |
|
asherkin@3839
|
1238 |
are used to generate structured data. Characters like embedded carriage |
|
asherkin@3839
|
1239 |
returns or ampersands could allow the user to create additional headers or |
|
asherkin@3839
|
1240 |
fields that could cause malicious transactions. |
|
asherkin@3839
|
1241 |
|
|
asherkin@3839
|
1242 |
.IP "Server-supplied Names" |
|
asherkin@3839
|
1243 |
A server can supply data which the application may, in some cases, use as |
|
asherkin@3839
|
1244 |
a file name. The curl command-line tool does this with --remote-header-name, |
|
asherkin@3839
|
1245 |
using the Content-disposition: header to generate a file name. An application |
|
asherkin@3839
|
1246 |
could also use CURLINFO_EFFECTIVE_URL to generate a file name from a |
|
asherkin@3839
|
1247 |
server-supplied redirect URL. Special care must be taken to sanitize such |
|
asherkin@3839
|
1248 |
names to avoid the possibility of a malicious server supplying one like |
|
asherkin@3839
|
1249 |
"/etc/passwd", "\autoexec.bat" or even ".bashrc". |
|
asherkin@3839
|
1250 |
|
|
asherkin@3839
|
1251 |
.IP "Server Certificates" |
|
asherkin@3839
|
1252 |
A secure application should never use the CURLOPT_SSL_VERIFYPEER option to |
|
asherkin@3839
|
1253 |
disable certificate validation. There are numerous attacks that are enabled |
|
asherkin@3839
|
1254 |
by apps that fail to properly validate server TLS/SSL certificates, |
|
asherkin@3839
|
1255 |
thus enabling a malicious server to spoof a legitimate one. HTTPS without |
|
asherkin@3839
|
1256 |
validated certificates is potentially as insecure as a plain HTTP connection. |
|
dvander@2518
|
1257 |
|
|
dvander@2518
|
1258 |
.IP "Showing What You Do" |
|
dvander@2518
|
1259 |
On a related issue, be aware that even in situations like when you have |
|
dvander@2518
|
1260 |
problems with libcurl and ask someone for help, everything you reveal in order |
|
dvander@2518
|
1261 |
to get best possible help might also impose certain security related |
|
asherkin@3839
|
1262 |
risks. Host names, user names, paths, operating system specifics, etc (not to |
|
dvander@2518
|
1263 |
mention passwords of course) may in fact be used by intruders to gain |
|
dvander@2518
|
1264 |
additional information of a potential target. |
|
dvander@2518
|
1265 |
|
|
dvander@2518
|
1266 |
To avoid this problem, you must of course use your common sense. Often, you |
|
dvander@2518
|
1267 |
can just edit out the sensitive data or just search/replace your true |
|
dvander@2518
|
1268 |
information with faked data. |
|
dvander@2518
|
1269 |
|
|
dvander@2518
|
1270 |
.SH "Multiple Transfers Using the multi Interface" |
|
dvander@2518
|
1271 |
|
|
dvander@2518
|
1272 |
The easy interface as described in detail in this document is a synchronous |
|
asherkin@3839
|
1273 |
interface that transfers one file at a time and doesn't return until it is |
|
dvander@2518
|
1274 |
done. |
|
dvander@2518
|
1275 |
|
|
asherkin@3839
|
1276 |
The multi interface, on the other hand, allows your program to transfer |
|
dvander@2518
|
1277 |
multiple files in both directions at the same time, without forcing you |
|
dvander@2518
|
1278 |
to use multiple threads. The name might make it seem that the multi |
|
dvander@2518
|
1279 |
interface is for multi-threaded programs, but the truth is almost the |
|
dvander@2518
|
1280 |
reverse. The multi interface can allow a single-threaded application |
|
dvander@2518
|
1281 |
to perform the same kinds of multiple, simultaneous transfers that |
|
dvander@2518
|
1282 |
multi-threaded programs can perform. It allows many of the benefits |
|
dvander@2518
|
1283 |
of multi-threaded transfers without the complexity of managing and |
|
dvander@2518
|
1284 |
synchronizing many threads. |
|
dvander@2518
|
1285 |
|
|
dvander@2518
|
1286 |
To use this interface, you are better off if you first understand the basics |
|
dvander@2518
|
1287 |
of how to use the easy interface. The multi interface is simply a way to make |
|
asherkin@3839
|
1288 |
multiple transfers at the same time by adding up multiple easy handles into |
|
dvander@2518
|
1289 |
a "multi stack". |
|
dvander@2518
|
1290 |
|
|
dvander@2518
|
1291 |
You create the easy handles you want and you set all the options just like you |
|
dvander@2518
|
1292 |
have been told above, and then you create a multi handle with |
|
dvander@2518
|
1293 |
\fIcurl_multi_init(3)\fP and add all those easy handles to that multi handle |
|
dvander@2518
|
1294 |
with \fIcurl_multi_add_handle(3)\fP. |
|
dvander@2518
|
1295 |
|
|
dvander@2518
|
1296 |
When you've added the handles you have for the moment (you can still add new |
|
asherkin@3839
|
1297 |
ones at any time), you start the transfers by calling |
|
dvander@2518
|
1298 |
\fIcurl_multi_perform(3)\fP. |
|
dvander@2518
|
1299 |
|
|
dvander@2518
|
1300 |
\fIcurl_multi_perform(3)\fP is asynchronous. It will only execute as little as |
|
dvander@2518
|
1301 |
possible and then return back control to your program. It is designed to never |
|
asherkin@3839
|
1302 |
block. |
|
dvander@2518
|
1303 |
|
|
dvander@2518
|
1304 |
The best usage of this interface is when you do a select() on all possible |
|
dvander@2518
|
1305 |
file descriptors or sockets to know when to call libcurl again. This also |
|
dvander@2518
|
1306 |
makes it easy for you to wait and respond to actions on your own application's |
|
dvander@2518
|
1307 |
sockets/handles. You figure out what to select() for by using |
|
dvander@2518
|
1308 |
\fIcurl_multi_fdset(3)\fP, that fills in a set of fd_set variables for you |
|
dvander@2518
|
1309 |
with the particular file descriptors libcurl uses for the moment. |
|
dvander@2518
|
1310 |
|
|
dvander@2518
|
1311 |
When you then call select(), it'll return when one of the file handles signal |
|
dvander@2518
|
1312 |
action and you then call \fIcurl_multi_perform(3)\fP to allow libcurl to do |
|
dvander@2518
|
1313 |
what it wants to do. Take note that libcurl does also feature some time-out |
|
asherkin@3839
|
1314 |
code so we advise you to never use very long timeouts on select() before you |
|
dvander@2518
|
1315 |
call \fIcurl_multi_perform(3)\fP, which thus should be called unconditionally |
|
dvander@2518
|
1316 |
every now and then even if none of its file descriptors have signaled |
|
dvander@2518
|
1317 |
ready. Another precaution you should use: always call |
|
dvander@2518
|
1318 |
\fIcurl_multi_fdset(3)\fP immediately before the select() call since the |
|
dvander@2518
|
1319 |
current set of file descriptors may change when calling a curl function. |
|
dvander@2518
|
1320 |
|
|
dvander@2518
|
1321 |
If you want to stop the transfer of one of the easy handles in the stack, you |
|
dvander@2518
|
1322 |
can use \fIcurl_multi_remove_handle(3)\fP to remove individual easy |
|
dvander@2518
|
1323 |
handles. Remember that easy handles should be \fIcurl_easy_cleanup(3)\fPed. |
|
dvander@2518
|
1324 |
|
|
dvander@2518
|
1325 |
When a transfer within the multi stack has finished, the counter of running |
|
dvander@2518
|
1326 |
transfers (as filled in by \fIcurl_multi_perform(3)\fP) will decrease. When |
|
dvander@2518
|
1327 |
the number reaches zero, all transfers are done. |
|
dvander@2518
|
1328 |
|
|
dvander@2518
|
1329 |
\fIcurl_multi_info_read(3)\fP can be used to get information about completed |
|
dvander@2518
|
1330 |
transfers. It then returns the CURLcode for each easy transfer, to allow you |
|
dvander@2518
|
1331 |
to figure out success on each individual transfer. |
|
dvander@2518
|
1332 |
|
|
dvander@2518
|
1333 |
.SH "SSL, Certificates and Other Tricks" |
|
dvander@2518
|
1334 |
|
|
dvander@2518
|
1335 |
[ seeding, passwords, keys, certificates, ENGINE, ca certs ] |
|
dvander@2518
|
1336 |
|
|
dvander@2518
|
1337 |
.SH "Sharing Data Between Easy Handles" |
|
asherkin@3839
|
1338 |
You can share some data between easy handles when the easy interface is used, |
|
asherkin@3839
|
1339 |
and some data is share automatically when you use the multi interface. |
|
dvander@2518
|
1340 |
|
|
asherkin@3839
|
1341 |
When you add easy handles to a multi handle, these easy handles will |
|
asherkin@3839
|
1342 |
automatically share a lot of the data that otherwise would be kept on a |
|
asherkin@3839
|
1343 |
per-easy handle basis when the easy interface is used. |
|
dvander@2518
|
1344 |
|
|
asherkin@3839
|
1345 |
The DNS cache is shared between handles within a multi handle, making |
|
asherkin@3839
|
1346 |
subsequent name resolvings faster and the connection pool that is kept to |
|
asherkin@3839
|
1347 |
better allow persistent connections and connection re-use is shared. If you're |
|
asherkin@3839
|
1348 |
using the easy interface, you can still share these between specific easy |
|
asherkin@3839
|
1349 |
handles by using the share interface, see \fIlibcurl-share(3)\fP. |
|
asherkin@3839
|
1350 |
|
|
asherkin@3839
|
1351 |
Some things are never shared automatically, not within multi handles, like for |
|
asherkin@3839
|
1352 |
example cookies so the only way to share that is with the share interface. |
|
dvander@2518
|
1353 |
.SH "Footnotes" |
|
dvander@2518
|
1354 |
|
|
dvander@2518
|
1355 |
.IP "[1]" |
|
dvander@2518
|
1356 |
libcurl 7.10.3 and later have the ability to switch over to chunked |
|
asherkin@3839
|
1357 |
Transfer-Encoding in cases where HTTP uploads are done with data of an unknown |
|
dvander@2518
|
1358 |
size. |
|
dvander@2518
|
1359 |
.IP "[2]" |
|
dvander@2518
|
1360 |
This happens on Windows machines when libcurl is built and used as a |
|
dvander@2518
|
1361 |
DLL. However, you can still do this on Windows if you link with a static |
|
dvander@2518
|
1362 |
library. |
|
dvander@2518
|
1363 |
.IP "[3]" |
|
asherkin@3839
|
1364 |
The curl-config tool is generated at build-time (on UNIX-like systems) and |
|
dvander@2518
|
1365 |
should be installed with the 'make install' or similar instruction that |
|
dvander@2518
|
1366 |
installs the library, header files, man pages etc. |
|
asherkin@3839
|
1367 |
.IP "[4]" |
|
asherkin@3839
|
1368 |
This behavior was different in versions before 7.17.0, where strings had to |
|
asherkin@3839
|
1369 |
remain valid past the end of the \fIcurl_easy_setopt(3)\fP call. |