VirtualBox

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

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

Runtime/http: add new function to set the filename containing the trusted root certificates, plus an extension of the testcase which fetches the root certificates

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: http.cpp 45331 2013-04-04 09:37:00Z 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.215389.xyz. 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 "internal/magics.h"
40
41
42/*******************************************************************************
43* Structures and Typedefs *
44*******************************************************************************/
45typedef struct RTHTTPINTERNAL
46{
47 uint32_t u32Magic;
48 CURL *pCurl;
49 long lLastResp;
50 struct curl_slist *pHeaders;
51 const char *pcszCAFile;
52} RTHTTPINTERNAL;
53typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
54
55typedef struct RTHTTPMEMCHUNK
56{
57 char *pszMem;
58 size_t cb;
59} RTHTTPMEMCHUNK;
60typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
61
62/*******************************************************************************
63* Defined Constants And Macros *
64*******************************************************************************/
65#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
66
67/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
68#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
69 do { \
70 AssertPtrReturn((hHttp), (rcCurl)); \
71 AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
72 } while (0)
73
74/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
75#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
76
77/** Validates a handle and returns (void) if not valid. */
78#define RTHTTP_VALID_RETURN_VOID(hHttp) \
79 do { \
80 AssertPtrReturnVoid(hHttp); \
81 AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
82 } while (0)
83
84
85RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
86{
87 AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
88
89 CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
90 if (CURL_FAILED(rcCurl))
91 return VERR_INTERNAL_ERROR;
92
93 CURL* pCurl = curl_easy_init();
94 if (!pCurl)
95 return VERR_INTERNAL_ERROR;
96
97 PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
98 if (!pHttpInt)
99 return VERR_NO_MEMORY;
100
101 pHttpInt->u32Magic = RTHTTP_MAGIC;
102 pHttpInt->pCurl = pCurl;
103
104 *phHttp = (RTHTTP)pHttpInt;
105
106 return VINF_SUCCESS;
107}
108
109RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
110{
111 if (!hHttp)
112 return;
113
114 PRTHTTPINTERNAL pHttpInt = hHttp;
115 RTHTTP_VALID_RETURN_VOID(pHttpInt);
116
117 pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
118
119 curl_easy_cleanup(pHttpInt->pCurl);
120
121 if (pHttpInt->pHeaders)
122 curl_slist_free_all(pHttpInt->pHeaders);
123
124 RTMemFree(pHttpInt);
125
126 curl_global_cleanup();
127}
128
129static size_t rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
130{
131 PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
132 size_t cbAll = cb * n;
133
134 pMem->pszMem = (char*)RTMemRealloc(pMem->pszMem, pMem->cb + cbAll + 1);
135 if (pMem->pszMem)
136 {
137 memcpy(&pMem->pszMem[pMem->cb], pvBuf, cbAll);
138 pMem->cb += cbAll;
139 pMem->pszMem[pMem->cb] = '\0';
140 }
141 return cbAll;
142}
143
144RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
145 const char *pcszProxyUser, const char *pcszProxyPwd)
146{
147 PRTHTTPINTERNAL pHttpInt = hHttp;
148 RTHTTP_VALID_RETURN(pHttpInt);
149 AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
150
151 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
152 if (CURL_FAILED(rcCurl))
153 return VERR_INVALID_PARAMETER;
154
155 if (uPort != 0)
156 {
157 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
158 if (CURL_FAILED(rcCurl))
159 return VERR_INVALID_PARAMETER;
160 }
161
162 if (pcszProxyUser && pcszProxyPwd)
163 {
164 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
165 if (CURL_FAILED(rcCurl))
166 return VERR_INVALID_PARAMETER;
167
168 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
169 if (CURL_FAILED(rcCurl))
170 return VERR_INVALID_PARAMETER;
171 }
172
173 return VINF_SUCCESS;
174}
175
176RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, uint32_t cHeaders, const char *pcszHeaders[])
177{
178 PRTHTTPINTERNAL pHttpInt = hHttp;
179 RTHTTP_VALID_RETURN(pHttpInt);
180
181 if (!cHeaders)
182 {
183 if (pHttpInt->pHeaders)
184 curl_slist_free_all(pHttpInt->pHeaders);
185 pHttpInt->pHeaders = 0;
186 return VINF_SUCCESS;
187 }
188
189 struct curl_slist* pHeaders = NULL;
190 for (unsigned i = 0; i < cHeaders; i++)
191 pHeaders = curl_slist_append(pHeaders, pcszHeaders[i]);
192
193 pHttpInt->pHeaders = pHeaders;
194 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
195 if (CURL_FAILED(rcCurl))
196 return VERR_INVALID_PARAMETER;
197
198 return VINF_SUCCESS;
199}
200
201RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
202{
203 PRTHTTPINTERNAL pHttpInt = hHttp;
204 RTHTTP_VALID_RETURN(pHttpInt);
205
206 pHttpInt->pcszCAFile = pcszCAFile;
207
208 return VINF_SUCCESS;
209}
210
211RTR3DECL(int) RTHttpGet(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
212{
213 PRTHTTPINTERNAL pHttpInt = hHttp;
214 RTHTTP_VALID_RETURN(pHttpInt);
215
216 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
217 if (CURL_FAILED(rcCurl))
218 return VERR_INVALID_PARAMETER;
219
220#if 0
221 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
222 if (CURL_FAILED(rcCurl))
223 return VERR_INVALID_PARAMETER;
224#endif
225
226 const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
227 if (pHttpInt->pcszCAFile)
228 pcszCAFile = pHttpInt->pcszCAFile;
229 if (RTFileExists(pcszCAFile))
230 {
231 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
232 if (CURL_FAILED(rcCurl))
233 return VERR_INTERNAL_ERROR;
234 }
235
236 RTHTTPMEMCHUNK chunk = { NULL, 0 };
237 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
238 if (CURL_FAILED(rcCurl))
239 return VERR_INTERNAL_ERROR;
240 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
241 if (CURL_FAILED(rcCurl))
242 return VERR_INTERNAL_ERROR;
243
244 rcCurl = curl_easy_perform(pHttpInt->pCurl);
245 int rc = VERR_INTERNAL_ERROR;
246 if (rcCurl == CURLE_OK)
247 {
248 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
249 switch (pHttpInt->lLastResp)
250 {
251 case 200:
252 /* OK, request was fulfilled */
253 case 204:
254 /* empty response */
255 rc = VINF_SUCCESS;
256 break;
257 case 400:
258 /* bad request */
259 rc = VERR_HTTP_BAD_REQUEST;
260 break;
261 case 403:
262 /* forbidden, authorization will not help */
263 rc = VERR_HTTP_ACCESS_DENIED;
264 break;
265 case 404:
266 /* URL not found */
267 rc = VERR_HTTP_NOT_FOUND;
268 break;
269 }
270 }
271 else
272 {
273 switch (rcCurl)
274 {
275 case CURLE_URL_MALFORMAT:
276 case CURLE_COULDNT_RESOLVE_HOST:
277 rc = VERR_HTTP_NOT_FOUND;
278 break;
279 default:
280 break;
281 }
282 }
283
284 *ppszResponse = chunk.pszMem;
285
286 return rc;
287}
Note: See TracBrowser for help on using the repository browser.

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