Skip to content

Commit

Permalink
libcurl: split up into subsections
Browse files Browse the repository at this point in the history
  • Loading branch information
bagder committed Dec 9, 2015
1 parent 334c455 commit 3f11dae
Show file tree
Hide file tree
Showing 10 changed files with 240 additions and 232 deletions.
8 changes: 8 additions & 0 deletions SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@
* [curl examples](curlexamples.md)
* [Building and installing](building.md)
* [Using libcurl](libcurl.md)
* [API compatibility](libcurl-api.md)
* [--libcurl](libcurl--libcurl.md)
* [Header files](libcurl-headers.md)
* [Global initialization](libcurl-globalinit.md)
* [CURL *handle](libcurl-handle.md)
* [curl easy options](libcurl-options.md)
* [CURLcode return codes](libcurl-curlcode.md)
* [Verbose operations](libcurl-verbose.md)
* [libcurl examples](libcurlexamples.md)
* [Bindings](bindings.md)
* [libcurl internals](internals.md)
68 changes: 68 additions & 0 deletions libcurl--libcurl.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
## curl --libcurl

We actively encourage users to first try out the transfer they want to do with
the curl command line tool, and once it works roughly the way you want it to
you append the `--libcurl [filename]` option to the command line and run it
again.

The `--libcurl` command line option will create a C program in the provided
file name. That C program is an application that uses libcurl to run the
transfer you just had the curl command line tool do. Sure there are some
exceptions and it isn't always a 100% match, but you will find that it can
serve as an excellent inspiration source for what libcurl options you want or
can use and what additional arguments to provide to them.

If you specify the filename as a single dash, as in `--libcurl -` you will get
the program written to stdout instead of a file.

As an example, we run a command to just get http://example.com:

curl http://example.com --libcurl example.c

This creates `example.c` in the current directory, looking similar to this:

/********* Sample code generated by the curl command line tool **********
* All curl_easy_setopt() options are documented at:
* http://curl.haxx.se/libcurl/c/curl_easy_setopt.html
************************************************************************/
#include <curl/curl.h>

int main(int argc, char *argv[])
{
CURLcode ret;
CURL *hnd;

hnd = curl_easy_init();
curl_easy_setopt(hnd, CURLOPT_URL, "http://example.com");
curl_easy_setopt(hnd, CURLOPT_NOPROGRESS, 1L);
curl_easy_setopt(hnd, CURLOPT_USERAGENT, "curl/7.45.0");
curl_easy_setopt(hnd, CURLOPT_MAXREDIRS, 50L);
curl_easy_setopt(hnd, CURLOPT_SSH_KNOWNHOSTS, "/home/daniel/.ssh/known_hosts");
curl_easy_setopt(hnd, CURLOPT_TCP_KEEPALIVE, 1L);

/* Here is a list of options the curl code used that cannot get generated
as source easily. You may select to either not use them or implement
them yourself.

CURLOPT_WRITEDATA set to a objectpointer
CURLOPT_WRITEFUNCTION set to a functionpointer
CURLOPT_READDATA set to a objectpointer
CURLOPT_READFUNCTION set to a functionpointer
CURLOPT_SEEKDATA set to a objectpointer
CURLOPT_SEEKFUNCTION set to a functionpointer
CURLOPT_ERRORBUFFER set to a objectpointer
CURLOPT_STDERR set to a objectpointer
CURLOPT_HEADERFUNCTION set to a functionpointer
CURLOPT_HEADERDATA set to a objectpointer

*/

ret = curl_easy_perform(hnd);

curl_easy_cleanup(hnd);
hnd = NULL;

return (int)ret;
}
/**** End of sample code ****/

4 changes: 4 additions & 0 deletions libcurl-api.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## API compatibility

TBD

25 changes: 25 additions & 0 deletions libcurl-curlcode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
## CURLcode return code

Many libcurl functions return a CURLcode. That's a special libcurl typedefed
variable for error codes. It returns CURLE_OK (which has the value zero) if
everything is fine and dandy and it returns a non-zero number if a problem was
detected. There are almost one hundred `CURLcode` errors in use, and you can
find them all in the `curl/curl.h` header file and documented in the
libcurl-errors man page.

You can convert a CURLcode into a human readable string with the
`curl_easy_strerror()` function - but be aware that these errors are rarely
phrased in a way that is suitable for anyone to expose in a UI or to an end
user:

const char *str = curl_easy_strerror( error );
printf("libcurl said %s\n", str);

Another way to get a slightly better error text in case of errors, is to set
the `CURLOPT_ERRORBUFFER` option to point out a buffer in your program and
then libcurl will store a related error message there before it returns an
error:

curl error[CURL_ERROR_SIZE]; /* needs to be at least this big */
CURLcode ret = curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, error);

20 changes: 20 additions & 0 deletions libcurl-globalinit.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
## Global initialization

Before you do anything libcurl related in your program, you should do a global
libcurl initialize call with `curl_global_init()`. This is necessary because
some underlying libraries that libcurl might be using need a call ahead to get
setup and inited properly.

