Skip to content

Commit

Permalink
Fix module path with "/v135/*PKG/" (esm-dev#1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
ije authored Jan 17, 2025
1 parent ced51f6 commit 70696fd
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 28 deletions.
56 changes: 29 additions & 27 deletions server/legacy_router.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"bytes"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
Expand Down Expand Up @@ -119,9 +118,28 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, buildVersionPrefi
if strings.HasPrefix(pathname, "/node_") && strings.HasSuffix(pathname, ".js") {
isStatic = true
} else {
pkgName, pkgVersion, subPath, hasTargetSegment, err := splitLegacyESMPath(pathname)
if err != nil {
return rex.Status(400, err.Error())
if strings.HasPrefix(pathname, "/gh/") {
if !strings.ContainsRune(pathname[4:], '/') {
return rex.Status(400, "invalid path")
}
// add a leading `@` to the package name
pathname = "/@" + pathname[4:]
}
pkgName, pkgVersion, subPath, hasTargetSegment := splitEsmPath(pathname)
var asteriskFlag bool
if len(pkgName) > 1 && pkgName[0] == '*' {
asteriskFlag = true
pkgName = pkgName[1:]
}
if !validatePackageName(pkgName) {
return rex.Status(400, "Invalid Package Name")
}
var extraQuery string
if pkgVersion != "" {
pkgVersion, extraQuery = utils.SplitByFirstByte(pkgVersion, '&')
if v, e := url.QueryUnescape(pkgVersion); e == nil {
pkgVersion = v
}
}
if !isExactVersion(pkgVersion) {
npmrc := DefaultNpmRC()
Expand All @@ -139,9 +157,16 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, buildVersionPrefi
b.WriteString(buildVersionPrefix)
}
b.WriteByte('/')
if asteriskFlag {
b.WriteByte('*')
}
b.WriteString(pkgName)
b.WriteByte('@')
b.WriteString(pkgInfo.Version)
if extraQuery != "" {
b.WriteByte('&')
b.WriteString(extraQuery)
}
if subPath != "" {
b.WriteByte('/')
b.WriteString(subPath)
Expand Down Expand Up @@ -281,26 +306,3 @@ func legacyESM(ctx *rex.Context, buildStorage storage.Storage, buildVersionPrefi
return code
}
}

func splitLegacyESMPath(pathname string) (pkgName string, version string, subPath string, hasTargetSegment bool, err error) {
if strings.HasPrefix(pathname, "/gh/") {
if !strings.ContainsRune(pathname[4:], '/') {
err = errors.New("invalid path")
return
}
// add a leading `@` to the package name
pathname = "/@" + pathname[4:]
}

pkgName, maybeVersion, subPath, hasTargetSegment := splitEsmPath(pathname)
if !validatePackageName(pkgName) {
err = fmt.Errorf("invalid package name '%s'", pkgName)
return
}

version, _ = utils.SplitByFirstByte(maybeVersion, '&')
if v, e := url.QueryUnescape(version); e == nil {
version = v
}
return
}
2 changes: 1 addition & 1 deletion server/npm.go
Original file line number Diff line number Diff line change
Expand Up @@ -866,7 +866,7 @@ func isNumericString(s string) bool {

// based on https://github.com/npm/validate-npm-package-name
func validatePackageName(pkgName string) bool {
if len(pkgName) > 214 {
if l := len(pkgName); l == 0 || l > 214 {
return false
}
if strings.HasPrefix(pkgName, "@") {
Expand Down
36 changes: 36 additions & 0 deletions test/legacy-routes/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ Deno.test("legacy routes", async () => {
assertEquals(res.headers.get("X-TypeScript-Types"), "http://localhost:8080/v135/@types/react-dom@~18.3/index.d.ts");
assertStringIncludes(await res.text(), "/v135/[email protected]/es2022/react-dom.development.mjs");
}
{
const res = await fetch("http://localhost:8080/react-dom@18&pin=v135&dev", {
redirect: "manual",
headers: {
"User-Agent":
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36",
},
});
res.body?.cancel();
assertEquals(res.status, 302);
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/react-dom@18."));
assert(res.headers.get("Location")?.endsWith("&pin=v135&dev"));
}
{
const res = await fetch("http://localhost:8080/[email protected]/client?pin=v135", {
headers: {
Expand Down Expand Up @@ -136,6 +149,29 @@ Deno.test("legacy routes", async () => {
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/v135/@emotion/sheet@"));
assert(res.headers.get("Location")?.endsWith("?external=react,react-dom"));
}
{
const res = await fetch("http://localhost:8080/v135/[email protected]/client?external=*");
assertEquals(res.status, 200);
assertStringIncludes(await res.text(), "/v135/[email protected]/X-ZS8q/denonext/client.js");
}
{
const res = await fetch("http://localhost:8080/*[email protected]/client?pin=v135");
assertEquals(res.status, 200);
assertStringIncludes(await res.text(), "/v135/[email protected]/X-ZS8q/denonext/client.js");
}
{
const res = await fetch("http://localhost:8080/v135/*[email protected]/client");
assertEquals(res.status, 200);
assertStringIncludes(await res.text(), "/v135/[email protected]/X-ZS8q/denonext/client.js");
}
{
const res = await fetch("http://localhost:8080/v135/*react-dom@19/client", {
redirect: "manual",
});
res.body?.cancel();
assertEquals(res.status, 302);
assert(res.headers.get("Location")?.startsWith("http://localhost:8080/v135/*react-dom@19."));
}
{
const res = await fetch("http://localhost:8080/v135/@types/react-dom@~18.3/index.d.ts", {
redirect: "manual",
Expand Down

0 comments on commit 70696fd

Please sign in to comment.