update
This commit is contained in:
@@ -45,7 +45,7 @@ func rewriteResponse(
|
|||||||
) (int, map[string]string, []byte, error) {
|
) (int, map[string]string, []byte, error) {
|
||||||
switch {
|
switch {
|
||||||
case path == "/packages.json":
|
case path == "/packages.json":
|
||||||
data, changed, err := rewriteComposerRootBody(body, ctx.Domain)
|
data, changed, err := rewriteComposerRootBody(body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return status, headers, body, err
|
return status, headers, body, err
|
||||||
}
|
}
|
||||||
@@ -104,29 +104,32 @@ func contentType(_ *hooks.RequestContext, locatorPath string) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteComposerRootBody(body []byte, domain string) ([]byte, bool, error) {
|
func rewriteComposerRootBody(body []byte) ([]byte, bool, error) {
|
||||||
type root struct {
|
// packages.json from Packagist may contain "packages" as array or object; we only care about URL-like fields.
|
||||||
Packages map[string]string `json:"packages"`
|
var root map[string]any
|
||||||
}
|
if err := json.Unmarshal(body, &root); err != nil {
|
||||||
var payload root
|
|
||||||
if err := json.Unmarshal(body, &payload); err != nil {
|
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
if len(payload.Packages) == 0 {
|
|
||||||
return body, false, nil
|
|
||||||
}
|
|
||||||
changed := false
|
changed := false
|
||||||
for key, value := range payload.Packages {
|
for key, val := range root {
|
||||||
rewritten := rewriteComposerAbsolute(domain, value)
|
str, ok := val.(string)
|
||||||
if rewritten != value {
|
if !ok {
|
||||||
payload.Packages[key] = rewritten
|
continue
|
||||||
|
}
|
||||||
|
switch strings.ToLower(key) {
|
||||||
|
// case "metadata-url", "providers-url", "providers-lazy-url", "notify", "notify-batch", "search":
|
||||||
|
case "metadata-url":
|
||||||
|
str = strings.ReplaceAll(str, "https://repo.packagist.org", "")
|
||||||
|
root[key] = str
|
||||||
changed = true
|
changed = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !changed {
|
if !changed {
|
||||||
return body, false, nil
|
return body, false, nil
|
||||||
}
|
}
|
||||||
data, err := json.Marshal(payload)
|
data, err := json.Marshal(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, false, err
|
return nil, false, err
|
||||||
}
|
}
|
||||||
@@ -166,7 +169,11 @@ func rewriteComposerMetadata(body []byte, domain string) ([]byte, bool, error) {
|
|||||||
return data, true, nil
|
return data, true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteComposerPackagesPayload(raw json.RawMessage, domain string, packageName string) (json.RawMessage, bool, error) {
|
func rewriteComposerPackagesPayload(
|
||||||
|
raw json.RawMessage,
|
||||||
|
domain string,
|
||||||
|
packageName string,
|
||||||
|
) (json.RawMessage, bool, error) {
|
||||||
var asArray []map[string]any
|
var asArray []map[string]any
|
||||||
if err := json.Unmarshal(raw, &asArray); err == nil {
|
if err := json.Unmarshal(raw, &asArray); err == nil {
|
||||||
rewrote := rewriteComposerVersionSlice(asArray, domain, packageName)
|
rewrote := rewriteComposerVersionSlice(asArray, domain, packageName)
|
||||||
@@ -229,7 +236,7 @@ func rewriteComposerVersion(entry map[string]any, domain string, packageName str
|
|||||||
if !ok || urlValue == "" {
|
if !ok || urlValue == "" {
|
||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
rewritten := rewriteComposerDistURL(domain, urlValue)
|
rewritten := rewriteComposerDistURL(urlValue)
|
||||||
if rewritten == urlValue {
|
if rewritten == urlValue {
|
||||||
return changed
|
return changed
|
||||||
}
|
}
|
||||||
@@ -237,46 +244,25 @@ func rewriteComposerVersion(entry map[string]any, domain string, packageName str
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
func rewriteComposerDistURL(domain, original string) string {
|
func rewriteComposerDistURL(original string) string {
|
||||||
parsed, err := url.Parse(original)
|
parsed, err := url.Parse(original)
|
||||||
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
if err != nil || parsed.Scheme == "" || parsed.Host == "" {
|
||||||
return original
|
return original
|
||||||
}
|
}
|
||||||
prefix := "/dist/" + parsed.Scheme + "/" + parsed.Host
|
if isPackagistHost(parsed.Host) {
|
||||||
newURL := url.URL{
|
pathVal := parsed.Path
|
||||||
Scheme: "https",
|
if raw := parsed.RawPath; raw != "" {
|
||||||
Host: domain,
|
pathVal = raw
|
||||||
Path: prefix + parsed.Path,
|
|
||||||
RawQuery: parsed.RawQuery,
|
|
||||||
Fragment: parsed.Fragment,
|
|
||||||
}
|
|
||||||
if raw := parsed.RawPath; raw != "" {
|
|
||||||
newURL.RawPath = prefix + raw
|
|
||||||
}
|
|
||||||
return newURL.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
func rewriteComposerAbsolute(domain, raw string) string {
|
|
||||||
if raw == "" {
|
|
||||||
return raw
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(raw, "//") {
|
|
||||||
return "https://" + domain + strings.TrimPrefix(raw, "//")
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(raw, "http://") || strings.HasPrefix(raw, "https://") {
|
|
||||||
parsed, err := url.Parse(raw)
|
|
||||||
if err != nil {
|
|
||||||
return raw
|
|
||||||
}
|
}
|
||||||
parsed.Host = domain
|
if !strings.HasPrefix(pathVal, "/") {
|
||||||
parsed.Scheme = "https"
|
pathVal = "/" + pathVal
|
||||||
return parsed.String()
|
}
|
||||||
|
if parsed.RawQuery != "" {
|
||||||
|
return pathVal + "?" + parsed.RawQuery
|
||||||
|
}
|
||||||
|
return pathVal
|
||||||
}
|
}
|
||||||
pathVal := raw
|
return original
|
||||||
if !strings.HasPrefix(pathVal, "/") {
|
|
||||||
pathVal = "/" + pathVal
|
|
||||||
}
|
|
||||||
return "https://" + domain + pathVal
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func isComposerMetadataPath(path string) bool {
|
func isComposerMetadataPath(path string) bool {
|
||||||
@@ -331,3 +317,14 @@ func parseComposerDistURL(path string, rawQuery string) (*url.URL, bool) {
|
|||||||
}
|
}
|
||||||
return target, true
|
return target, true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stripPackagistHost(raw string) string {
|
||||||
|
raw = strings.TrimSpace(raw)
|
||||||
|
raw = strings.ReplaceAll(raw, "https://repo.packagist.org", "")
|
||||||
|
raw = strings.ReplaceAll(raw, "http://repo.packagist.org", "")
|
||||||
|
return raw
|
||||||
|
}
|
||||||
|
|
||||||
|
func isPackagistHost(host string) bool {
|
||||||
|
return strings.EqualFold(host, "repo.packagist.org")
|
||||||
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ func TestResolveDistUpstream(t *testing.T) {
|
|||||||
|
|
||||||
func TestRewriteResponseUpdatesURLs(t *testing.T) {
|
func TestRewriteResponseUpdatesURLs(t *testing.T) {
|
||||||
ctx := &hooks.RequestContext{Domain: "cache.example"}
|
ctx := &hooks.RequestContext{Domain: "cache.example"}
|
||||||
body := []byte(`{"packages":{"a/b":{"1.0.0":{"dist":{"url":"https://pkg.example/dist.zip"}}}}}`)
|
body := []byte(`{"packages":{"a/b":{"1.0.0":{"dist":{"url":"https://repo.packagist.org/dist/package.zip"}}}}}`)
|
||||||
_, headers, rewritten, err := rewriteResponse(ctx, 200, map[string]string{}, body, "/p2/a/b.json")
|
_, headers, rewritten, err := rewriteResponse(ctx, 200, map[string]string{}, body, "/p2/a/b.json")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("rewrite failed: %v", err)
|
t.Fatalf("rewrite failed: %v", err)
|
||||||
@@ -37,7 +37,7 @@ func TestRewriteResponseUpdatesURLs(t *testing.T) {
|
|||||||
if headers["Content-Type"] != "application/json" {
|
if headers["Content-Type"] != "application/json" {
|
||||||
t.Fatalf("expected json content type")
|
t.Fatalf("expected json content type")
|
||||||
}
|
}
|
||||||
if !strings.Contains(string(rewritten), "https://cache.example/dist/https/pkg.example/dist.zip") {
|
if !strings.Contains(string(rewritten), "/dist/package.zip") {
|
||||||
t.Fatalf("expected rewritten URL, got %s", string(rewritten))
|
t.Fatalf("expected stripped packagist host, got %s", string(rewritten))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -263,7 +263,8 @@ func applyHookRewrite(hook *hookState, resp *http.Response, path string) (*http.
|
|||||||
body, err := io.ReadAll(resp.Body)
|
body, err := io.ReadAll(resp.Body)
|
||||||
resp.Body.Close()
|
resp.Body.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
resp.Body = io.NopCloser(bytes.NewReader(nil))
|
||||||
|
return resp, err
|
||||||
}
|
}
|
||||||
headers := make(map[string]string, len(resp.Header))
|
headers := make(map[string]string, len(resp.Header))
|
||||||
for key, values := range resp.Header {
|
for key, values := range resp.Header {
|
||||||
@@ -273,7 +274,9 @@ func applyHookRewrite(hook *hookState, resp *http.Response, path string) (*http.
|
|||||||
}
|
}
|
||||||
status, newHeaders, newBody, rewriteErr := hook.def.RewriteResponse(hook.ctx, resp.StatusCode, headers, body, path)
|
status, newHeaders, newBody, rewriteErr := hook.def.RewriteResponse(hook.ctx, resp.StatusCode, headers, body, path)
|
||||||
if rewriteErr != nil {
|
if rewriteErr != nil {
|
||||||
return nil, rewriteErr
|
resp.Body = io.NopCloser(bytes.NewReader(body))
|
||||||
|
resp.ContentLength = int64(len(body))
|
||||||
|
return resp, rewriteErr
|
||||||
}
|
}
|
||||||
if newHeaders == nil {
|
if newHeaders == nil {
|
||||||
newHeaders = headers
|
newHeaders = headers
|
||||||
|
|||||||
Reference in New Issue
Block a user