|
39 | 39 | #include <photon/fs/virtual-file.h> |
40 | 40 | #include <photon/fs/localfs.h> |
41 | 41 | #include <photon/net/http/client.h> |
| 42 | +#include <photon/net/http/url.h> |
42 | 43 | #include <photon/net/utils.h> |
43 | 44 | #include <photon/net/security-context/tls-stream.h> |
44 | 45 | #include <rapidjson/document.h> |
@@ -126,9 +127,9 @@ class RegistryFSImpl_v2 : public RegistryFS { |
126 | 127 | return open(pathname, flags); // ignore mode |
127 | 128 | } |
128 | 129 |
|
129 | | - RegistryFSImpl_v2(PasswordCB callback, const char *caFile, uint64_t timeout, |
| 130 | + RegistryFSImpl_v2(PasswordCB callback, std::vector<ImageConfigNS::MirrorConfig> mirrors, const char *caFile, uint64_t timeout, |
130 | 131 | photon::net::TLSContext *ctx, const char *ua) |
131 | | - : m_callback(callback), m_caFile(caFile), m_timeout(timeout), m_tls_ctx(ctx), |
| 132 | + : m_callback(callback), m_mirrors(std::move(mirrors)), m_caFile(caFile), m_timeout(timeout), m_tls_ctx(ctx), |
132 | 133 | m_meta_size(kMinimalMetaLife), m_scope_token(kMinimalTokenLife), |
133 | 134 | m_url_info(kMinimalAUrlLife) { |
134 | 135 |
|
@@ -209,8 +210,35 @@ class RegistryFSImpl_v2 : public RegistryFS { |
209 | 210 | } |
210 | 211 |
|
211 | 212 | UrlInfo* get_actual_url(const estring &url, uint64_t timeout, long &code) { |
212 | | - |
213 | 213 | Timeout tmo(timeout); |
| 214 | + if (m_accelerate.empty() && !m_mirrors.empty()) { |
| 215 | + // If p2p acceleration is not enabled, and mirrors are configured, |
| 216 | + // check each mirror whose host matches, in order, until one of them succeeds. |
| 217 | + URL parsed(url); |
| 218 | + if (!parsed.empty()) { |
| 219 | + // The URL was parsed successfully. |
| 220 | + for (ImageConfigNS::MirrorConfig& mirror : m_mirrors) { |
| 221 | + if (mirror.host() == parsed.host_port()) { |
| 222 | + long mirror_code = 0; |
| 223 | + estring mirror_url = mirror.mirror() + std::string(parsed.path()); |
| 224 | + Timeout mirrorTimeout(std::min(tmo.timeout(), mirror.timeoutMs() * 1000)); |
| 225 | + LOG_INFO("trying mirror `", mirror_url, "` for original url `", url, "` with timeout=", mirrorTimeout.timeout_ms(), "ms"); |
| 226 | + UrlInfo* info = get_actual_url_impl(mirror_url, mirrorTimeout, mirror_code); |
| 227 | + if (info != nullptr) { |
| 228 | + code = mirror_code; |
| 229 | + return info; |
| 230 | + } |
| 231 | + } |
| 232 | + } |
| 233 | + LOG_INFO("falling back to original url `", url, "`"); |
| 234 | + } else { |
| 235 | + LOG_WARN("failed to parse url `", url, "`"); |
| 236 | + } |
| 237 | + } |
| 238 | + return get_actual_url_impl(url, tmo.timeout(), code); |
| 239 | + } |
| 240 | + |
| 241 | + UrlInfo* get_actual_url_impl(const estring &url, Timeout tmo, long &code) { |
214 | 242 | estring authurl, scope; |
215 | 243 | estring *token = nullptr; |
216 | 244 |
|
@@ -317,6 +345,7 @@ class RegistryFSImpl_v2 : public RegistryFS { |
317 | 345 |
|
318 | 346 | protected: |
319 | 347 | PasswordCB m_callback; |
| 348 | + std::vector<ImageConfigNS::MirrorConfig> m_mirrors; |
320 | 349 | estring m_accelerate; |
321 | 350 | estring m_caFile; |
322 | 351 | estring m_useragent; |
@@ -533,15 +562,15 @@ inline IFile *RegistryFSImpl_v2::open(const char *pathname, int) { |
533 | 562 | return file; |
534 | 563 | } |
535 | 564 |
|
536 | | -IFileSystem *new_registryfs_v2(PasswordCB callback, const char *caFile, uint64_t timeout, |
| 565 | +IFileSystem *new_registryfs_v2(PasswordCB callback, std::vector<ImageConfigNS::MirrorConfig> mirrors, const char *caFile, uint64_t timeout, |
537 | 566 | const char *cert_file, const char *key_file, const char *customized_ua) { |
538 | 567 | if (!callback) |
539 | 568 | LOG_ERROR_RETURN(EINVAL, nullptr, "password callback not set"); |
540 | 569 | auto ctx = new_tls_context_from_file(cert_file, key_file); |
541 | 570 | if (!ctx) { |
542 | 571 | LOG_ERRNO_RETURN(0, nullptr, "failed to new tls context"); |
543 | 572 | } |
544 | | - return new RegistryFSImpl_v2(callback, caFile ? caFile : "", timeout, ctx, customized_ua); |
| 573 | + return new RegistryFSImpl_v2(callback, std::move(mirrors), caFile ? caFile : "", timeout, ctx, customized_ua); |
545 | 574 | } |
546 | 575 |
|
547 | 576 | class RegistryUploader : public VirtualFile { |
@@ -738,7 +767,7 @@ class RegistryUploader : public VirtualFile { |
738 | 767 | photon::init(photon::INIT_EVENT_DEFAULT, photon::INIT_IO_NONE); |
739 | 768 | DEFER(photon::fini()); |
740 | 769 | m_upload_fs = new RegistryFSImpl_v2({this, &RegistryUploader::load_auth}, |
741 | | - "", m_timeout, m_tls_ctx, nullptr); |
| 770 | + {}, "", m_timeout, m_tls_ctx, nullptr); |
742 | 771 | DEFER({ delete m_upload_fs; }); |
743 | 772 | m_http_client_ts = photon::now; |
744 | 773 | ::posix_memalign(&m_upload_buf, 4096, 1024 * 1024); |
|
0 commit comments