a728d4ed67a81768f2b35125cd965cfa91b507fa
[bpdyndnsd] / src / httphelper.cpp
1 /** @file
2  * @brief HTTPHelper class implementation. This class represents a Helper to perform HTTP operations easily.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "httphelper.hpp"
11
12 using namespace std;
13
14
15 /**
16  * Default Constructor.
17  */
18 HTTPHelper::HTTPHelper()
19     : Log(new Logger)
20     , ProxyPort(0)
21     , CurlError(CURLE_OK)
22     , CurlInitError(CURLE_OK)
23 {
24     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
25 }
26
27
28 /**
29  * Constructor. Use this constructor if HTTP AUTH should be used. Username and password will then be set as HTTP auth options.
30  * @param _log Logger Object
31  * @param _proxy Proxy to use
32  * @param _proxy_port Proxy Port
33  * @param _username Username
34  * @param _password Password
35  */
36 HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port, const string& _username, const string& _password)
37     : Log(_log)
38     , Proxy(_proxy)
39     , ProxyPort(_proxy_port)
40     , CurlError(CURLE_OK)
41     , CurlInitError(CURLE_OK)
42     , Username(_username)
43     , Password(_password)
44 {
45     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
46     if ( CurlEasyHandle != NULL )
47     {
48         if ( (CurlInitError = set_curl_auth(Username,Password)) != CURLE_OK )
49         {
50             curl_easy_cleanup(CurlEasyHandle);
51             CurlEasyHandle = NULL;
52         }
53     }
54 }
55
56
57 /**
58  * Constructor. Use this constructor if you have to encode the username and password into the url
59  * @param _log Logger Object
60  * @param _proxy Proxy to use
61  * @param _proxy_port Proxy Port
62  */
63 HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port)
64     : Log(_log)
65     , Proxy(_proxy)
66     , ProxyPort(_proxy_port)
67     , CurlError(CURLE_OK)
68     , CurlInitError(CURLE_OK)
69 {
70     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
71 }
72
73
74 /**
75  * Destructor
76  */
77 HTTPHelper::~HTTPHelper()
78 {
79     // Free memory
80     if ( CurlEasyHandle != NULL )
81     {
82         curl_easy_cleanup(CurlEasyHandle);
83         CurlEasyHandle = NULL;
84     }
85 }
86
87 /**
88  * Re-Init curl
89  */
90 void HTTPHelper::re_initialize()
91 {
92     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
93     if ( (CurlEasyHandle != NULL) && !(Username.empty()) && !(Password.empty()) )
94     {
95         if ( (CurlInitError = set_curl_auth(Username,Password)) != CURLE_OK )
96         {
97             curl_easy_cleanup(CurlEasyHandle);
98             CurlEasyHandle = NULL;
99         }
100     }
101 }
102
103
104 /**
105  * Perform a HTTP GET operation
106  * @param url URL for HTTP GET operation
107  * @return The status code from the http operation or -1 if an curl error occurs
108  */
109 long HTTPHelper::http_get(const string& url)
110 {
111     long curl_info;
112     CurlError = CURLE_OK;
113
114     if ( CurlEasyHandle != NULL )
115     {
116         if ( (CurlInitError = set_curl_url(url)) != CURLE_OK )
117         {
118             Log->print_curl_error(url,CurlInitError,CurlErrBuff);
119             CurlWritedataBuff.clear();
120             return -1;
121         }
122         if ( (CurlError = curl_easy_perform(CurlEasyHandle) ) != CURLE_OK )
123         {
124             Log->print_curl_error(url,CurlError,CurlErrBuff);
125             CurlWritedataBuff.clear();
126             return -1;
127         }
128         if ( (CurlError = curl_easy_getinfo(CurlEasyHandle,CURLINFO_RESPONSE_CODE,&curl_info)) != CURLE_OK )
129         {
130             Log->print_curl_error(url,CurlError);
131             CurlWritedataBuff.clear();
132             return -1;
133         }
134
135         Log->print_curl_data(CurlWritedataBuff);
136
137         // Copy the received data received via curl from the curl data buffer member to the received data member. This is needed because curl appends data to the buffer rather than overrites it.
138         ReceivedCurlData = CurlWritedataBuff;
139         CurlWritedataBuff.clear();
140
141         // Operation performed without any problems so we can return the curl_info
142         return curl_info;
143     }
144     return -1;
145 }
146
147
148 /**
149  * Getter for member CurlWritedataBuff
150  * @return CurlWritedataBuff
151  */
152 string HTTPHelper::get_curl_data() const
153 {
154     return ReceivedCurlData;
155 }
156
157
158 /**
159  * Initialized curl easy handle with a few options.
160  * @param curl_writedata_buff Reference to a string wich will be filled with the curl result
161  * @param curl_err_buff A pointer to an char array which will be filled with error message.
162  * @return A pointer to the easy curl handle or NULL if something went wrong.
163  */
164 CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff)
165 {
166     CurlInitError = CURLE_OK;
167     string user_agent = "Intra2net AG - Bullet Proof DYNDNS Daemon - 0.1.1";
168
169     CURL *curl_easy_handle = curl_easy_init();
170     if ( curl_easy_handle == NULL )
171     {
172         // something went wrong.
173         CurlInitError = CURLE_FAILED_INIT;
174         Log->print_curl_error_init("Could not initialize CURL object.",CURLE_FAILED_INIT);
175         return NULL;
176     }
177
178     CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1);
179     if ( CurlInitError == CURLE_OK)
180         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5);
181     if ( CurlInitError == CURLE_OK)
182         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10);
183     if ( CurlInitError == CURLE_OK)
184         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024);
185     if ( CurlInitError == CURLE_OK)
186         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff);
187     if ( CurlInitError == CURLE_OK)
188         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive);
189     if ( CurlInitError == CURLE_OK)
190         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff);
191     if ( CurlInitError == CURLE_OK)
192         CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_USERAGENT,&user_agent);
193
194     if ( !Proxy.empty() )
195     {
196         if ( CurlInitError == CURLE_OK)
197             CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXY,Proxy.c_str());
198         if ( CurlInitError == CURLE_OK)
199             CurlInitError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXYPORT,ProxyPort);
200     }
201
202     if ( CurlInitError != CURLE_OK )
203     {
204         // Some options could not be set, so destroy the CURL handle.
205         Log->print_curl_error_init("Could not set CURL options properly.",CurlInitError);
206         curl_easy_cleanup(curl_easy_handle);
207         curl_easy_handle = NULL;
208     }
209
210     return curl_easy_handle;
211 }
212
213
214 /**
215  * Test if the curl handle is initialized correctly.
216  * @return True if correctly initialized, false if something went wrong during initialization.
217  */
218 bool HTTPHelper::is_initialized() const
219 {
220     if ( (CurlInitError == CURLE_OK) && (CurlEasyHandle != NULL) )
221     {
222         return true;
223     }
224     return false;
225 }
226
227
228 /**
229  * Sets a url to the easy curl handle
230  * @param url The url to set.
231  * @return CURLcode CURLE_OK if everything is right.
232  */
233 CURLcode HTTPHelper::set_curl_url(const string& url)
234 {
235     CURLcode curlError = CURLE_OK;
236     if ( (CurlEasyHandle != NULL) && (CurlInitError == CURLE_OK) )
237     {
238         curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_URL,url.c_str());
239         if ( curlError != CURLE_OK )
240         {
241             // Some options could not be set, so destroy the CURL handle.
242             Log->print_curl_error_init("Could not set CURL URL properly.",curlError);
243             curl_easy_cleanup(CurlEasyHandle);
244             CurlEasyHandle = NULL;
245         }
246     }
247     else
248     {
249         return CURLE_FAILED_INIT;
250     }
251     return curlError;
252 }
253
254
255 /**
256  * Sets HTTP AUTH parameters
257  * @param username The username for HTTP AUTH
258  * @param password The password for HTTP AUTH
259  * @return CURLcode CURLE_OK if everything is right.
260  */
261 CURLcode HTTPHelper::set_curl_auth(const string& username, const string& password)
262 {
263     CURLcode curlError = CURLE_OK;
264     if ( (CurlEasyHandle != NULL) && (CurlInitError == CURLE_OK) )
265     {
266         curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_USERNAME,username.c_str());
267         if ( curlError != CURLE_OK )
268             Log->print_curl_error_init("Could not set CURL username properly.",curlError);
269         curlError = curl_easy_setopt(CurlEasyHandle,CURLOPT_PASSWORD,password.c_str());
270         if ( curlError != CURLE_OK )
271             Log->print_curl_error_init("Could not set CURL password properly.",curlError);
272     }
273     else
274     {
275         return CURLE_FAILED_INIT;
276     }
277     return curlError;
278 }
279
280
281 /**
282  * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer
283  * @param inBuffer Pointer to input.
284  * @param size How many mem blocks are received
285  * @param nmemb size of each memblock
286  * @param outBuffer Pointer to output stream.
287  * @return The size received.
288  */
289 size_t HTTPHelper::http_receive( const char *inBuffer, size_t size, size_t nmemb, string *outBuffer )
290 {
291     outBuffer->append(inBuffer);
292     return (size*nmemb);
293 }
294