source: azure_iot_hub/trunk/azure_iohub/c-utility/adapters/httpapi_curl.c@ 388

Last change on this file since 388 was 388, checked in by coas-nagasima, 5 years ago

Azure IoT Hub Device C SDK を使ったサンプルの追加

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 41.2 KB
Line 
1// Copyright (c) Microsoft. All rights reserved.
2// Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <string.h>
7#include <stddef.h>
8#include <ctype.h>
9
10#include "azure_c_shared_utility/strings.h"
11#include "azure_c_shared_utility/httpapi.h"
12#include "azure_c_shared_utility/httpheaders.h"
13#include "azure_c_shared_utility/crt_abstractions.h"
14#include "curl/curl.h"
15#include "azure_c_shared_utility/xlogging.h"
16#ifdef USE_OPENSSL
17#include "azure_c_shared_utility/x509_openssl.h"
18#elif USE_WOLFSSL
19#define WOLFSSL_OPTIONS_IGNORE_SYS
20#include "wolfssl/options.h"
21#include "wolfssl/ssl.h"
22#include "wolfssl/error-ssl.h"
23#endif
24#include "azure_c_shared_utility/shared_util_options.h"
25
26#define TEMP_BUFFER_SIZE 1024
27
28MU_DEFINE_ENUM_STRINGS(HTTPAPI_RESULT, HTTPAPI_RESULT_VALUES);
29
30typedef struct HTTP_HANDLE_DATA_TAG
31{
32 CURL* curl;
33 char* hostURL;
34 long timeout;
35 long lowSpeedLimit;
36 long lowSpeedTime;
37 long forbidReuse;
38 long freshConnect;
39 long verbose;
40 const char* x509privatekey;
41 const char* x509certificate;
42 const char* certificates; /*a list of CA certificates*/
43} HTTP_HANDLE_DATA;
44
45typedef struct HTTP_RESPONSE_CONTENT_BUFFER_TAG
46{
47 unsigned char* buffer;
48 size_t bufferSize;
49 unsigned char error;
50} HTTP_RESPONSE_CONTENT_BUFFER;
51
52static size_t nUsersOfHTTPAPI = 0; /*used for reference counting (a weak one)*/
53
54HTTPAPI_RESULT HTTPAPI_Init(void)
55{
56 HTTPAPI_RESULT result;
57 if (nUsersOfHTTPAPI == 0)
58 {
59 if (curl_global_init(CURL_GLOBAL_NOTHING) != 0)
60 {
61 result = HTTPAPI_INIT_FAILED;
62 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
63 }
64 else
65 {
66 nUsersOfHTTPAPI++;
67 result = HTTPAPI_OK;
68 }
69 }
70 else
71 {
72 nUsersOfHTTPAPI++;
73 result = HTTPAPI_OK;
74 }
75
76 return result;
77}
78
79void HTTPAPI_Deinit(void)
80{
81 if (nUsersOfHTTPAPI > 0)
82 {
83 nUsersOfHTTPAPI--;
84 if (nUsersOfHTTPAPI == 0)
85 {
86 curl_global_cleanup();
87 }
88 }
89}
90
91HTTP_HANDLE HTTPAPI_CreateConnection(const char* hostName)
92{
93 HTTP_HANDLE_DATA* httpHandleData;
94
95 if (hostName == NULL)
96 {
97 LogError("invalid arg const char* hostName = %p", hostName);
98 httpHandleData = NULL;
99 }
100 else
101 {
102 httpHandleData = (HTTP_HANDLE_DATA*)malloc(sizeof(HTTP_HANDLE_DATA));
103 if (httpHandleData != NULL)
104 {
105 size_t hostURL_size = strlen("https://") + strlen(hostName) + 1;
106 httpHandleData->hostURL = malloc(hostURL_size);
107 if (httpHandleData->hostURL == NULL)
108 {
109 LogError("unable to malloc");
110 free(httpHandleData);
111 httpHandleData = NULL;
112 }
113 else
114 {
115 if ((strcpy_s(httpHandleData->hostURL, hostURL_size, "https://") == 0) &&
116 (strcat_s(httpHandleData->hostURL, hostURL_size, hostName) == 0))
117 {
118 httpHandleData->curl = curl_easy_init();
119 if (httpHandleData->curl == NULL)
120 {
121 free(httpHandleData->hostURL);
122 free(httpHandleData);
123 httpHandleData = NULL;
124 }
125 else
126 {
127 httpHandleData->timeout = 242 * 1000; /*242 seconds seems like a nice enough time. Reasone for 242:
128 1. http://curl.haxx.se/libcurl/c/CURLOPT_TIMEOUT.html says Normally, name lookups can take a considerable time and limiting operations to less than a few minutes risk aborting perfectly normal operations.
129 2. 256KB of data... at 9600 bps transfers in about 218 seconds. Add to that a buffer of 10%... round it up to 242 :)*/
130 httpHandleData->lowSpeedTime = 0;
131 httpHandleData->lowSpeedLimit = 0;
132 httpHandleData->forbidReuse = 0;
133 httpHandleData->freshConnect = 0;
134 httpHandleData->verbose = 0;
135 httpHandleData->x509certificate = NULL;
136 httpHandleData->x509privatekey = NULL;
137 httpHandleData->certificates = NULL;
138 }
139 }
140 else
141 {
142 free(httpHandleData->hostURL);
143 free(httpHandleData);
144 httpHandleData = NULL;
145 }
146 }
147 }
148 }
149
150 return (HTTP_HANDLE)httpHandleData;
151}
152
153void HTTPAPI_CloseConnection(HTTP_HANDLE handle)
154{
155 HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle;
156 if (httpHandleData != NULL)
157 {
158 free(httpHandleData->hostURL);
159 curl_easy_cleanup(httpHandleData->curl);
160 free(httpHandleData);
161 }
162}
163
164static size_t HeadersWriteFunction(void *ptr, size_t size, size_t nmemb, void *userdata)
165{
166 HTTP_HEADERS_HANDLE responseHeadersHandle = (HTTP_HEADERS_HANDLE)userdata;
167 char* headerLine = (char*)ptr;
168
169 if (headerLine != NULL)
170 {
171 char* token = strtok(headerLine, "\r\n");
172 while ((token != NULL) &&
173 (token[0] != '\0'))
174 {
175 char* whereIsColon = strchr(token, ':');
176 if(whereIsColon!=NULL)
177 {
178 *whereIsColon='\0';
179 HTTPHeaders_AddHeaderNameValuePair(responseHeadersHandle, token, whereIsColon+1);
180 *whereIsColon=':';
181 }
182 else
183 {
184 /*not a header, maybe a status-line*/
185 }
186 token = strtok(NULL, "\r\n");
187 }
188 }
189
190 return size * nmemb;
191}
192
193static size_t ContentWriteFunction(void *ptr, size_t size, size_t nmemb, void *userdata)
194{
195 HTTP_RESPONSE_CONTENT_BUFFER* responseContentBuffer = (HTTP_RESPONSE_CONTENT_BUFFER*)userdata;
196 if ((userdata != NULL) &&
197 (ptr != NULL) &&
198 (size * nmemb > 0))
199 {
200 void* newBuffer = realloc(responseContentBuffer->buffer, responseContentBuffer->bufferSize + (size * nmemb));
201 if (newBuffer != NULL)
202 {
203 responseContentBuffer->buffer = newBuffer;
204 memcpy(responseContentBuffer->buffer + responseContentBuffer->bufferSize, ptr, size * nmemb);
205 responseContentBuffer->bufferSize += size * nmemb;
206 }
207 else
208 {
209 LogError("Could not allocate buffer of size %lu", (unsigned long)(responseContentBuffer->bufferSize + (size * nmemb)));
210 responseContentBuffer->error = 1;
211 if (responseContentBuffer->buffer != NULL)
212 {
213 free(responseContentBuffer->buffer);
214 }
215 }
216 }
217
218 return size * nmemb;
219}
220
221static CURLcode ssl_ctx_callback(CURL *curl, void *ssl_ctx, void *userptr)
222{
223 CURLcode result;
224
225 if (
226 (curl == NULL) ||
227 (ssl_ctx == NULL) ||
228 (userptr == NULL)
229 )
230 {
231 LogError("unexpected parameter CURL *curl=%p, void *ssl_ctx=%p, void *userptr=%p", curl, ssl_ctx, userptr);
232 result = CURLE_SSL_CERTPROBLEM;
233 }
234 else
235 {
236 HTTP_HANDLE_DATA *httpHandleData = (HTTP_HANDLE_DATA *)userptr;
237#ifdef USE_OPENSSL
238 /*trying to set the x509 per device certificate*/
239 if (
240 (httpHandleData->x509certificate != NULL) && (httpHandleData->x509privatekey != NULL) &&
241 (x509_openssl_add_credentials(ssl_ctx, httpHandleData->x509certificate, httpHandleData->x509privatekey) != 0)
242 )
243 {
244 LogError("unable to x509_openssl_add_credentials");
245 result = CURLE_SSL_CERTPROBLEM;
246 }
247 /*trying to set CA certificates*/
248 else if (
249 (httpHandleData->certificates != NULL) &&
250 (x509_openssl_add_certificates(ssl_ctx, httpHandleData->certificates) != 0)
251 )
252 {
253 LogError("failure in x509_openssl_add_certificates");
254 result = CURLE_SSL_CERTPROBLEM;
255 }
256#elif USE_WOLFSSL
257 if (
258 (httpHandleData->x509certificate != NULL) &&
259 (httpHandleData->x509privatekey != NULL) &&
260 (
261 ((wolfSSL_use_certificate_chain_buffer(ssl_ctx, (unsigned char*)httpHandleData->x509certificate, strlen(httpHandleData->x509certificate)) != SSL_SUCCESS)) ||
262 ((wolfSSL_use_PrivateKey_buffer(ssl_ctx, (unsigned char*)httpHandleData->x509privatekey, strlen(httpHandleData->x509privatekey), SSL_FILETYPE_PEM) != SSL_SUCCESS))
263 )
264 )
265 {
266 LogError("unable to add x509 certs to wolfssl");
267 result = CURLE_SSL_CERTPROBLEM;
268 }
269 else if (
270 (httpHandleData->certificates != NULL) &&
271 (wolfSSL_CTX_load_verify_buffer(ssl_ctx, (const unsigned char*)httpHandleData->certificates, strlen(httpHandleData->certificates), SSL_FILETYPE_PEM) != SSL_SUCCESS)
272 )
273 {
274 LogError("failure in adding trusted certificate to client");
275 result = CURLE_SSL_CERTPROBLEM;
276 }
277#else
278 if (httpHandleData->x509certificate != NULL || httpHandleData->x509privatekey != NULL)
279 {
280 LogError("Failure no platform is enabled to handle certificates");
281 result = CURLE_SSL_CERTPROBLEM;
282 }
283#endif
284 else
285 {
286 result = CURLE_OK;
287 }
288 }
289
290 return result;
291}
292
293HTTPAPI_RESULT HTTPAPI_ExecuteRequest(HTTP_HANDLE handle, HTTPAPI_REQUEST_TYPE requestType, const char* relativePath,
294 HTTP_HEADERS_HANDLE httpHeadersHandle, const unsigned char* content,
295 size_t contentLength, unsigned int* statusCode,
296 HTTP_HEADERS_HANDLE responseHeadersHandle, BUFFER_HANDLE responseContent)
297{
298 HTTPAPI_RESULT result;
299 HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle;
300 size_t headersCount;
301 HTTP_RESPONSE_CONTENT_BUFFER responseContentBuffer;
302
303 if ((httpHandleData == NULL) ||
304 (relativePath == NULL) ||
305 (httpHeadersHandle == NULL) ||
306 ((content == NULL) && (contentLength > 0))
307 )
308 {
309 result = HTTPAPI_INVALID_ARG;
310 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
311 }
312 else if (HTTPHeaders_GetHeaderCount(httpHeadersHandle, &headersCount) != HTTP_HEADERS_OK)
313 {
314 result = HTTPAPI_INVALID_ARG;
315 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
316 }
317 else
318 {
319 char* tempHostURL;
320 size_t tempHostURL_size = strlen(httpHandleData->hostURL) + strlen(relativePath) + 1;
321 tempHostURL = malloc(tempHostURL_size);
322 if (tempHostURL == NULL)
323 {
324 result = HTTPAPI_ERROR;
325 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
326 }
327 else
328 {
329 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_VERBOSE, httpHandleData->verbose) != CURLE_OK)
330 {
331 result = HTTPAPI_SET_OPTION_FAILED;
332 LogError("failed to set CURLOPT_VERBOSE (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
333 }
334 else if ((strcpy_s(tempHostURL, tempHostURL_size, httpHandleData->hostURL) != 0) ||
335 (strcat_s(tempHostURL, tempHostURL_size, relativePath) != 0))
336 {
337 result = HTTPAPI_STRING_PROCESSING_ERROR;
338 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
339 }
340 /* set the URL */
341 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_URL, tempHostURL) != CURLE_OK)
342 {
343 result = HTTPAPI_SET_OPTION_FAILED;
344 LogError("failed to set CURLOPT_URL (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
345 }
346 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_TIMEOUT_MS, httpHandleData->timeout) != CURLE_OK)
347 {
348 result = HTTPAPI_SET_OPTION_FAILED;
349 LogError("failed to set CURLOPT_TIMEOUT_MS (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
350 }
351 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_LOW_SPEED_LIMIT, httpHandleData->lowSpeedLimit) != CURLE_OK)
352 {
353 result = HTTPAPI_SET_OPTION_FAILED;
354 LogError("failed to set CURLOPT_LOW_SPEED_LIMIT (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
355 }
356 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_LOW_SPEED_TIME, httpHandleData->lowSpeedTime) != CURLE_OK)
357 {
358 result = HTTPAPI_SET_OPTION_FAILED;
359 LogError("failed to set CURLOPT_LOW_SPEED_TIME (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
360 }
361 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_FRESH_CONNECT, httpHandleData->freshConnect) != CURLE_OK)
362 {
363 result = HTTPAPI_SET_OPTION_FAILED;
364 LogError("failed to set CURLOPT_FRESH_CONNECT (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
365 }
366 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_FORBID_REUSE, httpHandleData->forbidReuse) != CURLE_OK)
367 {
368 result = HTTPAPI_SET_OPTION_FAILED;
369 LogError("failed to set CURLOPT_FORBID_REUSE (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
370 }
371 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1) != CURLE_OK)
372 {
373 result = HTTPAPI_SET_OPTION_FAILED;
374 LogError("failed to set CURLOPT_HTTP_VERSION (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
375 }
376 else
377 {
378 result = HTTPAPI_OK;
379
380 switch (requestType)
381 {
382 default:
383 result = HTTPAPI_INVALID_ARG;
384 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
385 break;
386
387 case HTTPAPI_REQUEST_GET:
388 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTPGET, 1L) != CURLE_OK)
389 {
390 result = HTTPAPI_SET_OPTION_FAILED;
391 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
392 }
393 else
394 {
395 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, NULL) != CURLE_OK)
396 {
397 result = HTTPAPI_SET_OPTION_FAILED;
398 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
399 }
400 }
401
402 break;
403
404 case HTTPAPI_REQUEST_HEAD:
405 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTPGET, 1L) != CURLE_OK)
406 {
407 result = HTTPAPI_SET_OPTION_FAILED;
408 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
409 }
410 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_NOBODY, 1L) != CURLE_OK)
411 {
412 result = HTTPAPI_SET_OPTION_FAILED;
413 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
414 }
415 else if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, NULL) != CURLE_OK)
416 {
417 result = HTTPAPI_SET_OPTION_FAILED;
418 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
419 }
420
421 break;
422
423 case HTTPAPI_REQUEST_POST:
424 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK)
425 {
426 result = HTTPAPI_SET_OPTION_FAILED;
427 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
428 }
429 else
430 {
431 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, NULL) != CURLE_OK)
432 {
433 result = HTTPAPI_SET_OPTION_FAILED;
434 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
435 }
436 }
437
438 break;
439
440 case HTTPAPI_REQUEST_PUT:
441 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L))
442 {
443 result = HTTPAPI_SET_OPTION_FAILED;
444 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
445 }
446 else
447 {
448 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "PUT") != CURLE_OK)
449 {
450 result = HTTPAPI_SET_OPTION_FAILED;
451 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
452 }
453 }
454 break;
455
456 case HTTPAPI_REQUEST_DELETE:
457 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK)
458 {
459 result = HTTPAPI_SET_OPTION_FAILED;
460 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
461 }
462 else
463 {
464 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "DELETE") != CURLE_OK)
465 {
466 result = HTTPAPI_SET_OPTION_FAILED;
467 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
468 }
469 }
470 break;
471
472 case HTTPAPI_REQUEST_PATCH:
473 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_POST, 1L) != CURLE_OK)
474 {
475 result = HTTPAPI_SET_OPTION_FAILED;
476 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
477 }
478 else
479 {
480 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_CUSTOMREQUEST, "PATCH") != CURLE_OK)
481 {
482 result = HTTPAPI_SET_OPTION_FAILED;
483 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
484 }
485 }
486
487 break;
488 }
489
490 if (result == HTTPAPI_OK)
491 {
492 /* add headers */
493 struct curl_slist* headers = NULL;
494 size_t i;
495
496 for (i = 0; i < headersCount; i++)
497 {
498 char *tempBuffer;
499 if (HTTPHeaders_GetHeader(httpHeadersHandle, i, &tempBuffer) != HTTP_HEADERS_OK)
500 {
501 /* error */
502 result = HTTPAPI_HTTP_HEADERS_FAILED;
503 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
504 break;
505 }
506 else
507 {
508 struct curl_slist* newHeaders = curl_slist_append(headers, tempBuffer);
509 if (newHeaders == NULL)
510 {
511 result = HTTPAPI_ALLOC_FAILED;
512 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
513 free(tempBuffer);
514 break;
515 }
516 else
517 {
518 free(tempBuffer);
519 headers = newHeaders;
520 }
521 }
522 }
523
524 if (result == HTTPAPI_OK)
525 {
526 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_HTTPHEADER, headers) != CURLE_OK)
527 {
528 result = HTTPAPI_SET_OPTION_FAILED;
529 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
530 }
531 else
532 {
533 /* add content */
534 if ((content != NULL) &&
535 (contentLength > 0))
536 {
537 if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDS, (void*)content) != CURLE_OK) ||
538 (curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDSIZE, contentLength) != CURLE_OK))
539 {
540 result = HTTPAPI_SET_OPTION_FAILED;
541 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
542 }
543 }
544 else
545 {
546 if (requestType != HTTPAPI_REQUEST_GET)
547 {
548 if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDS, (void*)NULL) != CURLE_OK) ||
549 (curl_easy_setopt(httpHandleData->curl, CURLOPT_POSTFIELDSIZE, 0) != CURLE_OK))
550 {
551 result = HTTPAPI_SET_OPTION_FAILED;
552 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
553 }
554 }
555 else
556 {
557 /*GET request cannot POST, so "do nothing*/
558 }
559 }
560
561 if (result == HTTPAPI_OK)
562 {
563 if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEHEADER, NULL) != CURLE_OK) ||
564 (curl_easy_setopt(httpHandleData->curl, CURLOPT_HEADERFUNCTION, NULL) != CURLE_OK) ||
565 (curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEFUNCTION, ContentWriteFunction) != CURLE_OK))
566 {
567 result = HTTPAPI_SET_OPTION_FAILED;
568 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
569 }
570 else
571 {
572 if (responseHeadersHandle != NULL)
573 {
574 /* setup the code to get the response headers */
575 if ((curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEHEADER, responseHeadersHandle) != CURLE_OK) ||
576 (curl_easy_setopt(httpHandleData->curl, CURLOPT_HEADERFUNCTION, HeadersWriteFunction) != CURLE_OK))
577 {
578 result = HTTPAPI_SET_OPTION_FAILED;
579 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
580 }
581 }
582
583 if (result == HTTPAPI_OK)
584 {
585 responseContentBuffer.buffer = NULL;
586 responseContentBuffer.bufferSize = 0;
587 responseContentBuffer.error = 0;
588
589 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_WRITEDATA, &responseContentBuffer) != CURLE_OK)
590 {
591 result = HTTPAPI_SET_OPTION_FAILED;
592 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
593 }
594
595 if (result == HTTPAPI_OK)
596 {
597 /* Execute request */
598 CURLcode curlRes = curl_easy_perform(httpHandleData->curl);
599 if (curlRes != CURLE_OK)
600 {
601 LogError("curl_easy_perform() failed: %s\n", curl_easy_strerror(curlRes));
602 result = HTTPAPI_OPEN_REQUEST_FAILED;
603 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
604 }
605 else
606 {
607 long httpCode;
608
609 /* get the status code */
610 if (curl_easy_getinfo(httpHandleData->curl, CURLINFO_RESPONSE_CODE, &httpCode) != CURLE_OK)
611 {
612 result = HTTPAPI_QUERY_HEADERS_FAILED;
613 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
614 }
615 else if (responseContentBuffer.error)
616 {
617 result = HTTPAPI_READ_DATA_FAILED;
618 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
619 }
620 else
621 {
622 if (statusCode != NULL)
623 {
624 *statusCode = (unsigned int)httpCode;
625 }
626
627 /* fill response content length */
628 if (responseContent != NULL)
629 {
630 if ((responseContentBuffer.bufferSize > 0) && (BUFFER_build(responseContent, responseContentBuffer.buffer, responseContentBuffer.bufferSize) != 0))
631 {
632 result = HTTPAPI_INSUFFICIENT_RESPONSE_BUFFER;
633 LogError("(result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
634 }
635 else
636 {
637 /*all nice*/
638 }
639 }
640
641 if (httpCode >= 300)
642 {
643 LogError("Failure in HTTP communication: server reply code is %ld", httpCode);
644 LogInfo("HTTP Response:%*.*s", (int)responseContentBuffer.bufferSize,
645 (int)responseContentBuffer.bufferSize, responseContentBuffer.buffer);
646 }
647 else
648 {
649 result = HTTPAPI_OK;
650 }
651 }
652 }
653 }
654
655 if (responseContentBuffer.buffer != NULL)
656 {
657 free(responseContentBuffer.buffer);
658 }
659 }
660 }
661 }
662 }
663 }
664 curl_slist_free_all(headers);
665 }
666 }
667 free(tempHostURL);
668 }
669 }
670
671 return result;
672}
673
674HTTPAPI_RESULT HTTPAPI_SetOption(HTTP_HANDLE handle, const char* optionName, const void* value)
675{
676 HTTPAPI_RESULT result;
677 if (
678 (handle == NULL) ||
679 (optionName == NULL) ||
680 (value == NULL)
681 )
682 {
683 result = HTTPAPI_INVALID_ARG;
684 LogError("invalid parameter (NULL) passed to HTTPAPI_SetOption");
685 }
686 else
687 {
688 HTTP_HANDLE_DATA* httpHandleData = (HTTP_HANDLE_DATA*)handle;
689 if (strcmp(OPTION_HTTP_TIMEOUT, optionName) == 0)
690 {
691 long timeout = (long)(*(unsigned int*)value);
692 httpHandleData->timeout = timeout;
693 result = HTTPAPI_OK;
694 }
695 else if (strcmp(OPTION_CURL_LOW_SPEED_LIMIT, optionName) == 0)
696 {
697 httpHandleData->lowSpeedLimit = *(const long*)value;
698 result = HTTPAPI_OK;
699 }
700 else if (strcmp(OPTION_CURL_LOW_SPEED_TIME, optionName) == 0)
701 {
702 httpHandleData->lowSpeedTime = *(const long*)value;
703 result = HTTPAPI_OK;
704 }
705 else if (strcmp(OPTION_CURL_FRESH_CONNECT, optionName) == 0)
706 {
707 httpHandleData->freshConnect = *(const long*)value;
708 result = HTTPAPI_OK;
709 }
710 else if (strcmp(OPTION_CURL_FORBID_REUSE, optionName) == 0)
711 {
712 httpHandleData->forbidReuse = *(const long*)value;
713 result = HTTPAPI_OK;
714 }
715 else if (strcmp(OPTION_CURL_VERBOSE, optionName) == 0)
716 {
717 httpHandleData->verbose = *(const long*)value;
718 result = HTTPAPI_OK;
719 }
720 else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0 || strcmp(OPTION_X509_ECC_KEY, optionName) == 0)
721 {
722 httpHandleData->x509privatekey = value;
723 if (httpHandleData->x509certificate != NULL)
724 {
725 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback) != CURLE_OK)
726 {
727 LogError("unable to curl_easy_setopt");
728 result = HTTPAPI_ERROR;
729 }
730 else
731 {
732 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_DATA, httpHandleData) != CURLE_OK)
733 {
734 LogError("unable to curl_easy_setopt");
735 result = HTTPAPI_ERROR;
736 }
737 else
738 {
739 result = HTTPAPI_OK;
740 }
741 }
742 }
743 else
744 {
745 /*if privatekey comes 1st and certificate is not set yet, then return OK and wait for the certificate to be set*/
746 result = HTTPAPI_OK;
747 }
748 }
749 else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0 || strcmp(OPTION_X509_ECC_CERT, optionName) == 0)
750 {
751 httpHandleData->x509certificate = value;
752 if (httpHandleData->x509privatekey != NULL)
753 {
754 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback) != CURLE_OK)
755 {
756 LogError("unable to curl_easy_setopt");
757 result = HTTPAPI_ERROR;
758 }
759 else
760 {
761 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_DATA, httpHandleData) != CURLE_OK)
762 {
763 LogError("unable to curl_easy_setopt");
764 result = HTTPAPI_ERROR;
765 }
766 else
767 {
768 result = HTTPAPI_OK;
769 }
770 }
771 }
772 else
773 {
774 /*if certificate comes 1st and private key is not set yet, then return OK and wait for the private key to be set*/
775 result = HTTPAPI_OK;
776 }
777 }
778 else if (strcmp(OPTION_HTTP_PROXY, optionName) == 0)
779 {
780 char proxy[MAX_HOSTNAME_LEN];
781 char* proxy_auth;
782
783 HTTP_PROXY_OPTIONS* proxy_data = (HTTP_PROXY_OPTIONS*)value;
784
785 if (sprintf_s(proxy, MAX_HOSTNAME_LEN, "%s:%d", proxy_data->host_address, proxy_data->port) <= 0)
786 {
787 LogError("failure constructing proxy address");
788 result = HTTPAPI_ERROR;
789 }
790 else
791 {
792 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_PROXY, proxy) != CURLE_OK)
793 {
794 LogError("failure setting curl proxy address");
795 result = HTTPAPI_ERROR;
796 }
797 else
798 {
799 if (proxy_data->username != NULL && proxy_data->password != NULL)
800 {
801 size_t authLen = strlen(proxy_data->username)+strlen(proxy_data->password)+1;
802 proxy_auth = malloc(authLen+1);
803 if (proxy_auth == NULL)
804 {
805 LogError("failure allocating proxy authentication");
806 result = HTTPAPI_ERROR;
807 }
808 else
809 {
810 // From curl website 'Pass a char * as parameter, which should be [user name]:[password]'
811 if (sprintf_s(proxy_auth, MAX_HOSTNAME_LEN, "%s:%s", proxy_data->username, proxy_data->password) <= 0)
812 {
813 LogError("failure constructing proxy authentication");
814 result = HTTPAPI_ERROR;
815 }
816 else
817 {
818 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_PROXYUSERPWD, proxy_auth) != CURLE_OK)
819 {
820 LogError("failure setting curl proxy authentication");
821 result = HTTPAPI_ERROR;
822 }
823 else
824 {
825 result = HTTPAPI_OK;
826 }
827 }
828 free(proxy_auth);
829 }
830 }
831 else
832 {
833 result = HTTPAPI_OK;
834 }
835 }
836 }
837 }
838 else if (strcmp("TrustedCerts", optionName) == 0)
839 {
840 /*TrustedCerts needs to trigger the CURLOPT_SSL_CTX_FUNCTION in curl so we can pass the CAs*/
841 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_FUNCTION, ssl_ctx_callback) != CURLE_OK)
842 {
843 LogError("failure in curl_easy_setopt - CURLOPT_SSL_CTX_FUNCTION");
844 result = HTTPAPI_ERROR;
845 }
846 else
847 {
848 if (curl_easy_setopt(httpHandleData->curl, CURLOPT_SSL_CTX_DATA, httpHandleData) != CURLE_OK)
849 {
850 LogError("failure in curl_easy_setopt - CURLOPT_SSL_CTX_DATA");
851 result = HTTPAPI_ERROR;
852 }
853 else
854 {
855 httpHandleData->certificates = (const char*)value;
856 result = HTTPAPI_OK;
857 }
858 }
859 }
860 else
861 {
862 result = HTTPAPI_INVALID_ARG;
863 LogError("unknown option %s", optionName);
864 }
865 }
866
867 return result;
868}
869
870HTTPAPI_RESULT HTTPAPI_CloneOption(const char* optionName, const void* value, const void** savedValue)
871{
872 HTTPAPI_RESULT result;
873 if (
874 (optionName == NULL) ||
875 (value == NULL) ||
876 (savedValue == NULL)
877 )
878 {
879 result = HTTPAPI_INVALID_ARG;
880 LogError("invalid argument(NULL) passed to HTTPAPI_CloneOption");
881 }
882 else
883 {
884 if (strcmp(OPTION_HTTP_TIMEOUT, optionName) == 0)
885 {
886 /*by convention value is pointing to an unsigned int */
887 unsigned int* temp = malloc(sizeof(unsigned int)); /*shall be freed by HTTPAPIEX*/
888 if (temp == NULL)
889 {
890 result = HTTPAPI_ERROR;
891 LogError("malloc failed (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
892 }
893 else
894 {
895 *temp = *(const unsigned int*)value;
896 *savedValue = temp;
897 result = HTTPAPI_OK;
898 }
899 }
900 else if (strcmp(SU_OPTION_X509_CERT, optionName) == 0 || strcmp(OPTION_X509_ECC_CERT, optionName) == 0)
901 {
902 /*this is getting the x509 certificate. In this case, value is a pointer to a const char* that contains the certificate as a null terminated string*/
903 if (mallocAndStrcpy_s((char**)savedValue, value) != 0)
904 {
905 LogError("unable to clone the x509 certificate content");
906 result = HTTPAPI_ERROR;
907 }
908 else
909 {
910 /*return OK when the certificate has been clones successfully*/
911 result = HTTPAPI_OK;
912 }
913 }
914 else if (strcmp(SU_OPTION_X509_PRIVATE_KEY, optionName) == 0 || strcmp(OPTION_X509_ECC_KEY, optionName) == 0)
915 {
916 /*this is getting the x509 private key. In this case, value is a pointer to a const char* that contains the private key as a null terminated string*/
917 if (mallocAndStrcpy_s((char**)savedValue, value) != 0)
918 {
919 LogError("unable to clone the x509 private key content");
920 result = HTTPAPI_ERROR;
921 }
922 else
923 {
924 /*return OK when the private key has been clones successfully*/
925 result = HTTPAPI_OK;
926 }
927 }
928 else if (strcmp("TrustedCerts", optionName) == 0)
929 {
930 if (mallocAndStrcpy_s((char**)savedValue, value) != 0)
931 {
932 LogError("unable to clone TrustedCerts");
933 result = HTTPAPI_ERROR;
934 }
935 else
936 {
937 /*return OK when the certificates have been clones successfully*/
938 result = HTTPAPI_OK;
939 }
940 }
941 else if (strcmp(OPTION_HTTP_PROXY, optionName) == 0)
942 {
943 HTTP_PROXY_OPTIONS* proxy_data = (HTTP_PROXY_OPTIONS*)value;
944
945 HTTP_PROXY_OPTIONS* new_proxy_info = malloc(sizeof(HTTP_PROXY_OPTIONS));
946 if (new_proxy_info == NULL)
947 {
948 LogError("unable to allocate proxy option information");
949 result = HTTPAPI_ERROR;
950 }
951 else
952 {
953 new_proxy_info->host_address = proxy_data->host_address;
954 new_proxy_info->port = proxy_data->port;
955 new_proxy_info->password = proxy_data->password;
956 new_proxy_info->username = proxy_data->username;
957 *savedValue = new_proxy_info;
958 result = HTTPAPI_OK;
959 }
960 }
961 /*all "long" options are cloned in the same way*/
962 else if (
963 (strcmp(OPTION_CURL_LOW_SPEED_LIMIT, optionName) == 0) ||
964 (strcmp(OPTION_CURL_LOW_SPEED_TIME, optionName) == 0) ||
965 (strcmp(OPTION_CURL_FRESH_CONNECT, optionName) == 0) ||
966 (strcmp(OPTION_CURL_FORBID_REUSE, optionName) == 0) ||
967 (strcmp(OPTION_CURL_VERBOSE, optionName) == 0)
968 )
969 {
970 /*by convention value is pointing to an long */
971 long* temp = malloc(sizeof(long)); /*shall be freed by HTTPAPIEX*/
972 if (temp == NULL)
973 {
974 result = HTTPAPI_ERROR;
975 LogError("malloc failed (result = %s)", MU_ENUM_TO_STRING(HTTPAPI_RESULT, result));
976 }
977 else
978 {
979 *temp = *(const long*)value;
980 *savedValue = temp;
981 result = HTTPAPI_OK;
982 }
983 }
984 else
985 {
986 result = HTTPAPI_INVALID_ARG;
987 LogError("unknown option %s", optionName);
988 }
989 }
990 return result;
991}
Note: See TracBrowser for help on using the repository browser.