VirtualBox

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

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

iprt/http: added support for custom headers

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.1 KB
Line 
1
2/* $Id: http.cpp 43713 2012-10-23 15:11:35Z vboxsync $ */
3/** @file
4 * IPRT - HTTP communication API.
5 */
6
7/*
8 * Copyright (C) 2012 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 *
18 * The contents of this file may alternatively be used under the terms
19 * of the Common Development and Distribution License Version 1.0
20 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
21 * VirtualBox OSE distribution, in which case the provisions of the
22 * CDDL are applicable instead of those of the GPL.
23 *
24 * You may elect to license modified versions of this file under the
25 * terms and conditions of either the GPL or the CDDL or both.
26 */
27
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#include <iprt/http.h>
33#include <iprt/assert.h>
34#include <iprt/err.h>
35#include <iprt/mem.h>
36#include <iprt/string.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} RTHTTPINTERNAL;
52typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
53
54typedef struct RTHTTPMEMCHUNK
55{
56 char *pszMem;
57 size_t cb;
58} RTHTTPMEMCHUNK;
59typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
60
61/*******************************************************************************
62* Defined Constants And Macros *
63*******************************************************************************/
64#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
65
66/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
67#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
68 do { \
69 AssertPtrReturn((hHttp), (rcCurl)); \
70 AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
71 } while (0)
72
73/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
74#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
75
76/** Validates a handle and returns (void) if not valid. */
77#define RTHTTP_VALID_RETURN_VOID(hHttp) \
78 do { \
79 AssertPtrReturnVoid(hHttp); \
80 AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
81 } while (0)
82
83
84RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
85{
86 AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
87
88 CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
89 if (CURL_FAILED(rcCurl))
90 return VERR_INTERNAL_ERROR;
91
92 CURL* pCurl = curl_easy_init();
93 if (!pCurl)
94 return VERR_INTERNAL_ERROR;
95
96 PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
97 if (!pHttpInt)
98 return VERR_NO_MEMORY;
99
100 pHttpInt->u32Magic = RTHTTP_MAGIC;
101 pHttpInt->pCurl = pCurl;
102
103 *phHttp = (RTHTTP)pHttpInt;
104
105 return VINF_SUCCESS;
106}
107
108RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
109{
110 if (!hHttp)
111 return;
112
113 PRTHTTPINTERNAL pHttpInt = hHttp;
114 RTHTTP_VALID_RETURN_VOID(pHttpInt);
115
116 pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
117
118 curl_easy_cleanup(pHttpInt->pCurl);
119
120 if (pHttpInt->pHeaders)
121 curl_slist_free_all(pHttpInt->pHeaders);
122
123 RTMemFree(pHttpInt);
124
125 curl_global_cleanup();
126}
127
128static size_t rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
129{
130 PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
131 size_t cbAll = cb * n;
132
133 pMem->pszMem = (char*)RTMemRealloc(pMem->pszMem, pMem->cb + cbAll + 1);
134 if (pMem->pszMem)
135 {
136 memcpy(&pMem->pszMem[pMem->cb], pvBuf, cbAll);
137 pMem->cb += cbAll;
138 pMem->pszMem[pMem->cb] = '\0';
139 }
140 return cbAll;
141}
142
143RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
144 const char *pcszProxyUser, const char *pcszProxyPwd)
145{
146 PRTHTTPINTERNAL pHttpInt = hHttp;
147 RTHTTP_VALID_RETURN(pHttpInt);
148 AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
149
150 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
151 if (CURL_FAILED(rcCurl))
152 return VERR_INVALID_PARAMETER;
153
154 if (uPort != 0)
155 {
156 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
157 if (CURL_FAILED(rcCurl))
158 return VERR_INVALID_PARAMETER;
159 }
160
161 if (pcszProxyUser && pcszProxyPwd)
162 {
163 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
164 if (CURL_FAILED(rcCurl))
165 return VERR_INVALID_PARAMETER;
166
167 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
168 if (CURL_FAILED(rcCurl))
169 return VERR_INVALID_PARAMETER;
170 }
171
172 return VINF_SUCCESS;
173}
174
175RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, uint32_t cHeaders, const char *pcszHeaders[])
176{
177 PRTHTTPINTERNAL pHttpInt = hHttp;
178 RTHTTP_VALID_RETURN(pHttpInt);
179
180 if (!cHeaders)
181 {
182 if (pHttpInt->pHeaders)
183 curl_slist_free_all(pHttpInt->pHeaders);
184 pHttpInt->pHeaders = 0;
185 return VINF_SUCCESS;
186 }
187
188 struct curl_slist* pHeaders = NULL;
189 for (unsigned i = 0; i < cHeaders; i++)
190 pHeaders = curl_slist_append(pHeaders, pcszHeaders[i]);
191
192 pHttpInt->pHeaders = pHeaders;
193 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
194 if (CURL_FAILED(rcCurl))
195 return VERR_INVALID_PARAMETER;
196
197 return VINF_SUCCESS;
198}
199
200RTR3DECL(int) RTHttpGet(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
201{
202 PRTHTTPINTERNAL pHttpInt = hHttp;
203 RTHTTP_VALID_RETURN(pHttpInt);
204
205 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
206 if (CURL_FAILED(rcCurl))
207 return VERR_INVALID_PARAMETER;
208
209#if 0
210 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
211 if (CURL_FAILED(rcCurl))
212 return VERR_INVALID_PARAMETER;
213#endif
214
215 /* XXX */
216 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, "/etc/ssl/certs/ca-certificates.crt");
217 if (CURL_FAILED(rcCurl))
218 return VERR_INTERNAL_ERROR;
219
220 RTHTTPMEMCHUNK chunk = { NULL, 0 };
221 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
222 if (CURL_FAILED(rcCurl))
223 return VERR_INTERNAL_ERROR;
224 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
225 if (CURL_FAILED(rcCurl))
226 return VERR_INTERNAL_ERROR;
227
228 rcCurl = curl_easy_perform(pHttpInt->pCurl);
229 int rc = VERR_INTERNAL_ERROR;
230 if (rcCurl == CURLE_OK)
231 {
232 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
233 switch (pHttpInt->lLastResp)
234 {
235 case 200:
236 /* OK, request was fulfilled */
237 case 204:
238 /* empty response */
239 rc = VINF_SUCCESS;
240 break;
241 case 400:
242 /* bad request */
243 rc = VERR_HTTP_BAD_REQUEST;
244 break;
245 case 403:
246 /* forbidden, authorization will not help */
247 rc = VERR_HTTP_ACCESS_DENIED;
248 break;
249 case 404:
250 /* URL not found */
251 rc = VERR_HTTP_NOT_FOUND;
252 break;
253 }
254 }
255 else
256 {
257 switch (rcCurl)
258 {
259 case CURLE_URL_MALFORMAT:
260 case CURLE_COULDNT_RESOLVE_HOST:
261 rc = VERR_HTTP_NOT_FOUND;
262 break;
263 default:
264 break;
265 }
266 }
267
268 *ppszResponse = chunk.pszMem;
269
270 return rc;
271}
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