VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/misc/http.cpp@ 45381

Last change on this file since 45381 was 45381, checked in by vboxsync, 12 years ago

Runtime/http: added error code + don't make tstHttp fail if we can't connect

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: http.cpp 45381 2013-04-05 15:00:45Z vboxsync $ */
2/** @file
3 * IPRT - HTTP communication API.
4 */
5
6/*
7 * Copyright (C) 2012-2013 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include <iprt/http.h>
32#include <iprt/assert.h>
33#include <iprt/err.h>
34#include <iprt/mem.h>
35#include <iprt/string.h>
36#include <iprt/file.h>
37
38#include <curl/curl.h>
39#include <openssl/ssl.h>
40#include "internal/magics.h"
41
42
43/*******************************************************************************
44* Structures and Typedefs *
45*******************************************************************************/
46typedef struct RTHTTPINTERNAL
47{
48 uint32_t u32Magic;
49 CURL *pCurl;
50 long lLastResp;
51 struct curl_slist *pHeaders;
52 const char *pcszCAFile;
53} RTHTTPINTERNAL;
54typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
55
56typedef struct RTHTTPMEMCHUNK
57{
58 char *pszMem;
59 size_t cb;
60} RTHTTPMEMCHUNK;
61typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
62
63/*******************************************************************************
64* Defined Constants And Macros *
65*******************************************************************************/
66#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
67
68/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
69#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
70 do { \
71 AssertPtrReturn((hHttp), (rcCurl)); \
72 AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
73 } while (0)
74
75/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
76#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
77
78/** Validates a handle and returns (void) if not valid. */
79#define RTHTTP_VALID_RETURN_VOID(hHttp) \
80 do { \
81 AssertPtrReturnVoid(hHttp); \
82 AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
83 } while (0)
84
85
86RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
87{
88 AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
89
90 CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
91 if (CURL_FAILED(rcCurl))
92 return VERR_INTERNAL_ERROR;
93
94 CURL *pCurl = curl_easy_init();
95 if (!pCurl)
96 return VERR_INTERNAL_ERROR;
97
98 PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
99 if (!pHttpInt)
100 return VERR_NO_MEMORY;
101
102 pHttpInt->u32Magic = RTHTTP_MAGIC;
103 pHttpInt->pCurl = pCurl;
104
105 *phHttp = (RTHTTP)pHttpInt;
106
107 return VINF_SUCCESS;
108}
109
110RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
111{
112 if (!hHttp)
113 return;
114
115 PRTHTTPINTERNAL pHttpInt = hHttp;
116 RTHTTP_VALID_RETURN_VOID(pHttpInt);
117
118 pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
119
120 curl_easy_cleanup(pHttpInt->pCurl);
121
122 if (pHttpInt->pHeaders)
123 curl_slist_free_all(pHttpInt->pHeaders);
124
125 RTMemFree(pHttpInt);
126
127 curl_global_cleanup();
128}
129
130static size_t rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
131{
132 PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
133 size_t cbAll = cb * n;
134
135 pMem->pszMem = (char*)RTMemRealloc(pMem->pszMem, pMem->cb + cbAll + 1);
136 if (pMem->pszMem)
137 {
138 memcpy(&pMem->pszMem[pMem->cb], pvBuf, cbAll);
139 pMem->cb += cbAll;
140 pMem->pszMem[pMem->cb] = '\0';
141 }
142 return cbAll;
143}
144
145RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
146 const char *pcszProxyUser, const char *pcszProxyPwd)
147{
148 PRTHTTPINTERNAL pHttpInt = hHttp;
149 RTHTTP_VALID_RETURN(pHttpInt);
150 AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
151
152 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
153 if (CURL_FAILED(rcCurl))
154 return VERR_INVALID_PARAMETER;
155
156 if (uPort != 0)
157 {
158 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
159 if (CURL_FAILED(rcCurl))
160 return VERR_INVALID_PARAMETER;
161 }
162
163 if (pcszProxyUser && pcszProxyPwd)
164 {
165 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
166 if (CURL_FAILED(rcCurl))
167 return VERR_INVALID_PARAMETER;
168
169 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
170 if (CURL_FAILED(rcCurl))
171 return VERR_INVALID_PARAMETER;
172 }
173
174 return VINF_SUCCESS;
175}
176
177RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, uint32_t cHeaders, const char *pcszHeaders[])
178{
179 PRTHTTPINTERNAL pHttpInt = hHttp;
180 RTHTTP_VALID_RETURN(pHttpInt);
181
182 if (!cHeaders)
183 {
184 if (pHttpInt->pHeaders)
185 curl_slist_free_all(pHttpInt->pHeaders);
186 pHttpInt->pHeaders = 0;
187 return VINF_SUCCESS;
188 }
189
190 struct curl_slist *pHeaders = NULL;
191 for (unsigned i = 0; i < cHeaders; i++)
192 pHeaders = curl_slist_append(pHeaders, pcszHeaders[i]);
193
194 pHttpInt->pHeaders = pHeaders;
195 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
196 if (CURL_FAILED(rcCurl))
197 return VERR_INVALID_PARAMETER;
198
199 return VINF_SUCCESS;
200}
201
202RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert,
203 uint8_t **pabSha1, size_t *pcbSha1,
204 uint8_t **pabSha512, size_t *pcbSha512)
205{
206 int rc = VINF_SUCCESS;
207
208 BIO *cert = BIO_new_mem_buf(pcszCert, (int)cbCert);
209 if (cert)
210 {
211 X509 *crt = NULL;
212 if (PEM_read_bio_X509(cert, &crt, NULL, NULL))
213 {
214 unsigned cb;
215 unsigned char md[EVP_MAX_MD_SIZE];
216
217 int rc1 = X509_digest(crt, EVP_sha1(), md, &cb);
218 if (rc1 > 0)
219 {
220 *pabSha1 = (uint8_t*)RTMemAlloc(cb);
221 if (*pabSha1)
222 {
223 memcpy(*pabSha1, md, cb);
224 *pcbSha1 = cb;
225
226 rc1 = X509_digest(crt, EVP_sha512(), md, &cb);
227 if (rc1 > 0)
228 {
229 *pabSha512 = (uint8_t*)RTMemAlloc(cb);
230 if (*pabSha512)
231 {
232 memcpy(*pabSha512, md, cb);
233 *pcbSha512 = cb;
234 }
235 else
236 rc = VERR_NO_MEMORY;
237 }
238 else
239 rc = VERR_INTERNAL_ERROR;
240 }
241 else
242 rc = VERR_NO_MEMORY;
243 }
244 else
245 rc = VERR_INTERNAL_ERROR;
246 X509_free(crt);
247 }
248 else
249 rc = VERR_INTERNAL_ERROR;
250 BIO_free(cert);
251 }
252 else
253 rc = VERR_INTERNAL_ERROR;
254
255 if (RT_FAILURE(rc))
256 {
257 RTMemFree(*pabSha512);
258 RTMemFree(*pabSha1);
259 }
260
261 return rc;
262}
263
264RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
265{
266 PRTHTTPINTERNAL pHttpInt = hHttp;
267 RTHTTP_VALID_RETURN(pHttpInt);
268
269 pHttpInt->pcszCAFile = pcszCAFile;
270
271 return VINF_SUCCESS;
272}
273
274RTR3DECL(int) RTHttpGet(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
275{
276 PRTHTTPINTERNAL pHttpInt = hHttp;
277 RTHTTP_VALID_RETURN(pHttpInt);
278
279 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
280 if (CURL_FAILED(rcCurl))
281 return VERR_INVALID_PARAMETER;
282
283#if 0
284 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
285 if (CURL_FAILED(rcCurl))
286 return VERR_INVALID_PARAMETER;
287#endif
288
289 const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
290 if (pHttpInt->pcszCAFile)
291 pcszCAFile = pHttpInt->pcszCAFile;
292 if (RTFileExists(pcszCAFile))
293 {
294 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
295 if (CURL_FAILED(rcCurl))
296 return VERR_INTERNAL_ERROR;
297 }
298
299 RTHTTPMEMCHUNK chunk = { NULL, 0 };
300 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
301 if (CURL_FAILED(rcCurl))
302 return VERR_INTERNAL_ERROR;
303 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
304 if (CURL_FAILED(rcCurl))
305 return VERR_INTERNAL_ERROR;
306
307 rcCurl = curl_easy_perform(pHttpInt->pCurl);
308 int rc = VERR_INTERNAL_ERROR;
309 if (rcCurl == CURLE_OK)
310 {
311 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
312 switch (pHttpInt->lLastResp)
313 {
314 case 200:
315 /* OK, request was fulfilled */
316 case 204:
317 /* empty response */
318 rc = VINF_SUCCESS;
319 break;
320 case 400:
321 /* bad request */
322 rc = VERR_HTTP_BAD_REQUEST;
323 break;
324 case 403:
325 /* forbidden, authorization will not help */
326 rc = VERR_HTTP_ACCESS_DENIED;
327 break;
328 case 404:
329 /* URL not found */
330 rc = VERR_HTTP_NOT_FOUND;
331 break;
332 }
333 }
334 else
335 {
336 switch (rcCurl)
337 {
338 case CURLE_URL_MALFORMAT:
339 case CURLE_COULDNT_RESOLVE_HOST:
340 rc = VERR_HTTP_NOT_FOUND;
341 break;
342 case CURLE_COULDNT_CONNECT:
343 rc = VERR_HTTP_COULDNT_CONNECT;
344 break;
345 default:
346 break;
347 }
348 }
349
350 *ppszResponse = chunk.pszMem;
351
352 return rc;
353}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette