VirtualBox

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

Last change on this file since 57546 was 57516, checked in by vboxsync, 9 years ago

Runtime/http: additional error code

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 18.6 KB
Line 
1/* $Id: http.cpp 57516 2015-08-24 21:13:13Z vboxsync $ */
2/** @file
3 * IPRT - HTTP communication API.
4 */
5
6/*
7 * Copyright (C) 2012-2015 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 "internal/iprt.h"
33
34#include <iprt/assert.h>
35#include <iprt/env.h>
36#include <iprt/err.h>
37#include <iprt/mem.h>
38#include <iprt/string.h>
39#include <iprt/file.h>
40#include <iprt/stream.h>
41
42#include <curl/curl.h>
43#include <openssl/ssl.h>
44#include "internal/magics.h"
45
46
47/*********************************************************************************************************************************
48* Structures and Typedefs *
49*********************************************************************************************************************************/
50typedef struct RTHTTPINTERNAL
51{
52 /** Magic value. */
53 uint32_t u32Magic;
54 /** cURL handle. */
55 CURL *pCurl;
56 /** The last response code. */
57 long lLastResp;
58 /** custom headers */
59 struct curl_slist *pHeaders;
60 /** CA certificate for HTTPS authentication check. */
61 char *pcszCAFile;
62 /** Abort the current HTTP request if true. */
63 bool fAbort;
64 /** The location field for 301 responses. */
65 char *pszRedirLocation;
66} RTHTTPINTERNAL;
67typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
68
69typedef struct RTHTTPMEMCHUNK
70{
71 uint8_t *pu8Mem;
72 size_t cb;
73} RTHTTPMEMCHUNK;
74typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
75
76
77/*********************************************************************************************************************************
78* Defined Constants And Macros *
79*********************************************************************************************************************************/
80#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
81
82/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
83#define RTHTTP_VALID_RETURN_RC(hHttp, rcCurl) \
84 do { \
85 AssertPtrReturn((hHttp), (rcCurl)); \
86 AssertReturn((hHttp)->u32Magic == RTHTTP_MAGIC, (rcCurl)); \
87 } while (0)
88
89/** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
90#define RTHTTP_VALID_RETURN(hHTTP) RTHTTP_VALID_RETURN_RC((hHttp), VERR_INVALID_HANDLE)
91
92/** Validates a handle and returns (void) if not valid. */
93#define RTHTTP_VALID_RETURN_VOID(hHttp) \
94 do { \
95 AssertPtrReturnVoid(hHttp); \
96 AssertReturnVoid((hHttp)->u32Magic == RTHTTP_MAGIC); \
97 } while (0)
98
99
100RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
101{
102 AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
103
104 CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
105 if (CURL_FAILED(rcCurl))
106 return VERR_HTTP_INIT_FAILED;
107
108 CURL *pCurl = curl_easy_init();
109 if (!pCurl)
110 return VERR_HTTP_INIT_FAILED;
111
112 PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
113 if (!pHttpInt)
114 return VERR_NO_MEMORY;
115
116 pHttpInt->u32Magic = RTHTTP_MAGIC;
117 pHttpInt->pCurl = pCurl;
118
119 *phHttp = (RTHTTP)pHttpInt;
120
121 return VINF_SUCCESS;
122}
123
124RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
125{
126 if (!hHttp)
127 return;
128
129 PRTHTTPINTERNAL pHttpInt = hHttp;
130 RTHTTP_VALID_RETURN_VOID(pHttpInt);
131
132 pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
133
134 curl_easy_cleanup(pHttpInt->pCurl);
135
136 if (pHttpInt->pHeaders)
137 curl_slist_free_all(pHttpInt->pHeaders);
138
139 if (pHttpInt->pcszCAFile)
140 RTStrFree(pHttpInt->pcszCAFile);
141
142 if (pHttpInt->pszRedirLocation)
143 RTStrFree(pHttpInt->pszRedirLocation);
144
145 RTMemFree(pHttpInt);
146
147 curl_global_cleanup();
148}
149
150static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
151{
152 PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
153 size_t cbAll = cb * n;
154
155 pMem->pu8Mem = (uint8_t*)RTMemRealloc(pMem->pu8Mem, pMem->cb + cbAll + 1);
156 if (pMem->pu8Mem)
157 {
158 memcpy(&pMem->pu8Mem[pMem->cb], pvBuf, cbAll);
159 pMem->cb += cbAll;
160 pMem->pu8Mem[pMem->cb] = '\0';
161 }
162 return cbAll;
163}
164
165static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow,
166 double UlTotal, double UlNow)
167{
168 PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData;
169 AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1);
170
171 return pHttpInt->fAbort ? 1 : 0;
172}
173
174RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
175{
176 PRTHTTPINTERNAL pHttpInt = hHttp;
177 RTHTTP_VALID_RETURN(pHttpInt);
178
179 pHttpInt->fAbort = true;
180
181 return VINF_SUCCESS;
182}
183
184RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation)
185{
186 PRTHTTPINTERNAL pHttpInt = hHttp;
187 RTHTTP_VALID_RETURN(pHttpInt);
188
189 if (!pHttpInt->pszRedirLocation)
190 return VERR_HTTP_NOT_FOUND;
191
192 *ppszRedirLocation = RTStrDup(pHttpInt->pszRedirLocation);
193 return VINF_SUCCESS;
194}
195
196RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
197{
198 PRTHTTPINTERNAL pHttpInt = hHttp;
199 RTHTTP_VALID_RETURN(pHttpInt);
200
201 /*
202 * Very limited right now, just enought to make it work for ourselves.
203 */
204 char szProxy[_1K];
205 int rc = RTEnvGetEx(RTENV_DEFAULT, "http_proxy", szProxy, sizeof(szProxy), NULL);
206 if (RT_SUCCESS(rc))
207 {
208 int rcCurl;
209 if (!strncmp(szProxy, RT_STR_TUPLE("http://")))
210 {
211 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
212 if (CURL_FAILED(rcCurl))
213 return VERR_INVALID_PARAMETER;
214 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80);
215 if (CURL_FAILED(rcCurl))
216 return VERR_INVALID_PARAMETER;
217 }
218 else
219 {
220 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
221 if (CURL_FAILED(rcCurl))
222 return VERR_INVALID_PARAMETER;
223 }
224 }
225 else if (rc == VERR_ENV_VAR_NOT_FOUND)
226 rc = VINF_SUCCESS;
227
228 return rc;
229}
230
231RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxy, uint32_t uPort,
232 const char *pcszProxyUser, const char *pcszProxyPwd)
233{
234 PRTHTTPINTERNAL pHttpInt = hHttp;
235 RTHTTP_VALID_RETURN(pHttpInt);
236 AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
237
238 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
239 if (CURL_FAILED(rcCurl))
240 return VERR_INVALID_PARAMETER;
241
242 if (uPort != 0)
243 {
244 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
245 if (CURL_FAILED(rcCurl))
246 return VERR_INVALID_PARAMETER;
247 }
248
249 if (pcszProxyUser && pcszProxyPwd)
250 {
251 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
252 if (CURL_FAILED(rcCurl))
253 return VERR_INVALID_PARAMETER;
254
255 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
256 if (CURL_FAILED(rcCurl))
257 return VERR_INVALID_PARAMETER;
258 }
259
260 return VINF_SUCCESS;
261}
262
263RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
264{
265 PRTHTTPINTERNAL pHttpInt = hHttp;
266 RTHTTP_VALID_RETURN(pHttpInt);
267
268 if (!cHeaders)
269 {
270 if (pHttpInt->pHeaders)
271 curl_slist_free_all(pHttpInt->pHeaders);
272 pHttpInt->pHeaders = 0;
273 return VINF_SUCCESS;
274 }
275
276 struct curl_slist *pHeaders = NULL;
277 for (size_t i = 0; i < cHeaders; i++)
278 pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
279
280 pHttpInt->pHeaders = pHeaders;
281 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
282 if (CURL_FAILED(rcCurl))
283 return VERR_INVALID_PARAMETER;
284
285 return VINF_SUCCESS;
286}
287
288RTR3DECL(int) RTHttpCertDigest(RTHTTP hHttp, char *pcszCert, size_t cbCert,
289 uint8_t **pabSha1, size_t *pcbSha1,
290 uint8_t **pabSha512, size_t *pcbSha512)
291{
292 int rc = VINF_SUCCESS;
293
294 BIO *cert = BIO_new_mem_buf(pcszCert, (int)cbCert);
295 if (cert)
296 {
297 X509 *crt = NULL;
298 if (PEM_read_bio_X509(cert, &crt, NULL, NULL))
299 {
300 unsigned cb;
301 unsigned char md[EVP_MAX_MD_SIZE];
302
303 int rc1 = X509_digest(crt, EVP_sha1(), md, &cb);
304 if (rc1 > 0)
305 {
306 *pabSha1 = (uint8_t*)RTMemAlloc(cb);
307 if (*pabSha1)
308 {
309 memcpy(*pabSha1, md, cb);
310 *pcbSha1 = cb;
311
312 rc1 = X509_digest(crt, EVP_sha512(), md, &cb);
313 if (rc1 > 0)
314 {
315 *pabSha512 = (uint8_t*)RTMemAlloc(cb);
316 if (*pabSha512)
317 {
318 memcpy(*pabSha512, md, cb);
319 *pcbSha512 = cb;
320 }
321 else
322 rc = VERR_NO_MEMORY;
323 }
324 else
325 rc = VERR_HTTP_CACERT_WRONG_FORMAT;
326
327 if (RT_FAILURE(rc))
328 RTMemFree(*pabSha1);
329 }
330 else
331 rc = VERR_NO_MEMORY;
332 }
333 else
334 rc = VERR_HTTP_CACERT_WRONG_FORMAT;
335 X509_free(crt);
336 }
337 else
338 rc = VERR_HTTP_CACERT_WRONG_FORMAT;
339 BIO_free(cert);
340 }
341 else
342 rc = VERR_INTERNAL_ERROR;
343
344 return rc;
345}
346
347RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
348{
349 PRTHTTPINTERNAL pHttpInt = hHttp;
350 RTHTTP_VALID_RETURN(pHttpInt);
351
352 if (pHttpInt->pcszCAFile)
353 RTStrFree(pHttpInt->pcszCAFile);
354 pHttpInt->pcszCAFile = RTStrDup(pcszCAFile);
355 if (!pHttpInt->pcszCAFile)
356 return VERR_NO_MEMORY;
357
358 return VINF_SUCCESS;
359}
360
361
362/**
363 * Figures out the IPRT status code for a GET.
364 *
365 * @returns IPRT status code.
366 * @param pHttpInt HTTP instance.
367 * @param rcCurl What curl returned.
368 */
369static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl)
370{
371 int rc = VERR_INTERNAL_ERROR;
372
373 if (pHttpInt->pszRedirLocation)
374 {
375 RTStrFree(pHttpInt->pszRedirLocation);
376 pHttpInt->pszRedirLocation = NULL;
377 }
378 if (rcCurl == CURLE_OK)
379 {
380 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
381 switch (pHttpInt->lLastResp)
382 {
383 case 200:
384 /* OK, request was fulfilled */
385 case 204:
386 /* empty response */
387 rc = VINF_SUCCESS;
388 break;
389 case 301:
390 {
391 const char *pszRedirect;
392 curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
393 size_t cb = strlen(pszRedirect);
394 if (cb > 0 && cb < 2048)
395 pHttpInt->pszRedirLocation = RTStrDup(pszRedirect);
396 rc = VERR_HTTP_REDIRECTED;
397 break;
398 }
399 case 400:
400 /* bad request */
401 rc = VERR_HTTP_BAD_REQUEST;
402 break;
403 case 403:
404 /* forbidden, authorization will not help */
405 rc = VERR_HTTP_ACCESS_DENIED;
406 break;
407 case 404:
408 /* URL not found */
409 rc = VERR_HTTP_NOT_FOUND;
410 break;
411 }
412 }
413 else
414 {
415 switch (rcCurl)
416 {
417 case CURLE_URL_MALFORMAT:
418 case CURLE_COULDNT_RESOLVE_HOST:
419 rc = VERR_HTTP_NOT_FOUND;
420 break;
421 case CURLE_COULDNT_CONNECT:
422 rc = VERR_HTTP_COULDNT_CONNECT;
423 break;
424 case CURLE_SSL_CONNECT_ERROR:
425 rc = VERR_HTTP_SSL_CONNECT_ERROR;
426 break;
427 case CURLE_SSL_CACERT:
428 /* The peer certificate cannot be authenticated with the CA certificates
429 * set by RTHttpSetCAFile(). We need other or additional CA certificates. */
430 rc = VERR_HTTP_CACERT_CANNOT_AUTHENTICATE;
431 break;
432 case CURLE_SSL_CACERT_BADFILE:
433 /* CAcert file (see RTHttpSetCAFile()) has wrong format */
434 rc = VERR_HTTP_CACERT_WRONG_FORMAT;
435 break;
436 case CURLE_ABORTED_BY_CALLBACK:
437 /* forcefully aborted */
438 rc = VERR_HTTP_ABORTED;
439 break;
440 case CURLE_COULDNT_RESOLVE_PROXY:
441 rc = VERR_HTTP_PROXY_NOT_FOUND;
442 break;
443 default:
444 break;
445 }
446 }
447
448 return rc;
449}
450
451RTR3DECL(int) rtHttpGet(RTHTTP hHttp, const char *pcszUrl, uint8_t **ppvResponse, size_t *pcb)
452{
453 PRTHTTPINTERNAL pHttpInt = hHttp;
454 RTHTTP_VALID_RETURN(pHttpInt);
455
456 pHttpInt->fAbort = false;
457
458 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
459 if (CURL_FAILED(rcCurl))
460 return VERR_INVALID_PARAMETER;
461
462#if 0
463 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
464 if (CURL_FAILED(rcCurl))
465 return VERR_INVALID_PARAMETER;
466#endif
467
468 const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
469 if (pHttpInt->pcszCAFile)
470 pcszCAFile = pHttpInt->pcszCAFile;
471 if (RTFileExists(pcszCAFile))
472 {
473 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
474 if (CURL_FAILED(rcCurl))
475 return VERR_INTERNAL_ERROR;
476 }
477
478 RTHTTPMEMCHUNK chunk = { NULL, 0 };
479 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
480 if (CURL_FAILED(rcCurl))
481 return VERR_INTERNAL_ERROR;
482 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void*)&chunk);
483 if (CURL_FAILED(rcCurl))
484 return VERR_INTERNAL_ERROR;
485 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
486 if (CURL_FAILED(rcCurl))
487 return VERR_INTERNAL_ERROR;
488 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
489 if (CURL_FAILED(rcCurl))
490 return VERR_INTERNAL_ERROR;
491 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
492 if (CURL_FAILED(rcCurl))
493 return VERR_INTERNAL_ERROR;
494 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
495 if (CURL_FAILED(rcCurl))
496 return VERR_INVALID_PARAMETER;
497
498 rcCurl = curl_easy_perform(pHttpInt->pCurl);
499 int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
500 *ppvResponse = chunk.pu8Mem;
501 *pcb = chunk.cb;
502
503 return rc;
504}
505
506
507RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszResponse)
508{
509 uint8_t *pv;
510 size_t cb;
511 int rc = rtHttpGet(hHttp, pcszUrl, &pv, &cb);
512 *ppszResponse = (char*)pv;
513 return rc;
514}
515
516
517RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb)
518{
519 return rtHttpGet(hHttp, pcszUrl, (uint8_t**)ppvResponse, pcb);
520}
521
522
523static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser)
524{
525 size_t cbAll = cb * n;
526 RTFILE hFile = (RTFILE)(intptr_t)pvUser;
527
528 size_t cbWritten = 0;
529 int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten);
530 if (RT_SUCCESS(rc))
531 return cbWritten;
532 return 0;
533}
534
535
536RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
537{
538 PRTHTTPINTERNAL pHttpInt = hHttp;
539 RTHTTP_VALID_RETURN(pHttpInt);
540
541 /*
542 * Set up the request.
543 */
544 pHttpInt->fAbort = false;
545
546 int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl);
547 if (CURL_FAILED(rcCurl))
548 return VERR_INVALID_PARAMETER;
549
550#if 0
551 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
552 if (CURL_FAILED(rcCurl))
553 return VERR_INVALID_PARAMETER;
554#endif
555
556 const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
557 if (pHttpInt->pcszCAFile)
558 pcszCAFile = pHttpInt->pcszCAFile;
559 if (RTFileExists(pcszCAFile))
560 {
561 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
562 if (CURL_FAILED(rcCurl))
563 return VERR_INTERNAL_ERROR;
564 }
565
566 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
567 if (CURL_FAILED(rcCurl))
568 return VERR_INTERNAL_ERROR;
569 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
570 if (CURL_FAILED(rcCurl))
571 return VERR_INTERNAL_ERROR;
572 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void*)pHttpInt);
573 if (CURL_FAILED(rcCurl))
574 return VERR_INTERNAL_ERROR;
575 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
576 if (CURL_FAILED(rcCurl))
577 return VERR_INTERNAL_ERROR;
578
579 /*
580 * Open the output file.
581 */
582 RTFILE hFile;
583 int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE);
584 if (RT_SUCCESS(rc))
585 {
586 rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile);
587 if (!CURL_FAILED(rcCurl))
588 {
589 /*
590 * Perform the request.
591 */
592 rcCurl = curl_easy_perform(pHttpInt->pCurl);
593 rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
594 }
595 else
596 rc = VERR_INTERNAL_ERROR;
597
598 int rc2 = RTFileClose(hFile);
599 if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
600 rc = rc2;
601 }
602
603 return rc;
604}
605
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