Next steps in fine tuning.
[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.h"
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     , CurlEasyHandle(NULL)
23 {
24 }
25
26
27 /**
28  * Constructor. Use this constructor if HTTP AUTH should be used. Username and password will then be set as HTTP auth options.
29  * @param _log Logger Object 
30  * @param _proxy Proxy to use
31  * @param _proxy_port Proxy Port
32  * @param _username Username
33  * @param _password Password
34  */
35 HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port, const string& _username, const string& _password)
36     : Log(_log)
37     , Proxy(_proxy)
38     , ProxyPort(_proxy_port)
39     , CurlError(CURLE_OK)
40 {
41     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
42     if ( CurlEasyHandle != NULL )
43     {
44         set_curl_auth(_username,_password);
45     }
46 }
47
48
49 /**
50  * Constructor. Use this constructor if you have to encode the username and password into the url
51  * @param _log Logger Object 
52  * @param _proxy Proxy to use
53  * @param _proxy_port Proxy Port
54  */
55 HTTPHelper::HTTPHelper(Logger::Ptr _log, const string& _proxy, const int _proxy_port)
56     : Log(_log)
57     , Proxy(_proxy)
58     , ProxyPort(_proxy_port)
59     , CurlError(CURLE_OK)
60 {
61     CurlEasyHandle = init_curl(CurlWritedataBuff, CurlErrBuff);
62 }
63
64
65 /**
66  * Destructor
67  */
68 HTTPHelper::~HTTPHelper()
69 {
70     // Free memory
71     if ( CurlEasyHandle != NULL )
72     {
73         curl_easy_cleanup(CurlEasyHandle);
74         CurlEasyHandle = NULL;
75     }
76 }
77
78
79 /**
80  * Perform a HTTP GET operation
81  * @param url URL for HTTP GET operation
82  * @return The status code from the http operation or -1 if an curl error occurs
83  */
84 long HTTPHelper::http_get(const string& url)
85 {
86     CURLcode curl_err_code;
87     long curl_info;
88
89     if ( CurlEasyHandle != NULL )
90     {
91         set_curl_url(url);
92
93         if ( (curl_err_code = curl_easy_perform(CurlEasyHandle) ) != CURLE_OK )
94         {
95             Log->print_curl_error(url,curl_err_code,CurlErrBuff);
96             CurlWritedataBuff.clear();
97             return -1;
98         }
99         if ( (curl_err_code = curl_easy_getinfo(CurlEasyHandle,CURLINFO_RESPONSE_CODE,&curl_info)) != CURLE_OK )
100         {
101             Log->print_curl_error(url,curl_err_code);
102             CurlWritedataBuff.clear();
103             return -1;
104         }
105
106         Log->print_curl_data(CurlWritedataBuff);
107
108         // 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.
109         ReceivedCurlData = CurlWritedataBuff;
110         CurlWritedataBuff.clear();
111
112         // Operation performed without any problems so we can return the curl_info
113         return curl_info;
114     }
115     return -1;
116 }
117
118
119 /**
120  * Getter for member CurlWritedataBuff
121  * @return CurlWritedataBuff
122  */
123 string HTTPHelper::get_curl_data() const
124 {
125     return ReceivedCurlData;
126 }
127
128
129 /**
130  * Initialized curl easy handle with a few options.
131  * @param curl_writedata_buff Reference to a string wich will be filled with the curl result
132  * @param curl_err_buff A pointer to an char array which will be filled with error message.
133  * @return A pointer to the easy curl handle.
134  */
135 CURL* HTTPHelper::init_curl(string& curl_writedata_buff,char* curl_err_buff)
136 {
137     string user_agent = "Bullet Proof DYNDNS Daemon 0.1.1 - Intra2net AG 2009";
138
139     CURL *curl_easy_handle = curl_easy_init();
140     if ( curl_easy_handle == NULL )
141     {
142         // something went wrong.
143         CurlError = CURLE_FAILED_INIT;
144         Log->print_curl_error_init("Could not initialize CURL object.",CURLE_FAILED_INIT);
145         return NULL;
146     }
147
148     if ( CurlError == CURLE_OK )
149         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_NOPROGRESS,1);
150     if ( CurlError == CURLE_OK)
151         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_CONNECTTIMEOUT,5);
152     if ( CurlError == CURLE_OK)
153         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_TIMEOUT,10);
154     if ( CurlError == CURLE_OK)
155         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_BUFFERSIZE,1024);
156     if ( CurlError == CURLE_OK)
157         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_ERRORBUFFER,curl_err_buff);
158     if ( CurlError == CURLE_OK)
159         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEFUNCTION,http_receive);
160     if ( CurlError == CURLE_OK)
161         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_WRITEDATA,&curl_writedata_buff);
162     if ( CurlError == CURLE_OK)
163         CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_USERAGENT,&user_agent);
164
165     if ( !Proxy.empty() )
166     {
167         if ( CurlError == CURLE_OK)
168             CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXY,Proxy.c_str());
169         if ( CurlError == CURLE_OK)
170             CurlError = curl_easy_setopt(curl_easy_handle,CURLOPT_PROXYPORT,ProxyPort);
171     }
172
173     if ( CurlError != CURLE_OK )
174     {
175         // Some options could not be set, so destroy the CURL handle.
176         Log->print_curl_error_init("Could not set CURL options properly.",CurlError);
177         curl_easy_cleanup(curl_easy_handle);
178         curl_easy_handle = NULL;
179     }
180
181     return curl_easy_handle;
182 }
183
184
185 /**
186  * Test if the curl handle is initialized correctly.
187  * @return True if correctly initialized, false if something went wrong during initialization.
188  */
189 bool HTTPHelper::is_initialized()
190 {
191     if ( (CurlError == CURLE_OK) && (CurlEasyHandle != NULL) )
192     {
193         return true;
194     }
195     return false;
196 }
197
198
199 /**
200  * Sets a url to the easy curl handle
201  * @param url The url to set.
202  */
203 void HTTPHelper::set_curl_url(const string& url)
204 {
205     if ( CurlEasyHandle != NULL )
206     {
207         curl_easy_setopt(CurlEasyHandle,CURLOPT_URL,url.c_str());
208     }
209 }
210
211
212 /**
213  * Sets HTTP AUTH parameters
214  * @param username The username for HTTP AUTH
215  * @param password The password for HTTP AUTH
216  */
217 void HTTPHelper::set_curl_auth(const string& username, const string& password)
218 {
219     if ( CurlEasyHandle != NULL )
220     {
221         curl_easy_setopt(CurlEasyHandle,CURLOPT_USERNAME,username.c_str());
222         curl_easy_setopt(CurlEasyHandle,CURLOPT_PASSWORD,password.c_str());
223     }
224 }
225
226
227 /**
228  * Callback Function is called every time CURL is receiving data from HTTPS-Server and will copy all received Data to the given stream pointer
229  * @param inBuffer Pointer to input.
230  * @param size How many mem blocks are received
231  * @param nmemb size of each memblock
232  * @param outBuffer Pointer to output stream.
233  * @return The size received.
234  */
235 size_t HTTPHelper::http_receive( const char *inBuffer, size_t size, size_t nmemb, string *outBuffer )
236 {
237     outBuffer->append(inBuffer);
238     return (size*nmemb);
239 }
240