Changeset 74062 in vbox for trunk/src/VBox/Runtime/generic/http-curl.cpp
- Timestamp:
- Sep 4, 2018 12:04:01 PM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Runtime/generic/http-curl.cpp
r74060 r74062 42 42 #include <iprt/asm.h> 43 43 #include <iprt/assert.h> 44 #include <iprt/base64.h> 44 45 #include <iprt/cidr.h> 45 46 #include <iprt/crypto/store.h> … … 58 59 #include <iprt/uni.h> 59 60 #include <iprt/uri.h> 61 #include <iprt/crypto/digest.h> 62 #include <iprt/crypto/pkix.h> 63 #include <iprt/crypto/key.h> 64 60 65 61 66 #include "internal/magics.h" … … 111 116 112 117 /** 118 * HTTP header. 119 */ 120 typedef struct RTHTTPHEADER 121 { 122 /** The core list structure. */ 123 struct curl_slist Core; 124 /** The field name length. */ 125 uint32_t cchName; 126 /** The value offset. */ 127 uint32_t offValue; 128 /** The full header field. */ 129 char szData[RT_FLEXIBLE_ARRAY]; 130 } RTHTTPHEADER; 131 /** Pointer to a HTTP header. */ 132 typedef RTHTTPHEADER *PRTHTTPHEADER; 133 134 /** 113 135 * Internal HTTP client instance. 114 136 */ … … 121 143 /** The last response code. */ 122 144 long lLastResp; 123 /** Custom headers/ */ 145 /** Custom headers (PRTHTTPHEADER). 146 * The list head is registered with curl, though we do all the allocating. */ 124 147 struct curl_slist *pHeaders; 148 /** Where to append the next header. */ 149 struct curl_slist **ppHeadersTail; 150 125 151 /** CA certificate file for HTTPS authentication. */ 126 152 char *pszCaFile; … … 291 317 static int rtHttpDarwinTryConfigProxies(PRTHTTPINTERNAL pThis, CFArrayRef hArrayProxies, CFURLRef hUrlTarget, bool fIgnorePacType); 292 318 #endif 319 static void rtHttpFreeHeaders(PRTHTTPINTERNAL pThis); 293 320 294 321 … … 311 338 pThis->u32Magic = RTHTTP_MAGIC; 312 339 pThis->pCurl = pCurl; 340 pThis->ppHeadersTail = &pThis->pHeaders; 341 pThis->fHaveSetUserAgent = false; 342 pThis->fHaveUserAgentHeader = false; 313 343 pThis->fUseSystemProxySettings = true; 314 344 pThis->cMaxRedirects = 0; /* no automatic redir following */ … … 316 346 pThis->HeadersOutput.pHttp = pThis; 317 347 348 318 349 *phHttp = (RTHTTP)pThis; 319 350 … … 361 392 pThis->pCurl = NULL; 362 393 363 if (pThis->pHeaders) 364 { 365 curl_slist_free_all(pThis->pHeaders); 366 pThis->pHeaders = NULL; 367 } 394 rtHttpFreeHeaders(pThis); 368 395 369 396 rtHttpUnsetCaFile(pThis); … … 1932 1959 * if it is now in one of the headers. 1933 1960 */ 1934 static void rtHttpUpdateUserAgentHeader(PRTHTTPINTERNAL pThis) 1935 { 1936 if ( pThis->fHaveUserAgentHeader 1937 && pThis->fHaveSetUserAgent) 1938 { 1939 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_USERAGENT, (char *)NULL); 1940 Assert(CURL_SUCCESS(rcCurl)); NOREF(rcCurl); 1941 pThis->fHaveSetUserAgent = false; 1942 } 1961 static int rtHttpUpdateUserAgentHeader(PRTHTTPINTERNAL pThis, PRTHTTPHEADER pNewHdr) 1962 { 1963 static const char s_szUserAgent[] = "User-Agent"; 1964 if ( pNewHdr->cchName == sizeof(s_szUserAgent) - 1 1965 && RTStrNICmpAscii(pNewHdr->szData, RT_STR_TUPLE(s_szUserAgent)) == 0) 1966 { 1967 pThis->fHaveUserAgentHeader = true; 1968 if (pThis->fHaveSetUserAgent) 1969 { 1970 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_USERAGENT, (char *)NULL); 1971 Assert(CURL_SUCCESS(rcCurl)); NOREF(rcCurl); 1972 pThis->fHaveSetUserAgent = false; 1973 } 1974 } 1975 return VINF_SUCCESS; 1976 } 1977 1978 1979 /** 1980 * Free the headers associated with the insance (w/o telling cURL about it). 1981 * 1982 * @param pThis The HTTP client instance. 1983 */ 1984 static void rtHttpFreeHeaders(PRTHTTPINTERNAL pThis) 1985 { 1986 struct curl_slist *pHead = pThis->pHeaders; 1987 pThis->pHeaders = NULL; 1988 pThis->ppHeadersTail = &pThis->pHeaders; 1989 pThis->fHaveUserAgentHeader = false; 1990 1991 while (pHead) 1992 { 1993 struct curl_slist *pFree = pHead; 1994 pHead = pHead->next; 1995 ASMCompilerBarrier(); /* paranoia */ 1996 1997 pFree->next = NULL; 1998 pFree->data = NULL; 1999 RTMemFree(pFree); 2000 } 2001 } 2002 2003 2004 /** 2005 * Worker for RTHttpSetHeaders and RTHttpAddHeader. 2006 * 2007 * @returns IPRT status code. 2008 * @param pThis The HTTP client instance. 2009 * @param pchName The field name. Does not need to be terminated. 2010 * @param cchName The field name length. 2011 * @param pchValue The field value. Does not need to be terminated. 2012 * @param cchValue The field value length. 2013 * @param fFlags RTHTTPADDHDR_F_XXX. 2014 */ 2015 static int rtHttpAddHeaderWorker(PRTHTTPINTERNAL pThis, const char *pchName, size_t cchName, 2016 const char *pchValue, size_t cchValue, uint32_t fFlags) 2017 { 2018 /* 2019 * Create the list entry. 2020 */ 2021 size_t cbData = cchName + 2 + cchValue + 1; 2022 PRTHTTPHEADER pHdr = (PRTHTTPHEADER)RTMemAlloc(RT_UOFFSETOF_DYN(RTHTTPHEADER, szData[cbData])); 2023 if (pHdr) 2024 { 2025 pHdr->Core.next = NULL; 2026 pHdr->Core.data = pHdr->szData; 2027 pHdr->cchName = (uint32_t)cchName; 2028 pHdr->offValue = (uint32_t)(cchName + 2); 2029 char *psz = pHdr->szData; 2030 memcpy(psz, pchName, cchName); 2031 psz += cchName; 2032 *psz++ = ':'; 2033 *psz++ = ' '; 2034 memcpy(psz, pchValue, cchValue); 2035 psz[cchValue] = '\0'; 2036 2037 /* 2038 * Append or prepend the header. 2039 */ 2040 AssertCompile(RTHTTPADDHDR_F_FRONT != 0); 2041 if (!(fFlags & RTHTTPADDHDR_F_FRONT)) 2042 { 2043 *pThis->ppHeadersTail = &pHdr->Core; 2044 pThis->ppHeadersTail = &pHdr->Core.next; 2045 if (pThis->pHeaders != NULL) 2046 return rtHttpUpdateUserAgentHeader(pThis, pHdr); 2047 2048 /* Need to update curl about the new list head. */ 2049 } 2050 else 2051 { 2052 pHdr->Core.next = pThis->pHeaders; 2053 if (!pThis->pHeaders) 2054 pThis->ppHeadersTail = &pHdr->Core.next; 2055 } 2056 pThis->pHeaders = &pHdr->Core; 2057 2058 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pThis->pHeaders); 2059 if (CURL_SUCCESS(rcCurl)) 2060 return rtHttpUpdateUserAgentHeader(pThis, pHdr); 2061 return VERR_HTTP_CURL_ERROR; 2062 } 2063 return VERR_NO_MEMORY; 1943 2064 } 1944 2065 … … 1954 2075 if (pThis->pHeaders) 1955 2076 { 1956 curl_slist_free_all(pThis->pHeaders);1957 pThis->pHeaders = NULL;1958 curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pThis->pHeaders);1959 }2077 rtHttpFreeHeaders(pThis); 2078 curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, (struct curl_slist *)NULL); 2079 } 2080 pThis->ppHeadersTail = &pThis->pHeaders; 1960 2081 pThis->fHaveUserAgentHeader = false; 1961 2082 … … 1967 2088 1968 2089 /* 1969 * Convert the headers into a curl string list, checking each string for User-Agent.1970 */ 1971 struct curl_slist *pHeaders = NULL;2090 * Add the headers, one by one. 2091 */ 2092 int rc = VINF_SUCCESS; 1972 2093 for (size_t i = 0; i < cHeaders; i++) 1973 2094 { 1974 struct curl_slist *pNewHeaders = curl_slist_append(pHeaders, papszHeaders[i]); 1975 if (pNewHeaders) 1976 pHeaders = pNewHeaders; 1977 else 1978 { 1979 if (pHeaders) 1980 curl_slist_free_all(pHeaders); 1981 return VERR_NO_MEMORY; 1982 } 1983 1984 if (strncmp(papszHeaders[i], RT_STR_TUPLE("User-Agent:")) == 0) 1985 pThis->fHaveUserAgentHeader = true; 1986 } 1987 1988 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pHeaders); 1989 if (CURL_FAILURE(rcCurl)) 1990 { 1991 curl_slist_free_all(pHeaders); 1992 return VERR_INVALID_PARAMETER; 1993 } 1994 pThis->pHeaders = pHeaders; 1995 1996 rtHttpUpdateUserAgentHeader(pThis); 1997 1998 return VINF_SUCCESS; 1999 } 2000 2001 2095 const char *pszHeader = papszHeaders[i]; 2096 size_t cchHeader = strlen(pszHeader); 2097 size_t cchName = (const char *)memchr(pszHeader, ':', cchHeader) - pszHeader; 2098 AssertBreakStmt(cchName < cchHeader, rc = VERR_INVALID_PARAMETER); 2099 size_t offValue = RT_C_IS_BLANK(pszHeader[cchName + 1]) ? cchName + 2 : cchName + 1; 2100 rc = rtHttpAddHeaderWorker(pThis, pszHeader, cchName, &pszHeader[offValue], cchHeader - offValue, RTHTTPADDHDR_F_BACK); 2101 AssertRCBreak(rc); 2102 } 2103 if (RT_SUCCESS(rc)) 2104 return rc; 2105 rtHttpFreeHeaders(pThis); 2106 curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, (struct curl_slist *)NULL); 2107 return rc; 2108 } 2109 2110 2111 #if 0 /** @todo reimplement RTHttpAddRawHeader if ever actually needed. */ 2002 2112 RTR3DECL(int) RTHttpAddRawHeader(RTHTTP hHttp, const char *pszHeader, uint32_t fFlags) 2003 2113 { … … 2040 2150 return VINF_SUCCESS; 2041 2151 } 2152 #endif 2042 2153 2043 2154 2044 2155 RTR3DECL(int) RTHttpAddHeader(RTHTTP hHttp, const char *pszField, const char *pszValue, uint32_t fFlags) 2045 2156 { 2046 2047 /* 2048 * Currently we don't any encoding here, so we just glue the two strings together. 2049 */ 2157 /* 2158 * Validate input and calc string lengths. 2159 */ 2160 PRTHTTPINTERNAL pThis = hHttp; 2161 RTHTTP_VALID_RETURN(pThis); 2162 AssertReturn(!(fFlags & ~RTHTTPADDHDR_F_BACK), VERR_INVALID_FLAGS); 2050 2163 AssertPtr(pszField); 2051 2164 size_t const cchField = strlen(pszField); … … 2064 2177 size_t const cchValue = strlen(pszValue); 2065 2178 2066 AssertReturn(!(fFlags & ~RTHTTPADDHDR_F_BACK), VERR_INVALID_FLAGS); 2067 2068 /* 2069 * Allocate a temporary buffer, construct the raw header string in it, 2070 * then use RTHttpAppendRawHeader to do the grunt work. 2071 */ 2072 size_t const cbNeeded = cchField + 2 + cchValue + 1; 2073 char *pszHeaderFree = NULL; 2074 char *pszHeader; 2075 if (cbNeeded < _2K) 2076 pszHeader = (char *)alloca(cbNeeded); 2077 else 2078 pszHeaderFree = pszHeader = (char *)RTMemTmpAlloc(cbNeeded); 2079 if (!pszHeader) 2080 return VERR_NO_TMP_MEMORY; 2081 2082 memcpy(pszHeader, pszField, cchField); 2083 pszHeader[cchField] = ':'; 2084 pszHeader[cchField + 1] = ' '; 2085 memcpy(&pszHeader[cchField + 2], pszValue, cchValue); 2086 pszHeader[cbNeeded - 1] = '\0'; 2087 2088 int rc = RTHttpAddRawHeader(hHttp, pszHeader, fFlags & RTHTTPADDHDR_F_FRONT); 2089 2090 if (pszHeaderFree) 2091 RTMemTmpFree(pszHeaderFree); 2092 return rc; 2179 /* 2180 * Just pass it along to the worker. 2181 */ 2182 return rtHttpAddHeaderWorker(pThis, pszField, cchField, pszValue, cchValue, fFlags); 2093 2183 } 2094 2184 … … 2099 2189 RTHTTP_VALID_RETURN_RC(pThis, NULL); 2100 2190 2101 struct curl_slist *pCur =pThis->pHeaders;2191 PRTHTTPHEADER pCur = (PRTHTTPHEADER)pThis->pHeaders; 2102 2192 if (pCur) 2103 2193 { … … 2106 2196 do 2107 2197 { 2108 /* strchr() is probably way faster than RTStrNICmpAscii(), so 2109 match the field name length first. */ 2110 const char *pszColon = strchr(pCur->data, ':'); 2111 if ( (size_t)(pszColon - pCur->data) == cchField 2112 && pszColon != NULL 2113 && RTStrNICmpAscii(pCur->data, pszField, cchField) == 0) 2198 if ( pCur->cchName == cchField 2199 && RTStrNICmpAscii(pCur->szData, pszField, cchField) == 0) 2200 return &pCur->szData[pCur->offValue]; 2201 2202 /* next field. */ 2203 pCur = (PRTHTTPHEADER)pCur->Core.next; 2204 } while (pCur); 2205 } 2206 return NULL; 2207 } 2208 2209 2210 RTR3DECL(int) RTHttpSignHeaders(RTHTTP hHttp, RTHTTPMETHOD enmMethod, const char *pszUrl, uint32_t fFlags, 2211 RTCRKEY hKey, const char *pszKeyId) 2212 { 2213 PRTHTTPINTERNAL pThis = hHttp; 2214 RTHTTP_VALID_RETURN_RC(pThis, NULL); 2215 AssertReturn(enmMethod > RTHTTPMETHOD_INVALID && enmMethod < RTHTTPMETHOD_END, VERR_INVALID_PARAMETER); 2216 AssertPtrReturn(pszUrl, VERR_INVALID_POINTER); 2217 AssertReturn(!fFlags, VERR_INVALID_FLAGS); 2218 AssertPtrReturn(pszKeyId, VERR_INVALID_POINTER); 2219 2220 /* 2221 * Do a little bit of preprocessing while we can easily return without 2222 * needing clean anything up.. 2223 */ 2224 RTURIPARSED ParsedUrl; 2225 int rc = RTUriParse(pszUrl, &ParsedUrl); 2226 AssertRCReturn(rc, rc); 2227 const char * const pszPath = pszUrl + ParsedUrl.offPath; 2228 2229 const char *pszMethodSp = NULL; 2230 switch (enmMethod) 2231 { 2232 case RTHTTPMETHOD_GET: pszMethodSp = "get "; break; 2233 case RTHTTPMETHOD_PUT: pszMethodSp = "put "; break; 2234 case RTHTTPMETHOD_POST: pszMethodSp = "post "; break; 2235 case RTHTTPMETHOD_PATCH: pszMethodSp = "patch "; break; 2236 case RTHTTPMETHOD_DELETE: pszMethodSp = "delete "; break; 2237 case RTHTTPMETHOD_HEAD: pszMethodSp = "head "; break; 2238 case RTHTTPMETHOD_OPTIONS: pszMethodSp = "options "; break; 2239 case RTHTTPMETHOD_TRACE: pszMethodSp = "trace "; break; 2240 /* no default! */ 2241 case RTHTTPMETHOD_INVALID: 2242 case RTHTTPMETHOD_END: 2243 case RTHTTPMETHOD_32BIT_HACK: 2244 break; 2245 } 2246 AssertReturn(pszMethodSp, VERR_INTERNAL_ERROR_4); 2247 2248 /* 2249 * We work the authorization header entry directly here to avoid extra copying and stuff. 2250 */ 2251 2252 /* Estimate required string length first. */ 2253 static const char s_szSuffixFmt[] = "Authorization: Signature version=\"1\",keyId=\"%s\",algorithm=\"rsa-sha256\",headers=\""; 2254 static const char s_szInfix[] = "\",signature=\"Base64(RSA-SHA256("; 2255 static const char s_szPostfix[] = "))\""; 2256 static const char s_szRequestField[] = "(request-target)"; 2257 size_t const cchKeyId = strlen(pszKeyId); 2258 size_t const cbSigRaw = (RTCrKeyGetBitCount(hKey) + 8) / 8; /** @todo ?? */ 2259 size_t const cbSigRawAligned = RT_ALIGN_Z(cbSigRaw, 8); 2260 size_t const cchSigStr = RTBase64EncodedLengthEx(cbSigRaw, RTBASE64_FLAGS_NO_LINE_BREAKS); 2261 size_t cbEstimated = sizeof(s_szSuffixFmt) + sizeof(s_szInfix) + sizeof(s_szPostfix) 2262 + cchKeyId + sizeof(s_szRequestField) + cchSigStr; 2263 for (PRTHTTPHEADER pCur = (PRTHTTPHEADER)pThis->pHeaders; pCur; pCur = (PRTHTTPHEADER)pCur->Core.next) 2264 cbEstimated += pCur->cchName + 1; 2265 cbEstimated += 32; /* safetype fudge */ 2266 /* Lazy bird: Put the raw signature at the end. */ 2267 cbEstimated = RT_ALIGN_Z(cbEstimated, 8) + cbSigRawAligned; 2268 2269 /* Allocate and initialize header entry. */ 2270 PRTHTTPHEADER const pHdr = (PRTHTTPHEADER)RTMemAllocZ(cbEstimated); 2271 AssertPtrReturn(pHdr, VERR_NO_MEMORY); 2272 uint8_t * const pbSigRaw = (uint8_t *)pHdr + cbEstimated - cbSigRawAligned; 2273 2274 pHdr->cchName = sizeof("Authorization") - 1; 2275 pHdr->offValue = sizeof("Authorization") + 1; 2276 char *pszLeft = pHdr->szData; 2277 size_t cbLeft = cbEstimated - RT_UOFFSETOF(RTHTTPHEADER, szData) - cbSigRawAligned; 2278 2279 size_t cch = RTStrPrintf(pszLeft, cbLeft, s_szSuffixFmt, pszKeyId); 2280 cbLeft -= cch; 2281 pszLeft += cch; 2282 2283 /* 2284 * Instantiate the digest. 2285 */ 2286 RTCRDIGEST hDigest = NIL_RTCRDIGEST; 2287 rc = RTCrDigestCreateByType(&hDigest, RTDIGESTTYPE_SHA256); 2288 if (RT_SUCCESS(rc)) 2289 { 2290 /* 2291 * Add the request-target pseudo header first. 2292 */ 2293 Assert(cbLeft > sizeof(s_szRequestField)); 2294 memcpy(pszLeft, RT_STR_TUPLE(s_szRequestField)); 2295 pszLeft += sizeof(s_szRequestField); 2296 2297 rc = RTCrDigestUpdate(hDigest, RT_STR_TUPLE(s_szRequestField)); 2298 if (RT_SUCCESS(rc)) 2299 rc = RTCrDigestUpdate(hDigest, RT_STR_TUPLE(": ")); 2300 if (RT_SUCCESS(rc)) 2301 rc = RTCrDigestUpdate(hDigest, pszMethodSp, strlen(pszMethodSp)); 2302 if (RT_SUCCESS(rc)) 2303 rc = RTCrDigestUpdate(hDigest, pszPath, strlen(pszPath)); 2304 2305 /* 2306 * Add the header fields. 2307 */ 2308 for (PRTHTTPHEADER pCur = (PRTHTTPHEADER)pThis->pHeaders; pCur && RT_SUCCESS(rc); pCur = (PRTHTTPHEADER)pCur->Core.next) 2309 { 2310 AssertBreakStmt(cbLeft > pCur->cchName, rc = VERR_INTERNAL_ERROR_3); 2311 memcpy(pszLeft, pCur->szData, pCur->cchName); 2312 pszLeft[pCur->cchName] = '\0'; 2313 RTStrToLower(pszLeft); 2314 2315 rc = RTCrDigestUpdate(hDigest, RT_STR_TUPLE("\n")); 2316 AssertRCBreak(rc); 2317 rc = RTCrDigestUpdate(hDigest, pszLeft, pCur->cchName); 2318 AssertRCBreak(rc); 2319 rc = RTCrDigestUpdate(hDigest, RT_STR_TUPLE(": ")); 2320 AssertRCBreak(rc); 2321 const char *pszValue = &pCur->szData[pCur->offValue]; 2322 rc = RTCrDigestUpdate(hDigest, pszValue, strlen(pszValue)); 2323 AssertRCBreak(rc); 2324 2325 pszLeft += pCur->cchName; 2326 cbLeft -= pCur->cchName; 2327 } 2328 if (RT_SUCCESS(rc)) 2329 AssertStmt(cbLeft > sizeof(s_szInfix) + cchSigStr + sizeof(s_szPostfix), rc = VERR_INTERNAL_ERROR_3); 2330 if (RT_SUCCESS(rc)) 2331 { 2332 /* Complete the header field part. */ 2333 memcpy(pszLeft, RT_STR_TUPLE(s_szInfix)); 2334 pszLeft += sizeof(s_szInfix) - 1; 2335 cbLeft -= sizeof(s_szInfix) - 1; 2336 2337 /* 2338 * Sign the digest. 2339 */ 2340 RTCRPKIXSIGNATURE hSigner; 2341 rc = RTCrPkixSignatureCreateByObjIdString(&hSigner, RTCR_PKCS1_SHA256_WITH_RSA_OID, hKey, NULL, true /*fSigning*/); 2342 AssertRC(rc); 2343 if (RT_SUCCESS(rc)) 2114 2344 { 2115 pszColon++; 2116 if (RT_C_IS_BLANK(*pszColon)) 2117 pszColon++; 2118 return pszColon; 2345 size_t cbActual = cbSigRawAligned; 2346 rc = RTCrPkixSignatureSign(hSigner, hDigest, pbSigRaw, &cbActual); 2347 AssertRC(rc); 2348 if (RT_SUCCESS(rc)) 2349 { 2350 RTCrPkixSignatureRelease(hSigner); 2351 hSigner = NIL_RTCRPKIXSIGNATURE; 2352 RTCrDigestRelease(hDigest); 2353 hDigest = NIL_RTCRDIGEST; 2354 2355 /* 2356 * Convert the signature to Base64 and append it to the string. 2357 */ 2358 size_t cchActual; 2359 rc = RTBase64EncodeEx(pbSigRaw, cbActual, RTBASE64_FLAGS_NO_LINE_BREAKS, pszLeft, cbLeft, &cchActual); 2360 AssertRC(rc); 2361 if (RT_SUCCESS(rc)) 2362 { 2363 Assert(cchActual == cchSigStr); 2364 pszLeft += cchActual; 2365 cbLeft -= cchActual; 2366 2367 /* 2368 * Append the postfix and add the header to the front of the list. 2369 */ 2370 AssertStmt(cbLeft >= sizeof(s_szPostfix), rc = VERR_INTERNAL_ERROR_3); 2371 if (RT_SUCCESS(rc)) 2372 { 2373 memcpy(pszLeft, s_szPostfix, sizeof(s_szPostfix)); 2374 2375 pHdr->Core.next = pThis->pHeaders; 2376 if (!pThis->pHeaders) 2377 pThis->ppHeadersTail = &pHdr->Core.next; 2378 pThis->pHeaders = &pHdr->Core; 2379 2380 int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pThis->pHeaders); 2381 if (CURL_SUCCESS(rcCurl)) 2382 return VINF_SUCCESS; 2383 rc = VERR_HTTP_CURL_ERROR; 2384 } 2385 } 2386 } 2387 RTCrPkixSignatureRelease(hSigner); 2119 2388 } 2120 2121 /* next field. */ 2122 pCur = pCur->next; 2123 } while (pCur); 2124 } 2125 return NULL; 2126 } 2127 2389 } 2390 RTCrDigestRelease(hDigest); 2391 } 2392 RTMemFree(pHdr); 2393 return rc; 2394 } 2128 2395 2129 2396
Note:
See TracChangeset
for help on using the changeset viewer.