curl - Sizuha/devdog GitHub Wiki
- iOS์ฉ ๋น๋ ์คํฌ๋ฆฝํธ
- Mac OS X์ iOS์ฉ ๋น๋ ์คํฌ๋ฆฝํธ
Xcode์์ ๋ค์ ํ๋ ์์ํฌ๋ฅผ ์ถ๊ฐํด์ผ ํ๋ค.
- libz.dylib
- Security.framework
libCURL์ ์๋์ ๊ฐ์ easy๋ผ๋ ์ด๋ฆ์ ๊ฐ์ง๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค.
- curl_global_init : curl ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ด๊ธฐํ ํ๋ค.
- curl_easy_init : context๋ฅผ ์์ฑํ๋ค.
- curl_easy_setopt : context ์ค์
- curl_easy_perform : ์์ฒญ์ ์ด๊ธฐํ ํ๊ณ callbackํจ์๋ฅผ ๋๊ธฐ์ํจ๋ค.
- curl_easy_cleanup : context๋ฅผ ์์ค๋ค.
- curl_global_cleanup : curl ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์์ค๋ค.
curl_easy_init ํจ์๋ฅผ ํธ์ถํด์ context ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ค.
CURL *ctx = curl_easy_init();
curl_easy_setopt ๋ฅผ ์ด์ฉํด์ context๊ฐ์ฒด๋ฅผ ์ค์ ํ๋ค. CURLOPT_URL์ ๋ชฉํ URL์ด๋ค.
curl_easy_setopt(ctx, CURLOPT_URL, argv[1]);
curl_easy_setopt๋ฅผ ์ด์ฉํ๋ฉด ์ด์ธ์๋ ๋ช ๊ฐ์ง ์ค์ ์ ๋ ํด์ค ์ ์๋ค.
curl_easy_setiopt(ctx, CURLOPT_WRITEHEADER, stderr);
curl_easy_setiopt(ctx, CURLOPT_WRITEDATA, stdout);
header ์ ๋ณด๋ ํ์ค์๋ฌ๋ก, body์ ๋ณด๋ ํ์ค์ถ๋ ฅ์ผ๋ก ๊ฐ์ ธ์ค๋๋ก ์ค์ ์ ํ๋ค.
์ด์ curl_easy_performํจ์๋ฅผ ์ด์ฉํด์ ์ค์ ํ์ด์ง๋ฅผ ๊ธ์ด์ค๋ ์ผ์ ํ๋๋ก ํ์.
const CURLcode rc = curl_easy_perform(ctx);
if (CURLE_OK != rc) {
std::cerr << "Error from cURL: " << curl_easy_strerror(rc) std::endl;
}
else {
// ๋ฐ์ดํฐ ์ฒ๋ฆฌ
}
์ดํ ๋ฐ์ดํฐ๋ ์๋์ ๊ฐ์ด curl_easy_getinfo๋ฅผ ํตํด์ ์ป์ด์์ ์ฒ๋ฆฌํ๋ฉด ๋๋ค.
long statLong;
curl_easy_getinfo(ctx, CURLINFO_HTTP_CODE, &statLong);
std::cout << "HTTP response code: " << statLong << std::endl;
์ํ๋ ๊ฐ์ ๊ฐ์ ธ์ค๊ธฐ ์ํด์๋ ๋ฐ์ดํฐ์ ํ์ ์ ๋ง๋ ์ธ์๋ฅผ ์จ์ผ ํ๋ค. 200์ด๋ 404์ ๊ฐ์ HTTP ์๋ต์ฝ๋๋ฅผ ๊ฐ์ ธ์ค๊ธธ ์ํ๋ค๋ฉด CURLINFO_HTTP_CODE๋ฅผ ์ ์ก๋ฐ์ ๋ฌธ์์ ํฌ๊ธฐ๋ฅผ ์์๋ด๊ธธ ์ํ๋ค๋ฉด CURLINFO_SIZE_DOWNLOAD๋ฅผ ์ฌ์ฉํ๋ ์์ด๋ค.
๋ชจ๋ ์์ ์ด ๋ค ๋๋ฌ๋ค๋ฉด, curl_easy_cleanup์ ํธ์ถํด์ curl_easy_setopt ๊ฐ์ฒด๋ฅผ ์๋ฉธ์์ผ์ผ ํ๋ค. ๊ทธ๋ ์ง ์์๊ฒฝ์ฐ ๋ฉ๋ชจ๋ฆฌ๋์ ํ์์ ๊ฒช๊ฒ ๋ ๊ฒ์ด๋ค.
/*
sample for O'ReillyNet article on libcURL:
{TITLE}
{URL}
AUTHOR: Ethan McCallum
Scenario: use http/GET to fetch a webpage
์ด ์ฝ๋๋ Ubuntu ๋ฆฌ๋
์ค Kernel 2.6.15์์
libcURL ๋ฒ์ ผ 7.15.1๋ก ํ
์คํธ ๋์๋ค.
2006๋
8์ 3์ผ
*/
#include <iostream>
extern "C" {
#include <curl/curl.h>
}
// - - - - - - - - - - - - - - - - - - - -
enum {
ERROR_ARGS = 1 ,
ERROR_CURL_INIT = 2
} ;
enum {
OPTION_FALSE = 0 ,
OPTION_TRUE = 1
} ;
enum {
FLAG_DEFAULT = 0
} ;
// - - - - - - - - - - - - - - - - - - - -
int main( const int argc , const char** argv ) {
if( argc != 2 ){
std::cerr << " Usage: ./" << argv[0] << " {url} [debug]" << std::endl ;
return( ERROR_ARGS ) ;
}
const char* url = argv[1] ;
// lubcURL ์ด๊ธฐํ
curl_global_init( CURL_GLOBAL_ALL ) ;
// context๊ฐ์ฒด์ ์์ฑ
CURL* ctx = curl_easy_init() ;
if( NULL == ctx ){
std::cerr << "Unable to initialize cURL interface" << std::endl ;
return( ERROR_CURL_INIT ) ;
}
// context ๊ฐ์ฒด๋ฅผ ์ค์ ํ๋ค.
// ๊ธ์ด์ฌ url์ ๋ช
์ํ๊ณ , url์ด URL์ ๋ณด์์ ์๋ ค์ค๋ค.
curl_easy_setopt( ctx , CURLOPT_URL, url ) ;
// no progress bar:
curl_easy_setopt( ctx , CURLOPT_NOPROGRESS , OPTION_TRUE ) ;
/*
By default, headers are stripped from the output.
They can be:
- passed through a separate FILE* (CURLOPT_WRITEHEADER)
- included in the body's output (CURLOPT_HEADER -> nonzero value)
(here, the headers will be passed to whatever function
processes the body, along w/ the body)
- handled with separate callbacks (CURLOPT_HEADERFUNCTION)
(in this case, set CURLOPT_WRITEHEADER to a
matching struct for the function)
*/
// ํค๋๋ ํ์ค์๋ฌ๋ก ์ถ๋ ฅํ๋๋ก ํ๋ค.
curl_easy_setopt( ctx , CURLOPT_WRITEHEADER , stderr ) ;
// body ๋ฐ์ดํฐ๋ ํ์ค์ถ๋ ฅ ํ๋๋ก ํ๋ค.
curl_easy_setopt( ctx , CURLOPT_WRITEDATA , stdout ) ;
// context ๊ฐ์ฒด์ ์ค์ ์ข
๋ฃ
// ์นํ์ด์ง๋ฅผ ๊ธ์ด์จ๋ค.
const CURLcode rc = curl_easy_perform( ctx ) ;
if( CURLE_OK != rc ){
std::cerr << "Error from cURL: " << curl_easy_strerror( rc ) << std::endl ;
} else {
// get some info about the xfer:
double statDouble ;
long statLong ;
char* statString = NULL ;
// HTTP ์๋ต์ฝ๋๋ฅผ ์ป์ด์จ๋ค.
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_HTTP_CODE , &statLong ) ){
std::cout << "Response code: " << statLong << std::endl ;
}
// Content-Type ๋ฅผ ์ป์ด์จ๋ค.
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_CONTENT_TYPE , &statString ) ){
std::cout << "Content type: " << statString << std::endl ;
}
// ๋ค์ด๋ก๋ํ ๋ฌธ์์ ํฌ๊ธฐ๋ฅผ ์ป์ด์จ๋ค.
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_SIZE_DOWNLOAD , &statDouble ) ){
std::cout << "Download size: " << statDouble << "bytes" << std::endl ;
}
//
if( CURLE_OK == curl_easy_getinfo( ctx , CURLINFO_SPEED_DOWNLOAD , &statDouble ) ){
std::cout << "Download speed: " << statDouble << "bytes/sec" << std::endl ;
}
}
// cleanup
curl_easy_cleanup( ctx ) ;
curl_global_cleanup() ;
return( 0 ) ;
}
POST๋ก ๋ณด๋ด๋ ๋ฐ์ดํฐ๋ key=valueํํ๋ก ๋์ด ์์ผ๋ฉฐ, ๊ฐ๊ฐ์ key=value ๋ &๋ฅผ ํตํด์ ๊ตฌ๋ถ๋๋ค.
const char* postData="param1=value1ยถm2=value2&...";
POST ๋ฐ์ดํฐ ์ ์ก์ ์ํด์ CURLOPT_POSTFIELDS์ต์ ์ ์ค์ ํ๋ฉด ๋๋ค.
curl_easy_setopt(ctx, CURLOPT_POSTFIELDS, postData);
์ด์ CURLOPT_HTTPHEADER๋ฅผ ์ด์ฉํด์ ์ฌ์ฉ์์ ์ HTTP ํค๋๋ฅผ ๋ง๋ค๋๋ก ํ๋ค.
curl_sist * responseHeaders=NULL;
responseHeaders = curl_slist_append(
responseHeaders,
"Expect: 100-continue"
);
curl_easy_setopt(ctx, CURLOPT_HTTPHEADER, responseHeaders);
์ฃผ์ ํ ๊ฒ์ libCURL์ hidden ํ๋๋ JavaScript์ ๊ฐ์ ํด๋ผ์ด์ธํธ์ธก์ ๊ธฐ์ ๋ค์ ์ฌ์ฉํ์ง ๋ชปํ๋ค๋ ์ ์ด๋ค. ์๋ฅผ๋ค์ด ํผ์ ๋ ฅ์ ํ๊ณ ๋์ submit๋ฒํผ์ ํด๋ฆญํ๋ฉด ํผ์ ๊ฐ ํ๋๋ฅผ ๊ฒ์ฌํ๋ ๋ฑ์ ์๋ฐ์คํฌ๋ฆฝํธ๋ฑ์ ์ฒ๋ฆฌํ ์ ์๋ค.
/*
sample for O'ReillyNet article on libcURL:
{TITLE}
{URL}
AUTHOR: Ethan McCallum
HTTP POST (e.g. form processing or REST web services)
์ด ์ฝ๋๋ Ubuntu 6.06 Dapper Drake,
libcURL
This code was built/tested under Fedora Core 3,
libcURL version 7.12.3 ํ๊ฒฝ์์ ํ
์คํธ ๋์๋ค.
*/
#include <cstdio>
#include <iostream>
#include <string>
#include <sstream>
extern "C" {
#include <curl/curl.h>
}
// - - - - - - - - - - - - - - - - - - - -
enum {
ERROR_ARGS = 1 ,
ERROR_CURL_INIT = 2
} ;
enum {
OPTION_FALSE = 0 ,
OPTION_TRUE = 1
} ;
enum {
FLAG_DEFAULT = 0
} ;
const char* targetUrl ;
// - - - - - - - - - - - - - - - - - - - -
int main( int argc , char** argv ) {
if( argc != 2 ){
std::cerr << "test of libcURL: test an HTTP post" << std::endl ;
std::cerr << "(post data is canned)" << std::endl ;
std::cerr << " Usage: " << argv[0] << " {post url}" << std::endl ;
std::exit( ERROR_ARGS ) ;
}
targetUrl = argv[1] ;
curl_global_init( CURL_GLOBAL_ALL ) ;
CURL* ctx = curl_easy_init() ;
if( NULL == ctx ){
std::cerr << "Unable to initialize cURL interface" << std::endl ;
return( ERROR_CURL_INIT ) ;
}
/* BEGIN: configure the handle: */
// Target URL:
curl_easy_setopt( ctx , CURLOPT_URL, targetUrl ) ;
// no progress bar:
curl_easy_setopt( ctx , CURLOPT_NOPROGRESS , OPTION_TRUE ) ;
// ์๋ต๋ฐ์ดํฐ๋ฅผ ํ์ค์ถ๋ ฅ์ผ๋ก ๋ณด๋ธ๋ค.
curl_easy_setopt( ctx , CURLOPT_WRITEDATA , stdout ) ;
// ์ฌ์ฉ์ ์ ์ HTTP ํค๋: create a linked list and assign
curl_slist* responseHeaders = NULL ;
responseHeaders = curl_slist_append( responseHeaders , "Expect: 100-continue" ) ;
responseHeaders = curl_slist_append( responseHeaders , "User-Agent: Some Custom App" ) ;
curl_easy_setopt( ctx , CURLOPT_HTTPHEADER , responseHeaders ) ;
// POST Data ์ค์
// notice the URL-unfriendly characters (such as "%" and "&")
// URL์์๋ '%', '&', ' '์ ๊ฐ์ ๋ฌธ์๋ฅผ URL encoding ์์ผ์ค์ผ ํ๋ค.
// curl_escape ํจ์๋ฅผ ์ด์ฉํด์ ์ธ์ฝ๋ฉํ ์ ์๋ค.
const char* postParams[] = {
"One" , "this has % and & symbols" ,
"Dos" , "value with spaces" ,
"Trois" , "plus+signs+will+be+escaped" ,
"Chetirye" , "fourth param..." ,
NULL
} ;
// buffer for the POST params
std::ostringstream postBuf ;
const char** postParamsPtr = postParams ;
while( NULL != *postParamsPtr )
{
// curl_escape( {string} , 0 ): replace special characters
// (such as space, "&", "+", "%") with HTML entities.
// ( 0 => "use strlen to find string length" )
// remember to call curl_free() on the strings on the way out
char* key = curl_escape( postParamsPtr[0] , FLAG_DEFAULT ) ;
char* val = curl_escape( postParamsPtr[1] , FLAG_DEFAULT ) ;
std::cout << "Setting POST param: "" << key << "" => "" << val << """ << std::endl ;
postBuf << key << "=" << val << "&" ;
postParamsPtr += 2 ;
// the cURL lib allocated the escaped versions of the
// param strings; we must free them here
curl_free( key ) ;
curl_free( val ) ;
}
postBuf << std::flush ;
// We can't really call "postBuf.str().c_str()" here, because
// the std::string created in the middle is a temporary. In turn,
// the char* buf from its c_str() operation isn't guaranteed to
// be around after the function call.
// The solution: explicitly create the string.
// Larger (and/or better) code would use std::string::copy() to create
// a const char* pointer to pass to cURL, then clean it up later.
// e.g.:
// const char* postData = new char*[ 1 + postBuf.tellg() ] ;
// postBuf.str().copy( postData , std::string::npos ) ;
// postData[ postBuf.tellg() ] == '' ;
const std::string postData = postBuf.str() ;
std::cout << "post data: " << postData << std::endl ;
curl_easy_setopt( ctx , CURLOPT_POSTFIELDS , postData.c_str() ) ;
// do a standard HTTP POST op
// in theory, this is automatically set for us by setting
// CURLOPT_POSTFIELDS...
curl_easy_setopt( ctx , CURLOPT_POST , OPTION_TRUE ) ;
/* END: configure the handle */
// action!
std::cout << "- - - BEGIN: response - - -" << std::endl ;
CURLcode rc = curl_easy_perform( ctx ) ;
std::cout << "- - - END: response - - -" << std::endl ;
// "curl_easy_strerror()" available in curl v7.12.x and later
if( CURLE_OK != rc ){
std::cerr << 't' << "Error from cURL: " << curl_easy_strerror( rc ) << std::endl ;
}
// cleanup
curl_slist_free_all( responseHeaders ) ;
curl_easy_cleanup( ctx ) ;
curl_global_cleanup() ;
std::exit( 0 ) ;
}
// ํ์์์ ์ค์ : ๋จ์๋ ์ด(sec)
void setTimeout(CURL* curl, int conn_timeout, int http_timeout)
{
curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, conn_timeout); // ์ฐ๊ฒฐ์ ํ์์์
curl_easy_setopt(curl, CURLOPT_TIMEOUT, http_timeout); // ๋ฐ์ดํฐ ์ ์ก ํ์์์
}
milliseconds ๋จ์๋ก ์ค์ ํ๋ ค๋ฉด CURLOPT_TIMEOUT_MS ์ต์ ์ผ๋ก ์ค์ .