Skip to content

KVM direct download: QCOW2 virtual size check fails for http:// URLs that redirect to HTTPS ("Unable to skip to the virtual size header") #14506

Open

Description

@kiranchavala

problem

For QCOW2 Direct Download templates, CheckUrlCommand also reads the QCOW2 header to obtain the virtual size. When the template URL is http:// and the server redirects to https://

Related: #12878

versions

ACS 4.22.x and 4.23.x

The steps to reproduce the bug

  1. Set store.download.follow.redirects to true.

  2. Ensure the HTTPS targets are trusted by the agent (e.g. upload Sectigo Public Server Authentication Root E46
    and ISRG Root X1 via uploadTemplateDirectDownloadCertificate) so TLS is not the failure cause.

  3. Register a direct download QCOW2 template:

    cmk register template name=cirros-http-redirect displaytext=cirros format=QCOW2 hypervisor=KVM \
      url=http://github.com/cirros-dev/cirros/releases/download/0.6.2/cirros-0.6.2-x86_64-disk.img \
      ostypeid=<id> zoneid=<id> directdownload=true
    
  4. Registration fails; the agent log shows the QCOW2Utils error above.

  5. The same image via https://github.com/... (https→https redirect) succeeds and returns templateSize.

What to do about it?

Root cause


`QCOW2Utils.getVirtualSizeFromUrl()` uses `java.net.HttpURLConnection` with
`setInstanceFollowRedirects(followRedirects)`. By design, the JDK **never follows redirects that change
protocol** (http→https or https→http), even when instance redirects are enabled. The connection therefore
returns the `301` response itself:

    $ curl -sI http://github.com/cirros-dev/cirros/releases/download/0.6.2/cirros-0.6.2-x86_64-disk.img
    HTTP/1.1 301 Moved Permanently
    Content-Length: 0
    Location: https://github.com/cirros-dev/cirros/releases/download/0.6.2/cirros-0.6.2-x86_64-disk.img

`getVirtualSize()` then calls `inputStream.skip(24)` on the empty 301 body, which throws
"Unable to skip to the virtual size header", reported as "Failed to connect URL".

So any QCOW2 direct download template registered with an `http://` URL that redirects to HTTPS
cannot be registered, regardless of `store.download.follow.redirects` or trust-store configuration.

What to do about it?

  • In QCOW2Utils.getVirtualSizeFromUrl(), follow redirects manually when followRedirects is true: disable
    setInstanceFollowRedirects, and on a 3xx response with a Location header, resolve it against the
    current URL (new URL(current, location)), open a new connection, and repeat up to a maximum hop
    count (e.g. 10).
  • Preferably, have the direct download downloaders read the QCOW2 header through their own HttpClient 4.x
    client (GET with Range: bytes=0-1023), which handles cross-protocol redirects and uses the merged
    cloud.jks + cacerts SSL context. This also fixes HttpsDirectTemplateDownloader.getRemoteFileSize(),
    which currently sets the custom SSLContext on one connection but reads from urlObj.openStream()
    (a new connection using the JVM default cloud.jks-only trust store).
  • Add unit tests for: http→https 301, relative Location headers, and the max-hop limit.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions

      ⌂ Proxy