[PATCH 2/2] erofs-utils: lib: oci: allow HTTP connections to registry
Gao Xiang
hsiangkao at linux.alibaba.com
Tue Dec 2 18:40:15 AEDT 2025
Hi Yifan,
Would you mind updating mkfs.erofs manpage too?
Thanks,
Gao Xiang
On 2025/12/1 19:15, zhaoyifan (H) wrote:
> Hi Chengyu,
>
> Thanks for your review. I will try to deal with `mount.erofs` later.
>
>
> Thanks,
>
> Yifan Zhao
>
>
> On 2025/12/1 17:25, hudsonZhu wrote:
>> Thanks for this patch, Yifan !
>>
>> It looks good to me. I have tested the patch and it works as expected.
>> One suggestion: it would be nice to have similar functionality in
>> mount.erofs as well, for consistency across the toolkit.
>>
>> Reviewed-and-tested-by: Chengyu Zhu <hudsonzhu at tencent.com>
>>
>> Thanks,
>> Chengyu
>>
>>> 2025年11月30日 18:42,Yifan Zhao <zhaoyifan28 at huawei.com> 写道:
>>>
>>> Currently, the URL used to send requests to the registry is hardcoded
>>> with "https://". This patch introduces an optional insecure option for
>>> `--oci`, enabling registry access via the HTTP protocol.
>>>
>>> Also, this patch refactors the deeply nested logic in the `--oci`
>>> argument parsing.
>>>
>>> Signed-off-by: Yifan Zhao <zhaoyifan28 at huawei.com>
>>> ---
>>> lib/liberofs_oci.h | 3 ++
>>> lib/remotes/oci.c | 40 +++++++++++--------
>>> mkfs/main.c | 97 ++++++++++++++++++++--------------------------
>>> 3 files changed, 70 insertions(+), 70 deletions(-)
>>>
>>> diff --git a/lib/liberofs_oci.h b/lib/liberofs_oci.h
>>> index 5298f18..9e0571f 100644
>>> --- a/lib/liberofs_oci.h
>>> +++ b/lib/liberofs_oci.h
>>> @@ -23,6 +23,7 @@ struct erofs_importer;
>>> * @password: password for authentication (optional)
>>> * @blob_digest: specific blob digest to extract (NULL for all layers)
>>> * @layer_index: specific layer index to extract (negative for all layers)
>>> + * @insecure: use HTTP for registry communication (optional)
>>> *
>>> * Configuration structure for OCI image parameters including registry
>>> * location, image identification, platform specification, and authentication
>>> @@ -37,6 +38,7 @@ struct ocierofs_config {
>>> int layer_index;
>>> char *tarindex_path;
>>> char *zinfo_path;
>>> + bool insecure;
>>> };
>>>
>>> struct ocierofs_layer_info {
>>> @@ -57,6 +59,7 @@ struct ocierofs_ctx {
>>> struct ocierofs_layer_info **layers;
>>> char *blob_digest;
>>> int layer_count;
>>> + const char *schema;
>>> };
>>>
>>> struct ocierofs_iostream {
>>> diff --git a/lib/remotes/oci.c b/lib/remotes/oci.c
>>> index c1d6cae..d5afd6a 100644
>>> --- a/lib/remotes/oci.c
>>> +++ b/lib/remotes/oci.c
>>> @@ -496,8 +496,8 @@ static char *ocierofs_discover_auth_endpoint(struct ocierofs_ctx *ctx,
>>>
>>> api_registry = ocierofs_get_api_registry(registry);
>>>
>>> - if (asprintf(&test_url, "https://%s/v2/%s/manifests/nonexistent",
>>> - api_registry, repository) < 0)
>>> + if (asprintf(&test_url, "%s%s/v2/%s/manifests/nonexistent",
>>> + ctx->schema, api_registry, repository) < 0)
>>> return NULL;
>>>
>>> curl_easy_reset(ctx->curl);
>>> @@ -528,9 +528,9 @@ static char *ocierofs_get_auth_token(struct ocierofs_ctx *ctx, const char *regis
>>> const char *password)
>>> {
>>> static const char * const auth_patterns[] = {
>>> - "https://%s/v2/auth",
>>> - "https://auth.%s/token",
>>> - "https://%s/token",
>>> + "%s%s/v2/auth",
>>> + "%sauth.%s/token",
>>> + "%s%s/token",
>>> NULL,
>>> };
>>> char *auth_header = NULL;
>>> @@ -561,8 +561,8 @@ static char *ocierofs_get_auth_token(struct ocierofs_ctx *ctx, const char *regis
>>>
>>> api_registry = ocierofs_get_api_registry(registry);
>>>
>>> - if (asprintf(&test_url, "https://%s/v2/%s/manifests/nonexistent",
>>> - api_registry, repository) >= 0) {
>>> + if (asprintf(&test_url, "%s%s/v2/%s/manifests/nonexistent",
>>> + ctx->schema, api_registry, repository) >= 0) {
>>> curl_easy_reset(ctx->curl);
>>> ocierofs_curl_setup_common_options(ctx->curl);
>>>
>>> @@ -598,7 +598,7 @@ static char *ocierofs_get_auth_token(struct ocierofs_ctx *ctx, const char *regis
>>> for (i = 0; auth_patterns[i]; i++) {
>>> char *auth_url;
>>>
>>> - if (asprintf(&auth_url, auth_patterns[i], registry) < 0)
>>> + if (asprintf(&auth_url, auth_patterns[i], ctx->schema, registry) < 0)
>>> continue;
>>>
>>> auth_header = ocierofs_get_auth_token_with_url(ctx, auth_url,
>>> @@ -629,8 +629,8 @@ static char *ocierofs_get_manifest_digest(struct ocierofs_ctx *ctx,
>>> int ret = 0, len, i;
>>>
>>> api_registry = ocierofs_get_api_registry(registry);
>>> - if (asprintf(&req.url, "https://%s/v2/%s/manifests/%s",
>>> - api_registry, repository, tag) < 0)
>>> + if (asprintf(&req.url, "%s%s/v2/%s/manifests/%s",
>>> + ctx->schema, api_registry, repository, tag) < 0)
>>> return ERR_PTR(-ENOMEM);
>>>
>>> if (auth_header && strstr(auth_header, "Bearer"))
>>> @@ -749,8 +749,8 @@ static int ocierofs_fetch_layers_info(struct ocierofs_ctx *ctx)
>>> ctx->layer_count = 0;
>>> api_registry = ocierofs_get_api_registry(registry);
>>>
>>> - if (asprintf(&req.url, "https://%s/v2/%s/manifests/%s",
>>> - api_registry, repository, digest) < 0)
>>> + if (asprintf(&req.url, "%s%s/v2/%s/manifests/%s",
>>> + ctx->schema, api_registry, repository, digest) < 0)
>>> return -ENOMEM;
>>>
>>> if (auth_header && strstr(auth_header, "Bearer"))
>>> @@ -1124,10 +1124,18 @@ static int ocierofs_init(struct ocierofs_ctx *ctx, const struct ocierofs_config
>>> if (!ctx->registry || !ctx->tag || !ctx->platform)
>>> return -ENOMEM;
>>>
>>> + ctx->schema = config->insecure ? "http://" : "https://";
>>> +
>>> ret = ocierofs_parse_ref(ctx, config->image_ref);
>>> if (ret)
>>> return ret;
>>>
>>> + if (config->insecure && (!strcmp(ctx->registry, DOCKER_API_REGISTRY) ||
>>> + !strcmp(ctx->registry, DOCKER_REGISTRY))) {
>>> + erofs_err("Insecure connection to Docker registry is not allowed");
>>> + return -EINVAL;
>>> + }
>>> +
>>> ret = ocierofs_prepare_layers(ctx, config);
>>> if (ret)
>>> return ret;
>>> @@ -1152,8 +1160,8 @@ static int ocierofs_download_blob_to_fd(struct ocierofs_ctx *ctx,
>>> };
>>>
>>> api_registry = ocierofs_get_api_registry(ctx->registry);
>>> - if (asprintf(&req.url, "https://%s/v2/%s/blobs/%s",
>>> - api_registry, ctx->repository, digest) == -1)
>>> + if (asprintf(&req.url, "%s%s/v2/%s/blobs/%s",
>>> + ctx->schema, api_registry, ctx->repository, digest) == -1)
>>> return -ENOMEM;
>>>
>>> if (auth_header && strstr(auth_header, "Bearer"))
>>> @@ -1344,8 +1352,8 @@ static int ocierofs_download_blob_range(struct ocierofs_ctx *ctx, off_t offset,
>>> length = (size_t)(blob_size - offset);
>>>
>>> api_registry = ocierofs_get_api_registry(ctx->registry);
>>> - if (asprintf(&req.url, "https://%s/v2/%s/blobs/%s",
>>> - api_registry, ctx->repository, digest) == -1)
>>> + if (asprintf(&req.url, "%s%s/v2/%s/blobs/%s",
>>> + ctx->schema, api_registry, ctx->repository, digest) == -1)
>>> return -ENOMEM;
>>>
>>> if (length)
>>> diff --git a/mkfs/main.c b/mkfs/main.c
>>> index 7aa8eae..5710948 100644
>>> --- a/mkfs/main.c
>>> +++ b/mkfs/main.c
>>> @@ -218,11 +218,12 @@ static void usage(int argc, char **argv)
>>> #endif
>>> #ifdef OCIEROFS_ENABLED
>>> " --oci=[f|i] generate a full (f) or index-only (i) image from OCI remote source\n"
>>> - " [,=platform=X] X=platform (default: linux/amd64)\n"
>>> + " [,platform=X] X=platform (default: linux/amd64)\n"
>>> " [,layer=#] #=layer index to extract (0-based; omit to extract all layers)\n"
>>> " [,blob=Y] Y=blob digest to extract (omit to extract all layers)\n"
>>> " [,username=Z] Z=username for authentication (optional)\n"
>>> " [,password=W] W=password for authentication (optional)\n"
>>> + " [,insecure] use HTTP instead of HTTPS (optional)\n"
>>> #endif
>>> " --tar=X generate a full or index-only image from a tarball(-ish) source\n"
>>> " (X = f|i|headerball; f=full mode, i=index mode,\n"
>>> @@ -744,7 +745,7 @@ static int mkfs_parse_s3_cfg(char *cfg_str)
>>> * Parse OCI options string containing comma-separated key=value pairs.
>>> *
>>> * Supported options include f|i, platform, blob|layer, username, password,
>>> - * and zinfo.
>>> + * and insecure.
>>> *
>>> * Return: 0 on success, negative errno on failure
>>> */
>>> @@ -772,67 +773,55 @@ static int mkfs_parse_oci_options(struct ocierofs_config *oci_cfg, char *options
>>> if (q)
>>> *q = '\0';
>>>
>>> -
>>> - p = strstr(opt, "platform=");
>>> - if (p) {
>>> + if ((p = strstr(opt, "platform="))) {
>>> p += strlen("platform=");
>>> free(oci_cfg->platform);
>>> oci_cfg->platform = strdup(p);
>>> if (!oci_cfg->platform)
>>> return -ENOMEM;
>>> - } else {
>>> - p = strstr(opt, "blob=");
>>> - if (p) {
>>> - p += strlen("blob=");
>>> - free(oci_cfg->blob_digest);
>>> + } else if ((p = strstr(opt, "blob="))) {
>>> + p += strlen("blob=");
>>> + free(oci_cfg->blob_digest);
>>>
>>> - if (oci_cfg->layer_index >= 0) {
>>> - erofs_err("invalid --oci: blob and layer cannot be set together");
>>> - return -EINVAL;
>>> - }
>>> + if (oci_cfg->layer_index >= 0) {
>>> + erofs_err("invalid --oci: blob and layer cannot be set together");
>>> + return -EINVAL;
>>> + }
>>>
>>> - if (!strncmp(p, "sha256:", 7)) {
>>> - oci_cfg->blob_digest = strdup(p);
>>> - if (!oci_cfg->blob_digest)
>>> - return -ENOMEM;
>>> - } else if (asprintf(&oci_cfg->blob_digest, "sha256:%s", p) < 0) {
>>> + if (!strncmp(p, "sha256:", 7)) {
>>> + oci_cfg->blob_digest = strdup(p);
>>> + if (!oci_cfg->blob_digest)
>>> return -ENOMEM;
>>> - }
>>> - } else {
>>> - p = strstr(opt, "layer=");
>>> - if (p) {
>>> - p += strlen("layer=");
>>> - if (oci_cfg->blob_digest) {
>>> - erofs_err("invalid --oci: layer and blob cannot be set together");
>>> - return -EINVAL;
>>> - }
>>> - idx = strtol(p, NULL, 10);
>>> - if (idx < 0)
>>> - return -EINVAL;
>>> - oci_cfg->layer_index = (int)idx;
>>> - } else {
>>> - p = strstr(opt, "username=");
>>> - if (p) {
>>> - p += strlen("username=");
>>> - free(oci_cfg->username);
>>> - oci_cfg->username = strdup(p);
>>> - if (!oci_cfg->username)
>>> - return -ENOMEM;
>>> - } else {
>>> - p = strstr(opt, "password=");
>>> - if (p) {
>>> - p += strlen("password=");
>>> - free(oci_cfg->password);
>>> - oci_cfg->password = strdup(p);
>>> - if (!oci_cfg->password)
>>> - return -ENOMEM;
>>> - } else {
>>> - erofs_err("mkfs: invalid --oci value %s", opt);
>>> - return -EINVAL;
>>> - }
>>> - }
>>> - }
>>> + } else if (asprintf(&oci_cfg->blob_digest, "sha256:%s", p) < 0) {
>>> + return -ENOMEM;
>>> }
>>> + } else if ((p = strstr(opt, "layer="))) {
>>> + p += strlen("layer=");
>>> + if (oci_cfg->blob_digest) {
>>> + erofs_err("invalid --oci: layer and blob cannot be set together");
>>> + return -EINVAL;
>>> + }
>>> + idx = strtol(p, NULL, 10);
>>> + if (idx < 0)
>>> + return -EINVAL;
>>> + oci_cfg->layer_index = (int)idx;
>>> + } else if ((p = strstr(opt, "username="))) {
>>> + p += strlen("username=");
>>> + free(oci_cfg->username);
>>> + oci_cfg->username = strdup(p);
>>> + if (!oci_cfg->username)
>>> + return -ENOMEM;
>>> + } else if ((p = strstr(opt, "password="))) {
>>> + p += strlen("password=");
>>> + free(oci_cfg->password);
>>> + oci_cfg->password = strdup(p);
>>> + if (!oci_cfg->password)
>>> + return -ENOMEM;
>>> + } else if ((p = strstr(opt, "insecure"))) {
>>> + oci_cfg->insecure = true;
>>> + } else {
>>> + erofs_err("mkfs: invalid --oci value %s", opt);
>>> + return -EINVAL;
>>> }
>>>
>>> opt = q ? q + 1 : NULL;
>>> --
>>> 2.43.0
>>>
More information about the Linux-erofs
mailing list