Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support data URIs #244

Open
1 task done
tunnckoCore opened this issue Oct 6, 2024 · 1 comment
Open
1 task done

Support data URIs #244

tunnckoCore opened this issue Oct 6, 2024 · 1 comment

Comments

@tunnckoCore
Copy link

tunnckoCore commented Oct 6, 2024

Describe the feature

It would be pretty basic option, basically skipping the url.hostname check in validateId or the validation altogther https://github.com/unjs/ipx/blob/main/src/storage/http.ts#99

Everything else can stay the same and actually work, because Fetch can fetch data URLs.

Additional information

example URI

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAD80lEQVR4nO2XT2gUVxzHP5PNbjaxkVhT0+mCZBvdQ/MH9iCiNeaQUBURWoQGtqGnHkp7K6UIIW2htASE0FMPBaEHs4JSUEFNk9hAFhXpQbD2kvVPWF2G6FpIaeN2k93pYfJmZ2ZnZ98kK/Xg97L7/uy8z3x/v/feb5WUrui8wGr4vwFq6SXgZvUScLNq9PuDI+GAa39htQhAKGiMX8kXN4FVljSgANOO9gGgXrrNrdOfARAfmeDpu3Fz7u3flzgUXrKBWl/MD7wU4JFwgF92dtDX21EBF7p4v2J+X28HWm+HDfTyl8OosQjxkQlpOPCRgwLOKje4ClDheCziC0zIdw5a3XMqOp9x7Q+3ttE9fJL0B8f9LlcbUITXKeFe99nzhFvbiM5nuLCtyehLKPyRLN+g3QmFyHiQt85eRKk3IJTDG53PEG5tIz4yYUI/OvG6Daaapne+BsA7mSdAHTfJlXyR7YFbbH11Oxe2Na27U+no22mNV5rWU3rcMTiO+ULZEzuIhB8zlV+tD+BgAOa63qjoP5RZssGkz33u+Zz4yAQ6DWTZIQUmpHiVW4MBeDwWMUP43vIqK8t/AlTdKF7SFrIcHD3DlqbG+jlYDzAhcdTIwoGEg2BcX37AtIWsDcjaFi6mdLk62fOgvrq+2fy69pd2mo9+umZrHxydNCG3hOQPm+dSzRw9XvBs/1OQ/5fxwpdbdQHUFrJmngHczY1x6bv3Adi15zBEr6Ev/mqOb20JSj/b913sJrdCYNeewwAkPhk1+5I/fAvASuF76WfXdDBQwuaOU073rHDVtLa2JoknATitw9BYsuq4GovYHHTCCdfEp19J56AfF5XOIdv4mcs3ze/Nbw5Jn4EgmYNXizAYSDL7TcI135x9+uKsDVJfnAUgNXmKfEmaDahxkwj1K8bBGmrQq0JaVS0HlU5/7oFEiAUcQHNjiKGxJN3DJz1Dfve3KVs7NXlqQ3Ag4aAVEDAXOdYCK//i6qgV/tjXkyyvQkr3W0tLAgIMBBRKltyxOmENf6FU7k+f+8KEFffwRiS1SUoeiW2DbYSZqRl6enpQVdU2T9M05g4MABBtbweg8/zPqKpqvsyGAVO6bgt1v6K45lOwIciTjz/lx/wzZmYMUKG5AwOk88+MRi4HwN937hjwHvksFWIBFVICFPSiCe0+T+fG3v08yOVMoN3hZqLt7Uw/eshX2Ycyy/kHFJBWuUEKQD/yCnVdigWrUrrCPuV6VcgH6+G1yivUvhwEeReTXTFzMzi17+Z16fWeC6AxzxsSDNBa56PvgtUJ5AQuz1P48F7aNaRCN/bup7+GP5uuqFuC1SHndEjcW/CETHbFPCH/A4GLqlx3WtZcAAAAAElFTkSuQmCC

And of course, there could be URL limit hit this way, but for small images it's okay (as above)

Other way would be to expose a similar thing programmatically accepting buffers.

  • Would you be willing to help implement this feature?
@tunnckoCore
Copy link
Author

tunnckoCore commented Oct 6, 2024

My current workaround is to detect if it's data: url, download it to the assets folder and rewrite the url of the request as it's trying local file and deleting that file after that.

import { createApp, toWebHandler } from "h3";
import {
  createIPX,
  createIPXH3App,
  createIPXH3Handler,
  ipxFSStorage,
  ipxHttpStorage,
} from "ipx";
import { rm as remove } from "node:fs/promises";

const ipx = createIPX({
  storage: ipxFSStorage({ dir: "./assets" }),
  httpStorage: ipxHttpStorage({ allowAllDomains: true, maxAge: 60 * 60 * 24 }),
});

export const app = createApp().use("/optimize", createIPXH3Handler(ipx));
const handler = toWebHandler(app);

Bun.serve({
  port: 3000,
  async fetch(req) {
    let url = new URL(req.url);

    if (url.pathname.startsWith("/optimize")) {
      const [_, seg] = url.pathname.split("/optimize/");
      const index = seg.indexOf("data");
      const fpath = index === -1 ? seg : seg.slice(index);

      let digest;

      // download it locally to the assets folder, then delete
      // at least until https://github.com/unjs/ipx/issues/244
      if (fpath.startsWith("data:")) {
        const buf = await fetch(fpath).then((res) => res.arrayBuffer());
        digest = await createDigest(new Uint8Array(buf));
        await Bun.write(`./assets/${digest}`, buf);

        const resp = await handler(
          new Request(
            `${url.origin}/optimize/${seg.slice(0, index - 1)}/${digest}`,
            req,
          ),
        );

        remove(`./assets/${digest}`);

        return resp;
      }
      return handler(req);
    }
    return new Response("Not found", { status: 404 });
  },
});

async function createDigest(
  msg: string | Uint8Array,
  algo: "SHA-1" | "SHA-256" | "SHA-512" = "SHA-256",
) {
  const data = typeof msg === "string" ? new TextEncoder().encode(msg) : msg;
  const hashBuffer = await crypto.subtle.digest(algo, data);
  const hashArray = Array.from(new Uint8Array(hashBuffer));
  const hashHex = hashArray
    .map((b) => b.toString(16).padStart(2, "0"))
    .join("");
  return hashHex;
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant