ad72c3d630
Remotes answer only GET, so HEAD probes get 405, and there is no RubyGems remote. Synthesized (github_*) and rewritten (npm, helm, pypi, puppet, terraform, nuget) mutable responses need the GET path for HEAD lengths to match.
- add a HEAD route for /api/v1/remote/{name}/*; rewritten and synthesized mutable HEADs go through the GET path
- mark rewriting providers with a ResponseRewriter capability; set Content-Length on proxied GETs
- use the remote's upstream client for upstream HEAD
- add a gems remote type: compact index and specs mutable, .gem and gemspec immutable
- add gems docs, UI snippet and e2e caching case; add HEAD-vs-GET e2e checks
Reviewed-on: #148
Co-authored-by: unkin-agent <unkin-agent@unkin.net>
Co-committed-by: unkin-agent <unkin-agent@unkin.net>
63 lines
1.7 KiB
Go
63 lines
1.7 KiB
Go
// Package gems proxies a RubyGems source: mutable compact index (versions,
|
|
// info/*, names) and legacy specs indexes, plus immutable .gem and
|
|
// quick/Marshal.4.8 gemspec downloads.
|
|
package gems
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"strings"
|
|
|
|
"git.unkin.net/unkin/artifactapi/internal/auth"
|
|
"git.unkin.net/unkin/artifactapi/internal/provider"
|
|
"git.unkin.net/unkin/artifactapi/pkg/models"
|
|
)
|
|
|
|
func init() {
|
|
provider.Register(&Provider{})
|
|
}
|
|
|
|
type Provider struct{}
|
|
|
|
func (p *Provider) Type() models.PackageType { return models.PackageGems }
|
|
|
|
func (p *Provider) Classify(path string) provider.Mutability {
|
|
if isGem(path) || isQuickSpec(path) {
|
|
return provider.Immutable
|
|
}
|
|
return provider.Mutable
|
|
}
|
|
|
|
func (p *Provider) ContentType(path string) string {
|
|
path = strings.TrimLeft(path, "/")
|
|
if path == "versions" || path == "names" || strings.HasPrefix(path, "info/") {
|
|
return "text/plain; charset=utf-8"
|
|
}
|
|
if strings.HasPrefix(path, "api/v1/") && strings.HasSuffix(path, ".json") {
|
|
return "application/json"
|
|
}
|
|
return "application/octet-stream"
|
|
}
|
|
|
|
func (p *Provider) UpstreamURL(remote models.Remote, path string) string {
|
|
return strings.TrimRight(remote.BaseURL, "/") + "/" + strings.TrimLeft(path, "/")
|
|
}
|
|
|
|
func (p *Provider) RewriteResponse(_ []byte, _ models.Remote, _ string) ([]byte, error) {
|
|
return nil, nil
|
|
}
|
|
|
|
func (p *Provider) AuthHeaders(_ context.Context, remote models.Remote) (http.Header, error) {
|
|
return auth.BasicHeaders(remote), nil
|
|
}
|
|
|
|
func isGem(path string) bool {
|
|
path = strings.TrimLeft(path, "/")
|
|
return strings.HasPrefix(path, "gems/") && strings.HasSuffix(path, ".gem")
|
|
}
|
|
|
|
func isQuickSpec(path string) bool {
|
|
path = strings.TrimLeft(path, "/")
|
|
return strings.HasPrefix(path, "quick/Marshal.4.8/") && strings.HasSuffix(path, ".gemspec.rz")
|
|
}
|