curl_global_init() is unfortunately not thread safe so you must sure that you
only do it once and never simultaneously as another call. It initializes
global state so you should only call it once and once your program is
completely done using libcurl you can call `curl_global_cleanup()` to again
free and clean up the associated global resources the init call allocated.

libcurl is built to handle that you skip the `curl_global_init()` call, but it
does so by calling it itself instead if you didn't do it before any actual
file transfer starts and it then uses its own defaults. But beware that it is
still not thread safe even then so it might cause some "interesting" side
effects for you. It is much better to call curl_global_init() yourself in a
controlled manner.

26 changes: 26 additions & 0 deletions libcurl-handle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
## CURL *handle

The CURL handle is what we usually call an "easy handle". You create one with
`curl_easy_init()` and it is then your handle to a transfer.

CURL *easy = curl_easy_init();

Of course at the point in time when you have created it, it is empty and it
doesn't know what transfer it should do. You must then set a few options for
it so that it knows what to do when you ask it to perform.

Also, when you use an easy handle to actually perform a transfer it will build
up and hold "state". It means it will keep information within the handle that
libcurl can use and find. By reusing an easy handle for example, libcurl can
reuse that information again.

When you're done with the handle, like if you've done your transfers and you
don't plan to do any more with this same handle, you need to free it to remove
and clean up all related resources. You do this with `curl_easy_cleanup()`. We
encourage applications to reuse handles as much as possible for performance
and efficiency purposes.

In case of problem (like perhaps out of memory), curl_easy_init() returns NULL
and that is of course a serious error for any application. You need to write
your program to take this risk into account.

11 changes: 11 additions & 0 deletions libcurl-headers.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
## Header files

There is ever only one header your libcurl using application needs to include:

#include <curl/curl.h>

That file in turn includes a few other public header files but you can
basically pretend they don't exist. (Historically speaking, we started out
slightly different but over time we've stabilized around this form of only
using a single one for includes.)

57 changes: 57 additions & 0 deletions libcurl-options.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
## Set handle options

You set options in the easy handle to control how that transfer is going to be
done or in some cases you can actually set options and modify the transfer's
behavior while it is in progress. You set options with `curl_easy_setopt()`
and you provide the handle, the option you want to set and the argument to the
option. All options take exactly one argument and you must always pass exactly
three parameters to the curl_easy_setopt() calls.

Since the curl_easy_setopt() call accepts several hundred different options
and the various options accept a variety of different types of arguments, it
is very important to read up on the specifics and provide exactly the argument
type the specific option supports and expects. Passing in the wrong type can
lead to unexpected side-effects or hard to understand hiccups.

The perhaps most important option that every transfer needs, is the URL.
libcurl cannot perform a transfer without knowing which URL it concerns so you
must tell it. The URL option name is `CURLOPT_URL` as all options are prefixed
with `CURLOPT_` and then the descriptive name - all using uppercase
letters. An example line setting the URL to get the "http://example.com" HTTP
contents could look like:

CURLcode ret = curl_easy_setopt(easy, CURLOPT_URL, "http://example.com");

Again: this only sets the option in the handle. It will not do the actual
transfer or anything. It will basically just tell libcurl to copy the string
and if that works it returns OK.

It is of course good form to check the return code to see that nothing went
wrong.

### Setting numerical options

Since curl_easy_setopt() is a vararg function where the 3rd argument can use
different types depending on the situation, normal C language type conversion
cannot be done. So you **must** make sure that you truly pass a 'long' and not
an 'int' if the documentation tells you so. On architectures where they are
the same size, you may not get any problems but not all work like
that. Similarly, for options that accept a 'curl_off_t' type, it is
**crucial** that you pass in an argument using that type and no other.

Enforce a long:

curl_easy_setopt(handle, CURLOPT_TIMEOUT, 5L); /* 5 seconds timeout */

Enforce a curl_off_t:

curl_off_t no_larger_than = 0x50000;
curl_easy_setopt(handle, CURLOPT_MAXFILE_LARGE, no_larger_than);

### Get handle options

No, there's no general method to extract the same information you previously
set with `curl_easy_setopt()`! If you need to be able to extract the
information again that you set earlier, then we encourage you to keep track of
that data yourself in your application.

21 changes: 21 additions & 0 deletions libcurl-verbose.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Verbose operations

Okay, we just showed how to get the error as a human readable text as that is
an excellent help to figure out what went wrong in a particular transfer and
often explains why it can be done like that or what the problem is for the
moment.

The next life safer when writing libcurl applications that everyone needs to
know about and needs to use extensively, at least while developing libcurl
applications or debugging libcurl itself, is to enable "verbose mode" with
`CURLOPT_URL`:

CURLcode ret = curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);

When libcurl is told to be verbose it will mention transfer related details
and information to stderr while the transfer is ongoing. This is awesome to
figure out why things fail and to learn exactly what libcurl does when you ask
it different things. You can redirect the output elsewhere by changing stderr
with `CURLOPT_STDERR` or you can get even more info in a fancier way with the
debug callback (explained further in a later section).

Loading

0 comments on commit 3f11dae

Please sign in to comment.