31 #include <curl/curl.h> 33 #include <openssl/ssl.h> 42 #define HTTP_IDLE_TIMEOUT 200 43 #define MAX_USER_AGENT 256 45 #define CHK_EASY(call) \ 49 if (code != CURLE_OK) \ 51 TRACE(TERROR, ("FAIL %s",#call)) \ 58 #define DBG_ENTRY(x) DBG_PRINTF(" >> %s\n", #x); 59 #define DBG_EXIT(x) DBG_PRINTF(" << %s\n", #x); 76 struct curl_slist *headers;
87 static CURLM *multi_handle = NULL;
89 static void *ssl_mutex;
91 static char http_user_agent[MAX_USER_AGENT] =
"";
92 static U16BIT http_timeout = 30;
93 static char curl_error_buffer[CURL_ERROR_SIZE];
99 static size_t httpWriteCallback(
void *ptr,
size_t size,
100 size_t nmemb,
void *handle);
101 static size_t httpHeaderCallback(
void *ptr,
size_t size,
102 size_t nmemb,
void *handle);
103 static void* httpParseCertificate(U8BIT *
buffer, U16BIT length);
104 static CURLcode httpSslCtxFunction(CURL *curl,
void *sslctx,
void *parm);
119 multi_handle = curl_multi_init();
120 if (multi_handle != NULL)
126 err = HTTP_ERR_INTERNAL;
144 strcpy(http_user_agent, (
char *)user_agent);
167 http_timeout = timeout;
197 *handle = curl_easy_init();
201 if (client_info != NULL)
203 client_info->userdata = NULL;
204 client_info->headers = NULL;
206 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_URL, (U8BIT *)url));
207 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_PRIVATE, client_info));
209 if (http_user_agent[0] !=
'\0')
211 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_USERAGENT,
215 curl_error_buffer[0] = 0;
216 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_ERRORBUFFER,
218 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_WRITEFUNCTION,
220 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_WRITEDATA, *handle));
221 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_HEADERFUNCTION,
222 httpHeaderCallback));
223 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_WRITEHEADER, *handle));
225 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_HEADER, 0));
226 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_NOPROGRESS, 1));
227 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_HTTP_VERSION,
228 CURL_HTTP_VERSION_1_1));
230 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_SSL_CTX_FUNCTION,
231 httpSslCtxFunction));
232 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_SSL_CIPHER_LIST,
233 "aRSA:MD5:SHA:eNULL"));
234 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_CAINFO, NULL));
236 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_CONNECTTIMEOUT,
238 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_LOW_SPEED_LIMIT, 32));
239 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_LOW_SPEED_TIME,
244 case HTTP_REQUEST_GET:
245 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_HTTPGET, 1));
247 case HTTP_REQUEST_HEAD:
248 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_NOBODY, 1));
250 case HTTP_REQUEST_POST:
251 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_POST, 1));
252 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_POSTFIELDS,
""));
253 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_POSTFIELDSIZE, 0));
255 case HTTP_REQUEST_STREAM:
256 CHK_EASY(curl_easy_setopt(*handle, CURLOPT_HTTPGET, 1));
262 curl_easy_cleanup(*handle);
270 err = HTTP_ERR_BAD_PARAMETER;
290 CURLMcode multi_code;
295 err = HTTP_ERR_INTERNAL;
302 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
303 client_info =
private;
304 if (client_info->headers != NULL)
306 code = curl_easy_setopt(handle, CURLOPT_HTTPHEADER,
307 client_info->headers);
310 if (code == CURLE_OK)
313 multi_code = curl_multi_add_handle(multi_handle, handle);
314 if (multi_code == CURLM_OK)
320 TRACE(TERROR,(
"curl_multi_add_handle %d",multi_code))
325 TRACE(TERROR,(
"curl_easy_setopt d",code))
330 err = HTTP_ERR_BAD_PARAMETER;
353 err = HTTP_ERR_INTERNAL;
357 code = curl_easy_pause(handle, CURLPAUSE_CONT);
358 if (code == CURLE_OK)
366 TRACE(TERROR,(
"CURL error %d",code))
371 err = HTTP_ERR_BAD_PARAMETER;
388 CURLMcode multi_code;
393 err = HTTP_ERR_INTERNAL;
397 multi_code = curl_multi_remove_handle(multi_handle, handle);
398 if (multi_code == CURLM_OK)
405 err = HTTP_ERR_BAD_PARAMETER;
428 err = HTTP_ERR_INTERNAL;
433 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
434 client_info =
private;
435 if (client_info->headers != NULL)
437 curl_easy_setopt(handle, CURLOPT_HTTPHEADER, NULL);
438 curl_slist_free_all(client_info->headers);
439 client_info->headers = NULL;
444 curl_easy_cleanup(handle);
448 err = HTTP_ERR_BAD_PARAMETER;
472 err = HTTP_ERR_INTERNAL;
476 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
477 client_info =
private;
478 client_info->userdata = userdata;
483 err = HTTP_ERR_BAD_PARAMETER;
507 err = HTTP_ERR_INTERNAL;
509 if (handle != NULL && header != NULL)
511 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
512 client_info =
private;
513 client_info->headers = curl_slist_append(client_info->headers,
519 err = HTTP_ERR_BAD_PARAMETER;
542 err = HTTP_ERR_INTERNAL;
544 if (handle != NULL && postdata != NULL)
546 code = curl_easy_setopt(handle, CURLOPT_POSTFIELDS, postdata);
547 if (code == CURLE_OK)
549 code = curl_easy_setopt(handle, CURLOPT_POSTFIELDSIZE, -1);
550 if (code == CURLE_OK)
558 err = HTTP_ERR_BAD_PARAMETER;
580 err = HTTP_ERR_INTERNAL;
582 if (handle != NULL && range != NULL)
584 CHK_EASY(curl_easy_setopt(handle, CURLOPT_RANGE, range));
589 err = HTTP_ERR_BAD_PARAMETER;
613 err = HTTP_ERR_INTERNAL;
615 if (handle != NULL && url != NULL)
617 code = curl_easy_getinfo(handle, CURLINFO_REDIRECT_URL, &redir_url);
618 if (code == CURLE_OK)
620 *url = (U8BIT *)redir_url;
626 err = HTTP_ERR_BAD_PARAMETER;
649 err = HTTP_ERR_INTERNAL;
651 if (cert != NULL && len > 0)
654 pcert = &http_cert_list;
655 while (*pcert != NULL)
657 pcert = &(*pcert)->next;
664 curr->x509 = httpParseCertificate(cert, len);
665 if (curr->x509 != NULL)
681 err = HTTP_ERR_BAD_PARAMETER;
701 pcert = &http_cert_list;
702 while (*pcert != NULL)
705 *pcert = (*pcert)->next;
706 X509_free(curr->x509);
726 CURLMcode multi_code;
731 struct timeval timeout;
736 err = HTTP_ERR_INTERNAL;
743 multi_code = curl_multi_fdset(multi_handle, &readfds, &writefds,
744 &exceptfds, &max_fd);
745 if (multi_code == CURLM_OK)
750 timeout.tv_usec = HTTP_IDLE_TIMEOUT * 1000;
751 select(max_fd + 1, &readfds, &writefds, &exceptfds, &timeout);
772 CURLMcode multi_code;
782 err = HTTP_ERR_INTERNAL;
786 multi_code = curl_multi_perform(multi_handle, &running_handles);
789 while (multi_code == CURLM_CALL_MULTI_PERFORM);
791 if (multi_code == CURLM_OK)
795 multi_msg = curl_multi_info_read(multi_handle, &msgs_in_queue);
796 if (multi_msg != NULL)
798 if (multi_msg->msg == CURLMSG_DONE)
800 curl_easy_getinfo(multi_msg->easy_handle,
801 CURLINFO_PRIVATE, &
private);
802 client_info =
private;
803 switch (multi_msg->data.result)
806 status = HTTP_STATUS_OK;
808 case CURLE_PARTIAL_FILE:
809 status = HTTP_STATUS_PARTIAL;
811 case CURLE_SSL_CACERT:
812 status = HTTP_STATUS_SSL_ERROR;
814 case CURLE_COULDNT_RESOLVE_PROXY:
815 case CURLE_COULDNT_RESOLVE_HOST:
816 case CURLE_COULDNT_CONNECT:
817 status = HTTP_STATUS_NETWORK_ERROR;
819 case CURLE_OPERATION_TIMEDOUT:
820 status = HTTP_STATUS_TIMEOUT;
823 status = HTTP_STATUS_OTHER_ERROR;
824 TRACE(TERROR,(
"error buffer=%s",curl_error_buffer));
826 TRACE(TICS, (
"ud=%p status=%u rslt=%u", client_info->userdata, status, multi_msg->data.result));
831 TRACE(TERROR,(
"multi_msg->msg = %d\n", multi_msg->msg));
835 while (multi_msg != NULL);
841 TRACE(TERROR,(
"curl error %s", curl_multi_strerror(multi_code)));
844 *active_count = running_handles;
860 if (multi_handle != NULL)
862 curl_multi_cleanup(multi_handle);
866 curl_global_cleanup();
883 static size_t httpHeaderCallback(
void *ptr,
size_t size,
884 size_t nmemb,
void *handle)
890 DBG_ENTRY(httpHeaderCallback);
892 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
893 curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &response_code);
895 client_info =
private;
896 TRACE(TICS, (
"itm size=%u num=%u ptr=%p", size, nmemb, ptr));
900 DBG_EXIT(httpHeaderCallback);
913 static size_t httpWriteCallback(
void *ptr,
size_t size,
914 size_t nmemb,
void *handle)
921 DBG_ENTRY(httpWriteCallback);
923 retval = size * nmemb;
925 curl_easy_getinfo(handle, CURLINFO_PRIVATE, &
private);
926 client_info =
private;
927 TRACE(TICS, (
"itm size=%u num=%u ptr=%p", size, nmemb, ptr));
932 retval = CURL_WRITEFUNC_PAUSE;
935 DBG_EXIT(httpWriteCallback);
946 static void* httpParseCertificate(U8BIT *
buffer, U16BIT length)
952 DBG_ENTRY(httpParseCertificate);
956 bio = BIO_new_mem_buf(
buffer, length);
959 x509 = d2i_X509_bio(bio, NULL);
967 DBG_EXIT(httpParseCertificate);
979 static CURLcode httpSslCtxFunction(CURL *curl,
void *sslctx,
void *parm)
981 SSL_CTX *ssl_ctx = sslctx;
982 X509_STORE *x509_store;
984 X509_VERIFY_PARAM *param;
990 DBG_ENTRY(sslCtxFunction);
993 x509_store = SSL_CTX_get_cert_store(ssl_ctx);
994 if (x509_store != NULL)
999 curr = http_cert_list;
1000 while (curr != NULL)
1002 if (X509_STORE_add_cert(x509_store, curr->x509) == 0)
1004 TRACE(TERROR,(
"failed to ADD cert"));
1005 rc = CURLE_SSL_CERTPROBLEM;
1014 param = X509_VERIFY_PARAM_new();
1018 tmstruct.tm_sec = date_time.second;
1019 tmstruct.tm_min = date_time.minute;
1020 tmstruct.tm_hour = date_time.hour;
1021 tmstruct.tm_mday = date_time.day;
1022 tmstruct.tm_mon = date_time.month - 1;
1023 tmstruct.tm_year = date_time.year - 1900;
1024 tmstruct.tm_isdst = 0;
1025 current_time = mktime(&tmstruct);
1026 X509_VERIFY_PARAM_set_time(param, current_time);
1027 X509_STORE_set1_param(x509_store, param);
1028 X509_VERIFY_PARAM_free(param);
1036 TRACE(TERROR,(
"failed to GET cert"));
1037 rc = CURLE_SSL_CERTPROBLEM;
1039 TRACE(TICS, (
"rc=%d", rc));
1040 DBG_EXIT(sslCtxFunction);
E_HttpErr HP_CreateRequest(U8BIT *url, E_HttpRequestType type, void **handle)
Create an HTTP request. The URL is provided, and is guaranteed to be either "http://..." or "https://..." The request type is also provided. Streaming request is the same as a GET request, except that a "Range:" header is also allowed for it.
E_MhegErr DVB_MhegGetLocalTime(S_DateTime *pDateAndTime)
Provide the current local time and date, normally from the system real time clock, with any local time conversions (if necessary). The returned time should take into account local timezone and daylight saving settings.
E_HttpErr HP_Process(U16BIT *active_count)
Process HTTP requests. This may cause request callbacks to be called.
void STB_OSTaskDelay(U16BIT timeout)
Delay Task for Specifed Time Period.
E_HttpErr HP_StartRequest(void *handle)
Start an HTTP request.
void STB_MemFree(void *ptr)
Releases previously allocated memory.
void STB_OSDeleteMutex(void *mutex)
Delete a mutex.
E_HttpErr HP_SetRange(void *handle, U8BIT *range)
Set "Range:" header for an HTTP request.
E_HttpErr HP_StopRequest(void *handle)
Stop an HTTP request.
System Memory allocation interface.
E_HttpErr HP_ClearTlsCertificates(void)
Clear TLS certificates.
E_HttpErr HP_GetRedirectUrl(void *handle, U8BIT **url)
Get redirection URL for HTTP request.
E_HttpErr HP_ResumeRequest(void *handle)
Resume an HTTP request.
void STB_OSMutexUnlock(void *mutex)
Unlock a mutex (a.k.a. 'leave', 'signal' or 'release')
void * STB_MemAlloc(U32BIT memSize)
Allocates the specified number of bytes.
void * STB_OSCreateMutex(void)
Create a mutex.
E_HttpErr HP_WaitForAction(void)
Wait until there is some activity on one (or more) of the HTTP requests, or until some other conditio...
E_HttpErr HP_SetPostData(void *handle, U8BIT *postdata)
Set POST data for an HTTP request.
E_HttpErr HP_SetTimeout(U16BIT timeout)
Set timeout (in seconds) for HTTP requests. The timeout applies to connections (i.e. the time it takes to connect to the server) as well as response time (i.e the time it takes to download the content). Between sending the request and receiving the first byte of the the response there is no timeout.
E_HttpErr HP_Initialise(void)
Initialise the HTTP interface.
E_HttpErr HP_DestroyRequest(void *handle)
Destroy an HTTP request.
void STB_OSMutexLock(void *mutex)
Lock a mutex (a.k.a. 'enter', 'wait' or 'get').
E_HttpErr HP_AddHeader(void *handle, U8BIT *header)
Add HTTP header to HTTP request.
References: [1] UK1 Profile - Digital Terrestrial Television - Requirements for interoperability (The...
E_HttpErr HP_SetUserAgent(U8BIT *user_agent)
Set user agent for HTTP client.
E_HttpErr HP_SetUserData(void *handle, void *userdata)
Set user data associated with an HTTP request.
E_HttpErr HP_AddTlsCertificate(U8BIT *cert, U32BIT len)
Add a certificate for TLS connections.
E_HttpErr HP_Terminate(void)
Terminate the HTTP interface.
Header file - Function prototypes for operating system.