📄 libcurl-tutorial.3
字号:
why the server behaves the way it does. Include headers in the normal bodyoutput with CURLOPT_HEADER set TRUE.Of course there are bugs left. We need to get to know about them to be ableto fix them, so we're quite dependent on your bug reports! When you do reportsuspected bugs in libcurl, please include as much details you possibly can: aprotocol dump that CURLOPT_VERBOSE produces, library version, as much aspossible of your code that uses libcurl, operating system name and version,compiler name and version etc.If CURLOPT_VERBOSE is not enough, you increase the level of debug data yourapplication receive by using the CURLOPT_DEBUGFUNCTION.Getting some in-depth knowledge about the protocols involved is never wrong,and if you're trying to do funny things, you might very well understandlibcurl and how to use it better if you study the appropriate RFC documentsat least briefly..SH "Upload Data to a Remote Site"libcurl tries to keep a protocol independent approach to most transfers, thusuploading to a remote FTP site is very similar to uploading data to a HTTPserver with a PUT request.Of course, first you either create an easy handle or you re-use one existingone. Then you set the URL to operate on just like before. This is the remoteURL, that we now will upload.Since we write an application, we most likely want libcurl to get the uploaddata by asking us for it. To make it do that, we set the read callback andthe custom pointer libcurl will pass to our read callback. The read callbackshould have a prototype similar to: size_t function(char *bufptr, size_t size, size_t nitems, void *userp);Where bufptr is the pointer to a buffer we fill in with data to upload andsize*nitems is the size of the buffer and therefore also the maximum amountof data we can return to libcurl in this call. The 'userp' pointer is thecustom pointer we set to point to a struct of ours to pass private databetween the application and the callback. curl_easy_setopt(easyhandle, CURLOPT_READFUNCTION, read_function); curl_easy_setopt(easyhandle, CURLOPT_INFILE, &filedata);Tell libcurl that we want to upload: curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, TRUE);A few protocols won't behave properly when uploads are done without any priorknowledge of the expected file size. So, set the upload file size using theCURLOPT_INFILESIZE_LARGE for all known file sizes like this[1]:.nf /* in this example, file_size must be an off_t variable */ curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE_LARGE, file_size);.fiWhen you call \fIcurl_easy_perform(3)\fP this time, it'll perform all thenecessary operations and when it has invoked the upload it'll call yoursupplied callback to get the data to upload. The program should return as muchdata as possible in every invoke, as that is likely to make the upload performas fast as possible. The callback should return the number of bytes it wrotein the buffer. Returning 0 will signal the end of the upload..SH "Passwords"Many protocols use or even require that user name and password are providedto be able to download or upload the data of your choice. libcurl offersseveral ways to specify them.Most protocols support that you specify the name and password in the URLitself. libcurl will detect this and use them accordingly. This is writtenlike this: protocol://user:password@example.com/path/If you need any odd letters in your user name or password, you should enterthem URL encoded, as %XX where XX is a two-digit hexadecimal number.libcurl also provides options to set various passwords. The user name andpassword as shown embedded in the URL can instead get set with theCURLOPT_USERPWD option. The argument passed to libcurl should be a char * toa string in the format "user:password:". In a manner like this: curl_easy_setopt(easyhandle, CURLOPT_USERPWD, "myname:thesecret");Another case where name and password might be needed at times, is for thoseusers who need to authenticate themselves to a proxy they use. libcurl offersanother option for this, the CURLOPT_PROXYUSERPWD. It is used quite similarto the CURLOPT_USERPWD option like this: curl_easy_setopt(easyhandle, CURLOPT_PROXYUSERPWD, "myname:thesecret"); There's a long time unix "standard" way of storing ftp user names andpasswords, namely in the $HOME/.netrc file. The file should be made privateso that only the user may read it (see also the "Security Considerations"chapter), as it might contain the password in plain text. libcurl has theability to use this file to figure out what set of user name and password touse for a particular host. As an extension to the normal functionality,libcurl also supports this file for non-FTP protocols such as HTTP. To makecurl use this file, use the CURLOPT_NETRC option: curl_easy_setopt(easyhandle, CURLOPT_NETRC, TRUE);And a very basic example of how such a .netrc file may look like:.nf machine myhost.mydomain.com login userlogin password secretword.fiAll these examples have been cases where the password has been optional, orat least you could leave it out and have libcurl attempt to do its jobwithout it. There are times when the password isn't optional, like whenyou're using an SSL private key for secure transfers.To pass the known private key password to libcurl: curl_easy_setopt(easyhandle, CURLOPT_KEYPASSWD, "keypassword");.SH "HTTP Authentication"The previous chapter showed how to set user name and password for gettingURLs that require authentication. When using the HTTP protocol, there aremany different ways a client can provide those credentials to the server andyou can control what way libcurl will (attempt to) use. The default HTTPauthentication method is called 'Basic', which is sending the name andpassword in clear-text in the HTTP request, base64-encoded. This is insecure.At the time of this writing libcurl can be built to use: Basic, Digest, NTLM,Negotiate, GSS-Negotiate and SPNEGO. You can tell libcurl which one to usewith CURLOPT_HTTPAUTH as in: curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);And when you send authentication to a proxy, you can also set authenticationtype the same way but instead with CURLOPT_PROXYAUTH: curl_easy_setopt(easyhandle, CURLOPT_PROXYAUTH, CURLAUTH_NTLM);Both these options allow you to set multiple types (by ORing them together),to make libcurl pick the most secure one out of the types the server/proxyclaims to support. This method does however add a round-trip since libcurlmust first ask the server what it supports: curl_easy_setopt(easyhandle, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST|CURLAUTH_BASIC);For convenience, you can use the 'CURLAUTH_ANY' define (instead of a listwith specific types) which allows libcurl to use whatever method it wants.When asking for multiple types, libcurl will pick the available one itconsiders "best" in its own internal order of preference..SH "HTTP POSTing"We get many questions regarding how to issue HTTP POSTs with libcurl theproper way. This chapter will thus include examples using both differentversions of HTTP POST that libcurl supports.The first version is the simple POST, the most common version, that most HTMLpages using the <form> tag uses. We provide a pointer to the data and telllibcurl to post it all to the remote site:.nf char *data="name=daniel&project=curl"; curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, data); curl_easy_setopt(easyhandle, CURLOPT_URL, "http://posthere.com/"); curl_easy_perform(easyhandle); /* post away! */.fiSimple enough, huh? Since you set the POST options with theCURLOPT_POSTFIELDS, this automatically switches the handle to use POST in theupcoming request.Ok, so what if you want to post binary data that also requires you to set theContent-Type: header of the post? Well, binary posts prevents libcurl frombeing able to do strlen() on the data to figure out the size, so therefore wemust tell libcurl the size of the post data. Setting headers in libcurlrequests are done in a generic way, by building a list of our own headers andthen passing that list to libcurl..nf struct curl_slist *headers=NULL; headers = curl_slist_append(headers, "Content-Type: text/xml"); /* post binary data */ curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDS, binaryptr); /* set the size of the postfields data */ curl_easy_setopt(easyhandle, CURLOPT_POSTFIELDSIZE, 23); /* pass our list of custom made headers */ curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, headers); curl_easy_perform(easyhandle); /* post away! */ curl_slist_free_all(headers); /* free the header list */.fiWhile the simple examples above cover the majority of all cases where HTTPPOST operations are required, they don't do multi-part formposts. Multi-partformposts were introduced as a better way to post (possibly large) binary dataand was first documented in the RFC1867. They're called multi-part becausethey're built by a chain of parts, each being a single unit. Each part has itsown name and contents. You can in fact create and post a multi-part formpostwith the regular libcurl POST support described above, but that would requirethat you build a formpost yourself and provide to libcurl. To make thateasier, libcurl provides \fIcurl_formadd(3)\fP. Using this function, you addparts to the form. When you're done adding parts, you post the whole form.The following example sets two simple text parts with plain textual contents,and then a file with binary contents and upload the whole thing..nf struct curl_httppost *post=NULL; struct curl_httppost *last=NULL; curl_formadd(&post, &last, CURLFORM_COPYNAME, "name", CURLFORM_COPYCONTENTS, "daniel", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "project", CURLFORM_COPYCONTENTS, "curl", CURLFORM_END); curl_formadd(&post, &last, CURLFORM_COPYNAME, "logotype-image", CURLFORM_FILECONTENT, "curl.png", CURLFORM_END); /* Set the form info */ curl_easy_setopt(easyhandle, CURLOPT_HTTPPOST, post); curl_easy_perform(easyhandle); /* post away! */ /* free the post data again */ curl_formfree(post);.fiMultipart formposts are chains of parts using MIME-style separators andheaders. It means that each one of these separate parts get a few headers setthat describe the individual content-type, size etc. To enable yourapplication to handicraft this formpost even more, libcurl allows you tosupply your own set of custom headers to such an individual form part. You canof course supply headers to as many parts you like, but this little examplewill show how you set headers to one specific part when you add that to thepost handle:.nf struct curl_slist *headers=NULL; headers = curl_slist_append(headers, "Content-Type: text/xml"); curl_formadd(&post, &last, CURLFORM_COPYNAME, "logotype-image", CURLFORM_FILECONTENT, "curl.xml", CURLFORM_CONTENTHEADER, headers, CURLFORM_END); curl_easy_perform(easyhandle); /* post away! */ curl_formfree(post); /* free post */ curl_slist_free_all(post); /* free custom header list */.fiSince all options on an easyhandle are "sticky", they remain the same untilchanged even if you do call \fIcurl_easy_perform(3)\fP, you may need to tellcurl to go back to a plain GET request if you intend to do such a one as yournext request. You force an easyhandle to back to GET by using theCURLOPT_HTTPGET option: curl_easy_setopt(easyhandle, CURLOPT_HTTPGET, TRUE);Just setting CURLOPT_POSTFIELDS to "" or NULL will *not* stop libcurl fromdoing a POST. It will just make it POST without any data to send!.SH "Showing Progress"For historical and traditional reasons, libcurl has a built-in progress meterthat can be switched on and then makes it presents a progress meter in yourterminal.Switch on the progress meter by, oddly enough, set CURLOPT_NOPROGRESS toFALSE. This option is set to TRUE by default.For most applications however, the built-in progress meter is useless andwhat instead is interesting is the ability to specify a progresscallback. The function pointer you pass to libcurl will then be called onirregular intervals with information about the current transfer.Set the progress callback by using CURLOPT_PROGRESSFUNCTION. And pass apointer to a function that matches this prototype:.nf int progress_callback(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow);.fiIf any of the input arguments is unknown, a 0 will be passed. The firstargument, the 'clientp' is the pointer you pass to libcurl withCURLOPT_PROGRESSDATA. libcurl won't touch it.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -