libcurl 是處理收送網路 request、response 的 library,可用來收送 HTTP 的 request 及 response。
libcurl 收到 response 時會 call callback function,由 callback function 處理收到的資料。callback function 可自行撰寫,其 prototype 如下:
1 size_t func (void *ptr, size_t size, size_t nmemb, void *userdata)
ptr 指向收到的資料
nmemb 為收到資料的大小
userdata 可自己定義,我拿它當 return value。
libcurl 的 callback function 分成處理 header 跟 data,用 curl_easy_setopt()
指定處理的 callback function。如果沒有指定 callback function,預設上 data 會被印出來,header 則不處理。
Usage 1. Initialize
1 2 3 #include <curl/curl.h> CURL* curl = curl_easy_init();
2. Set HTTP header data
設 HTTP header,如指定 Content-type:
1 2 3 struct curl_slist * headers ;memset (header, 0 , sizeof (headers));headers = curl_slist_append(headers, "Content-type: application/json" );
call curl_slist_append()
會不斷加資訊到 headers 這個資料結構中。
3. Set options
1 2 3 4 5 6 7 8 9 10 curl_easy_setopt(curl, CURLOPT_POST, 1 ); curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parseHeader); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &rescode); curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, getResponse); curl_easy_setopt(curl, CURLOPT_WRITEDATA, &response);
4. 傳送 request
1 curl_easy_perform(curl);
以 blocking 的方式傳送 request。
5. clean up
1 2 curl_slist_free_all(headers); curl_easy_cleanup(curl);
callback function 1 size_t parseHeader (void *ptr, size_t size, size_t nmemb, string *userdata)
指定以 parseHeader()
處理 header:
1 2 curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parseHeader); curl_easy_setopt(curl, CURLOPT_WRITEHEADER, &data);
userdata 是 void*,可以使用任何 type 或 structure 的 pointer。
處理 data 的 option 是 CURLOPT_WRITEFUNCTION
跟 CURLOPT_WRITEDATA
。
傳送 POST 資料 1 2 3 char postdata[] = "{\"reboot\": {\"type\" : \"SOFT\"}}" ;curl_easy_setopt(curl, CURLOPT_POST, 1 ); curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postdata);
在 postdata 放要傳的資料,用 set option 指定。不太確定 postdata 的 type 是不是一定要用 char?
Link option 用 curl-config --libs
指令找到需要的 link option。
Example 要求 Openstack reboot 某台 VM:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 bool reboot (string token, int vmid) { CURL *curl; struct curl_slist *headers = NULL ; string url = string (APIURL) + "/servers/" + int2string (vmid) + "/action" ; char postdata[] = "{\"reboot\": {\"type\" : \"SOFT\"}}" ; string rescode; curl = curl_easy_init (); if ( curl ) { headers = curl_slist_append (headers, string ("X-Auth-Token: " + token).c_str ()); headers = curl_slist_append (headers, "Content-type: application/json" ); curl_easy_setopt (curl, CURLOPT_POST, 1 ); curl_easy_setopt (curl, CURLOPT_HTTPHEADER, headers); curl_easy_setopt (curl, CURLOPT_URL, url.c_str ()); curl_easy_setopt (curl, CURLOPT_POSTFIELDS, postdata); curl_easy_setopt (curl, CURLOPT_HEADERFUNCTION, parseHeader); curl_easy_setopt (curl, CURLOPT_WRITEHEADER, &rescode); curl_easy_perform (curl); curl_slist_free_all (headers); curl_easy_cleanup (curl); } if ( rescode == "202" ) return true ; else { cerr << "reboot failed, response code is " << rescode << endl; return false ; } } size_t parseHeader (void *ptr, size_t size, size_t nmemb, string *userdata) { if ( strncmp ((char *)ptr, "X-Auth-Token:" , 13 ) == 0 ) { strtok ((char *)ptr, " " ); *userdata = string (strtok (NULL , " \n" )); } else if ( strncmp ((char *)ptr, "HTTP/1.1" , 8 ) == 0 ) { strtok ((char *)ptr, " " ); *userdata = string (strtok (NULL , " \n" )); } return nmemb; }
Ref