18c58dc9c7
Bundler needs one source for internal and public gems, but gems virtuals have no merger, so a local gems repo and rubygems.org cannot be served together. - merge `info/<gem>` across members (member order wins a duplicate version-platform); pass a single-member gem through verbatim - regenerate `versions` lines and md5s for gems several members list; union `names` - 302 `gems/*.gem` and `quick/Marshal.4.8/*` to the member owning that version, via the shared member-path validation - return 502 on a member error; cache merges in the shared virtual cache; route HEAD on virtuals - add `docs/gems/virtual.md` and a stock `ruby:3.3` bundler e2e-docker case Reviewed-on: #154 Co-authored-by: unkin-agent <unkin-agent@unkin.net> Co-committed-by: unkin-agent <unkin-agent@unkin.net>
40 lines
1.2 KiB
Go
40 lines
1.2 KiB
Go
package v1
|
|
|
|
import (
|
|
"errors"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"git.unkin.net/unkin/artifactapi/internal/virtual"
|
|
"git.unkin.net/unkin/artifactapi/pkg/models"
|
|
)
|
|
|
|
// serveVirtualGems serves the merged compact index and 302s downloads to the
|
|
// member owning that version.
|
|
func (h *ProxyHandler) serveVirtualGems(w http.ResponseWriter, r *http.Request, virt models.Virtual, path, proxyBaseURL string) {
|
|
var body []byte
|
|
var loc string
|
|
var err error
|
|
if isGemsIndexPath(path) {
|
|
body, _, err = h.virtualEngine.FetchGems(r.Context(), virt, path)
|
|
} else {
|
|
loc, err = h.virtualEngine.GemsRedirect(r.Context(), virt, path, r.URL.RawQuery, proxyBaseURL)
|
|
}
|
|
switch {
|
|
case errors.Is(err, virtual.ErrNotFound):
|
|
gemsText(w, http.StatusNotFound, "not found")
|
|
case errors.Is(err, virtual.ErrBadPath):
|
|
gemsText(w, http.StatusBadRequest, err.Error())
|
|
case err != nil:
|
|
slog.Error("virtual gems fetch failed", "virtual", virt.Name, "path", path, "error", err)
|
|
gemsText(w, http.StatusBadGateway, "bad gateway")
|
|
case loc != "":
|
|
w.Header().Set("Cache-Control", "no-store")
|
|
w.Header().Set("Vary", "Host, X-Forwarded-Proto")
|
|
http.Redirect(w, r, loc, http.StatusFound)
|
|
default:
|
|
w.Header().Set("X-Artifact-Source", "virtual")
|
|
gemsText(w, http.StatusOK, string(body))
|
|
}
|
|
}
|