2424#include < cstdarg>
2525#include < filesystem>
2626#include < fstream>
27+ #include < future>
2728#include < list>
2829#include < regex>
2930#include < set>
3637#if defined(LLAMA_USE_CURL)
3738#include < curl/curl.h>
3839#include < curl/easy.h>
39- #include < future>
4040#endif
4141
42+ #ifdef __linux__
43+ #include < linux/limits.h>
44+ #elif defined(_WIN32)
45+ # if !defined(PATH_MAX)
46+ # define PATH_MAX MAX_PATH
47+ # endif
48+ #elif defined(_AIX)
49+ #include < sys/limits.h>
50+ #else
51+ #include < sys/syslimits.h>
52+ #endif
53+ #define LLAMA_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
54+
4255using json = nlohmann::ordered_json;
4356
4457std::initializer_list<enum llama_example> mmproj_examples = {
@@ -208,19 +221,6 @@ bool common_has_curl() {
208221 return true ;
209222}
210223
211- #ifdef __linux__
212- #include < linux/limits.h>
213- #elif defined(_WIN32)
214- # if !defined(PATH_MAX)
215- # define PATH_MAX MAX_PATH
216- # endif
217- #elif defined(_AIX)
218- #include < sys/limits.h>
219- #else
220- #include < sys/syslimits.h>
221- #endif
222- #define LLAMA_CURL_MAX_URL_LENGTH 2084 // Maximum URL Length in Chrome: 2083
223-
224224//
225225// CURL utils
226226//
@@ -368,10 +368,9 @@ static bool common_download_head(CURL * curl,
368368}
369369
370370// download one single file from remote URL to local path
371- static bool common_download_file_single (const std::string & url,
372- const std::string & path,
373- const std::string & bearer_token,
374- bool offline) {
371+ static bool common_download_file_single_online (const std::string & url,
372+ const std::string & path,
373+ const std::string & bearer_token) {
375374 // If the file exists, check its JSON metadata companion file.
376375 std::string metadata_path = path + " .json" ;
377376 static const int max_attempts = 3 ;
@@ -384,10 +383,6 @@ static bool common_download_file_single(const std::string & url,
384383 // Check if the file already exists locally
385384 const auto file_exists = std::filesystem::exists (path);
386385 if (file_exists) {
387- if (offline) {
388- LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
389- return true ; // skip verification/downloading
390- }
391386 // Try and read the JSON metadata file (note: stream autoclosed upon exiting this block).
392387 std::ifstream metadata_in (metadata_path);
393388 if (metadata_in.good ()) {
@@ -407,10 +402,6 @@ static bool common_download_file_single(const std::string & url,
407402 }
408403 // if we cannot open the metadata file, we assume that the downloaded file is not valid (etag and last-modified are left empty, so we will download it again)
409404 } else {
410- if (offline) {
411- LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
412- return false ;
413- }
414405 LOG_INF (" %s: no previous model file found %s\n " , __func__, path.c_str ());
415406 }
416407
@@ -530,6 +521,89 @@ static bool common_download_file_single(const std::string & url,
530521 return true ;
531522}
532523
524+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
525+ curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
526+ curl_slist_ptr http_headers;
527+ std::vector<char > res_buffer;
528+
529+ curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
530+ curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
531+ curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
532+ curl_easy_setopt (curl.get (), CURLOPT_VERBOSE, 1L );
533+ typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
534+ auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
535+ auto data_vec = static_cast <std::vector<char > *>(data);
536+ data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
537+ return size * nmemb;
538+ };
539+ curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
540+ curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
541+ #if defined(_WIN32)
542+ curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
543+ #endif
544+ if (params.timeout > 0 ) {
545+ curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
546+ }
547+ if (params.max_size > 0 ) {
548+ curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
549+ }
550+ http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
551+ for (const auto & header : params.headers ) {
552+ http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
553+ }
554+ curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
555+
556+ CURLcode res = curl_easy_perform (curl.get ());
557+
558+ if (res != CURLE_OK) {
559+ std::string error_msg = curl_easy_strerror (res);
560+ throw std::runtime_error (" error: cannot make GET request: " + error_msg);
561+ }
562+
563+ long res_code;
564+ curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
565+
566+ return { res_code, std::move (res_buffer) };
567+ }
568+
569+ #else
570+
571+ bool common_has_curl () {
572+ return false ;
573+ }
574+
575+ static bool common_download_file_single_online (const std::string &, const std::string &, const std::string &) {
576+ LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
577+ return false ;
578+ }
579+
580+ std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
581+ if (!url.empty ()) {
582+ throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
583+ }
584+
585+ return {};
586+ }
587+
588+ #endif // LLAMA_USE_CURL
589+
590+ static bool common_download_file_single (const std::string & url,
591+ const std::string & path,
592+ const std::string & bearer_token,
593+ bool offline) {
594+ if (!offline) {
595+ return common_download_file_single_online (url, path, bearer_token);
596+ }
597+
598+ if (!std::filesystem::exists (path)) {
599+ LOG_ERR (" %s: required file is not available in cache (offline mode): %s\n " , __func__, path.c_str ());
600+ return false ;
601+ }
602+
603+ LOG_INF (" %s: using cached file (offline mode): %s\n " , __func__, path.c_str ());
604+ return true ;
605+ }
606+
533607// download multiple files from remote URLs to local paths
534608// the input is a vector of pairs <url, path>
535609static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> & urls, const std::string & bearer_token, bool offline) {
@@ -588,7 +662,7 @@ static bool common_download_model(
588662
589663 if (n_split > 1 ) {
590664 char split_prefix[PATH_MAX] = {0 };
591- char split_url_prefix[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
665+ char split_url_prefix[LLAMA_MAX_URL_LENGTH ] = {0 };
592666
593667 // Verify the first split file format
594668 // and extract split URL and PATH prefixes
@@ -609,7 +683,7 @@ static bool common_download_model(
609683 char split_path[PATH_MAX] = {0 };
610684 llama_split_path (split_path, sizeof (split_path), split_prefix, idx, n_split);
611685
612- char split_url[LLAMA_CURL_MAX_URL_LENGTH ] = {0 };
686+ char split_url[LLAMA_MAX_URL_LENGTH ] = {0 };
613687 llama_split_path (split_url, sizeof (split_url), split_url_prefix, idx, n_split);
614688
615689 if (std::string (split_path) == model.path ) {
@@ -626,50 +700,6 @@ static bool common_download_model(
626700 return true ;
627701}
628702
629- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params & params) {
630- curl_ptr curl (curl_easy_init (), &curl_easy_cleanup);
631- curl_slist_ptr http_headers;
632- std::vector<char > res_buffer;
633-
634- curl_easy_setopt (curl.get (), CURLOPT_URL, url.c_str ());
635- curl_easy_setopt (curl.get (), CURLOPT_NOPROGRESS, 1L );
636- curl_easy_setopt (curl.get (), CURLOPT_FOLLOWLOCATION, 1L );
637- typedef size_t (*CURLOPT_WRITEFUNCTION_PTR)(void * ptr, size_t size, size_t nmemb, void * data);
638- auto write_callback = [](void * ptr, size_t size, size_t nmemb, void * data) -> size_t {
639- auto data_vec = static_cast <std::vector<char > *>(data);
640- data_vec->insert (data_vec->end (), (char *)ptr, (char *)ptr + size * nmemb);
641- return size * nmemb;
642- };
643- curl_easy_setopt (curl.get (), CURLOPT_WRITEFUNCTION, static_cast <CURLOPT_WRITEFUNCTION_PTR>(write_callback));
644- curl_easy_setopt (curl.get (), CURLOPT_WRITEDATA, &res_buffer);
645- #if defined(_WIN32)
646- curl_easy_setopt (curl.get (), CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
647- #endif
648- if (params.timeout > 0 ) {
649- curl_easy_setopt (curl.get (), CURLOPT_TIMEOUT, params.timeout );
650- }
651- if (params.max_size > 0 ) {
652- curl_easy_setopt (curl.get (), CURLOPT_MAXFILESIZE, params.max_size );
653- }
654- http_headers.ptr = curl_slist_append (http_headers.ptr , " User-Agent: llama-cpp" );
655- for (const auto & header : params.headers ) {
656- http_headers.ptr = curl_slist_append (http_headers.ptr , header.c_str ());
657- }
658- curl_easy_setopt (curl.get (), CURLOPT_HTTPHEADER, http_headers.ptr );
659-
660- CURLcode res = curl_easy_perform (curl.get ());
661-
662- if (res != CURLE_OK) {
663- std::string error_msg = curl_easy_strerror (res);
664- throw std::runtime_error (" error: cannot make GET request: " + error_msg);
665- }
666-
667- long res_code;
668- curl_easy_getinfo (curl.get (), CURLINFO_RESPONSE_CODE, &res_code);
669-
670- return { res_code, std::move (res_buffer) };
671- }
672-
673703/* *
674704 * Allow getting the HF file from the HF repo with tag (like ollama), for example:
675705 * - bartowski/Llama-3.2-3B-Instruct-GGUF:q4
@@ -736,21 +766,17 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
736766 std::string mmprojFile;
737767
738768 if (res_code == 200 || res_code == 304 ) {
739- // extract ggufFile.rfilename in json, using regex
740- {
741- std::regex pattern (" \" ggufFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
742- std::smatch match;
743- if (std::regex_search (res_str, match, pattern)) {
744- ggufFile = match[1 ].str ();
769+ try {
770+ auto j = json::parse (res_str);
771+
772+ if (j.contains (" ggufFile" ) && j[" ggufFile" ].contains (" rfilename" )) {
773+ ggufFile = j[" ggufFile" ][" rfilename" ].get <std::string>();
745774 }
746- }
747- // extract mmprojFile.rfilename in json, using regex
748- {
749- std::regex pattern (" \" mmprojFile\" [\\ s\\ S]*?\" rfilename\"\\ s*:\\ s*\" ([^\" ]+)\" " );
750- std::smatch match;
751- if (std::regex_search (res_str, match, pattern)) {
752- mmprojFile = match[1 ].str ();
775+ if (j.contains (" mmprojFile" ) && j[" mmprojFile" ].contains (" rfilename" )) {
776+ mmprojFile = j[" mmprojFile" ][" rfilename" ].get <std::string>();
753777 }
778+ } catch (const std::exception & e) {
779+ throw std::runtime_error (std::string (" error parsing manifest JSON: " ) + e.what ());
754780 }
755781 if (!use_cache) {
756782 // if not using cached response, update the cache file
@@ -770,45 +796,6 @@ static struct common_hf_file_res common_get_hf_file(const std::string & hf_repo_
770796 return { hf_repo, ggufFile, mmprojFile };
771797}
772798
773- #else
774-
775- bool common_has_curl () {
776- return false ;
777- }
778-
779- static bool common_download_file_single (const std::string &, const std::string &, const std::string &, bool ) {
780- LOG_ERR (" error: built without CURL, cannot download model from internet\n " );
781- return false ;
782- }
783-
784- static bool common_download_file_multiple (const std::vector<std::pair<std::string, std::string>> &, const std::string &, bool ) {
785- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
786- return false ;
787- }
788-
789- static bool common_download_model (
790- const common_params_model &,
791- const std::string &,
792- bool ) {
793- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
794- return false ;
795- }
796-
797- static struct common_hf_file_res common_get_hf_file (const std::string &, const std::string &, bool ) {
798- LOG_ERR (" error: built without CURL, cannot download model from the internet\n " );
799- return {};
800- }
801-
802- std::pair<long , std::vector<char >> common_remote_get_content (const std::string & url, const common_remote_params &) {
803- if (!url.empty ()) {
804- throw std::runtime_error (" error: built without CURL, cannot download model from the internet" );
805- }
806-
807- return {};
808- }
809-
810- #endif // LLAMA_USE_CURL
811-
812799//
813800// Docker registry functions
814801//
0 commit comments