3535#define HTTP_CONTENT_TYPE_JSON "Content-Type: " HTTP_APP_JSON \
3636 "; charset=utf-8"
3737
38+ /* HTTP header API Key authentication-specific */
39+ #define HTTP_AUTH_API_KEY "Authorization: ApiKey "
40+ #define APIKEY_BUFF_SIZE 512
41+
3842/* Elasticsearch/SQL data types */
3943/* 2 */
4044#define TYPE_IP "IP"
@@ -382,6 +386,10 @@ static void cleanup_curl(esodbc_dbc_st *dbc)
382386 return ;
383387 }
384388 DBGH (dbc , "libcurl: handle 0x%p cleanup." , dbc -> curl );
389+ if (dbc -> curl_hdrs ) {
390+ curl_slist_free_all (dbc -> curl_hdrs );
391+ dbc -> curl_hdrs = NULL ;
392+ }
385393 dbc -> curl_err = CURLE_OK ;
386394 dbc -> curl_err_buff [0 ] = '\0' ;
387395
@@ -442,11 +450,34 @@ SQLRETURN dbc_curl_set_url(esodbc_dbc_st *dbc, int url_type)
442450 return SQL_ERROR ;
443451}
444452
453+ /* copy of unexported Curl_slist_duplicate() libcurl function */
454+ static struct curl_slist * curl_slist_duplicate (struct curl_slist * inlist )
455+ {
456+ struct curl_slist * outlist = NULL ;
457+ struct curl_slist * tmp ;
458+
459+ while (inlist ) {
460+ tmp = curl_slist_append (outlist , inlist -> data );
461+
462+ if (!tmp ) {
463+ curl_slist_free_all (outlist );
464+ return NULL ;
465+ }
466+
467+ outlist = tmp ;
468+ inlist = inlist -> next ;
469+ }
470+ return outlist ;
471+ }
472+
445473static SQLRETURN dbc_curl_init (esodbc_dbc_st * dbc )
446474{
447475 CURL * curl ;
448476 SQLRETURN ret ;
449477 BOOL compress ;
478+ char apikey_buff [APIKEY_BUFF_SIZE ], * apikey_ptr = NULL ;
479+ struct curl_slist * curl_hdrs ;
480+
450481
451482 assert (! dbc -> curl );
452483
@@ -467,14 +498,6 @@ static SQLRETURN dbc_curl_init(esodbc_dbc_st *dbc)
467498 goto err ;
468499 }
469500
470- /* set the HTTP headers: Content-Type, Accept */
471- dbc -> curl_err = curl_easy_setopt (curl , CURLOPT_HTTPHEADER ,
472- dbc -> pack_json ? json_headers : cbor_headers );
473- if (dbc -> curl_err != CURLE_OK ) {
474- ERRH (dbc , "libcurl: failed to set HTTP headers list." );
475- goto err ;
476- }
477-
478501 /* set the behavior for redirection */
479502 dbc -> curl_err = curl_easy_setopt (curl , CURLOPT_FOLLOWLOCATION ,
480503 dbc -> follow );
@@ -582,8 +605,55 @@ static SQLRETURN dbc_curl_init(esodbc_dbc_st *dbc)
582605 goto err ;
583606 }
584607 }
608+ } else if (dbc -> api_key .cnt ) {
609+ if (sizeof (HTTP_AUTH_API_KEY ) + dbc -> api_key .cnt <
610+ sizeof (apikey_buff )) {
611+ apikey_ptr = apikey_buff ;
612+ } else {
613+ DBGH (dbc , "static buffer size %zuB less than required %zuB, "
614+ "allocating." , sizeof (apikey_buff ), sizeof (HTTP_AUTH_API_KEY ) +
615+ dbc -> api_key .cnt );
616+ apikey_ptr = malloc (sizeof (HTTP_AUTH_API_KEY ) + dbc -> api_key .cnt );
617+ if (! apikey_ptr ) {
618+ ERRNH (dbc , "OOM for %zuB." , sizeof (HTTP_AUTH_API_KEY ) +
619+ dbc -> api_key .cnt );
620+ goto err ;
621+ }
622+ }
623+ memcpy (apikey_ptr , HTTP_AUTH_API_KEY , sizeof (HTTP_AUTH_API_KEY ) - 1 );
624+ memcpy (apikey_ptr + sizeof (HTTP_AUTH_API_KEY ) - 1 , dbc -> api_key .str ,
625+ dbc -> api_key .cnt );
626+ apikey_ptr [sizeof (HTTP_AUTH_API_KEY ) - 1 + dbc -> api_key .cnt ] = '\0' ;
627+
628+ dbc -> curl_hdrs = curl_slist_append (NULL , apikey_ptr );
629+ if (apikey_ptr != apikey_buff ) {
630+ free (apikey_ptr );
631+ apikey_ptr = NULL ;
632+ }
633+ if (! dbc -> curl_hdrs ) {
634+ ERRH (dbc , "libcurl: failed to init API key Auth header." );
635+ goto err ;
636+ }
585637 } else {
586- INFOH (dbc , "no username provided: auth disabled." );
638+ INFOH (dbc , "no username or API key provided: auth disabled." );
639+ }
640+
641+ /* set the HTTP headers: Content-Type, Accept, Authorization(?) */
642+ curl_hdrs = dbc -> pack_json ? json_headers : cbor_headers ;
643+ /* is there already an Autorization header set? then chain the pack hdrs */
644+ if (dbc -> curl_hdrs ) {
645+ if (! (curl_hdrs = curl_slist_duplicate (curl_hdrs ))) {
646+ ERRNH (dbc , "failed duplicating packing format headers." );
647+ goto err ;
648+ }
649+ dbc -> curl_hdrs -> next = curl_hdrs ;
650+ /* if there's no Authz header, the pack headers won't be dup'd */
651+ curl_hdrs = dbc -> curl_hdrs ;
652+ }
653+ dbc -> curl_err = curl_easy_setopt (curl , CURLOPT_HTTPHEADER , curl_hdrs );
654+ if (dbc -> curl_err != CURLE_OK ) {
655+ ERRH (dbc , "libcurl: failed to set HTTP headers list." );
656+ goto err ;
587657 }
588658
589659 /* proxy parameters */
@@ -1322,6 +1392,14 @@ SQLRETURN config_dbc(esodbc_dbc_st *dbc, esodbc_dsn_attrs_st *attrs)
13221392 /* indicates the presence of a non-empty password */
13231393 INFOH (dbc , "connection PWD: " ESODBC_PWD_VAL_SUBST "." );
13241394 }
1395+ } else if (attrs -> api_key .cnt ) {
1396+ if (! wstr_to_utf8 (& attrs -> api_key , & dbc -> api_key )) {
1397+ ERRH (dbc , "failed to convert API key [%zu] `" LWPDL "` to UTF8." ,
1398+ attrs -> api_key .cnt , LWSTR (& attrs -> api_key ));
1399+ SET_HDIAG (dbc , SQL_STATE_HY000 , "API key UTF8 conversion failed" ,
1400+ 0 );
1401+ goto err ;
1402+ }
13251403 }
13261404
13271405 /* "follow location" param for liburl */
0 commit comments