| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Registry.Npm.Request
Description
Request shaping and URL building for the npm data plane.
Three details of the wire protocol are load-bearing and handled here:
- Content negotiation. Metadata comes in two forms selected by
Accept: the abbreviated install view (application/vnd.npm.install-v1+json), which the proxy treats as primary, and the full packument (application/json), needed when a rule reasons over publish age (the abbreviated form drops thetimemap).MetadataFormselects between them; both requestAccept-Encoding: gzip, since popular packuments are megabytes. - Scoped-name path encoding. A scoped name
@scope/nameis encoded on the wire as@scope%2Fname: the scope separator is percent-encoded but the leading@is not.metadataRequestbuilds this from an already-parsedPackageName, never from raw client path segments. - Streaming and buffering.
artifactRequestmarks its request non-decompressing (decompressreturnsFalse): a tarball is opaque binary that must reach the client byte-for-byte, so the.tgzis never gunzipped in flight (and itsdist.integritystays valid).
Synopsis
- data MetadataForm
- = Abbreviated
- | Full
- metadataAccept :: MetadataForm -> ByteString
- data Validators = Validators {}
- noValidators :: Validators
- metadataRequest :: Text -> Maybe Secret -> MetadataForm -> Validators -> PackageName -> Either UrlFormationError Request
- artifactRequest :: Text -> Maybe Secret -> PackageName -> Version -> Either UrlFormationError Request
- artifactRequestByFile :: Text -> Maybe Secret -> PackageName -> Text -> Either UrlFormationError Request
- artifactRequestByUrl :: Text -> Maybe Secret -> Text -> Either UrlFormationError Request
- artifactFileUrl :: Text -> PackageName -> Text -> Either UrlFormationError Text
- packageUrl :: Text -> PackageName -> Either UrlFormationError Text
- joinPath :: Text -> Text -> Either UrlFormationError Text
- encodePackagePath :: PackageName -> Text
- withToken :: Maybe Secret -> Request -> Request
- addValidators :: Validators -> Request -> Request
- parseRequestEither :: Text -> Either UrlFormationError Request
Content negotiation
data MetadataForm Source #
Which of npm's two metadata documents to request, selected by the Accept
header (see metadataAccept).
Constructors
| Abbreviated | The install-optimised abbreviated packument
( |
| Full | The full packument ( |
Instances
| Show MetadataForm Source # | |
Defined in Ecluse.Core.Registry.Npm.Request Methods showsPrec :: Int -> MetadataForm -> ShowS # show :: MetadataForm -> String # showList :: [MetadataForm] -> ShowS # | |
| Eq MetadataForm Source # | |
Defined in Ecluse.Core.Registry.Npm.Request | |
metadataAccept :: MetadataForm -> ByteString Source #
The Accept header value selecting a MetadataForm.
>>>metadataAccept Abbreviated"application/vnd.npm.install-v1+json"
>>>metadataAccept Full"application/json"
Conditional-GET validators
data Validators Source #
The conditional-GET validators to relay on a metadata fetch. Replaying an
upstream's ETag as If-None-Match (or its Last-Modified as
If-Modified-Since) lets the upstream answer 304 Not Modified with no body:
the cheap freshness check the proxy uses on a cache revalidation. Both are
forwarded only when present.
Constructors
| Validators | |
Fields
| |
Instances
| Show Validators Source # | |
Defined in Ecluse.Core.Registry.Npm.Request Methods showsPrec :: Int -> Validators -> ShowS # show :: Validators -> String # showList :: [Validators] -> ShowS # | |
| Eq Validators Source # | |
Defined in Ecluse.Core.Registry.Npm.Request | |
noValidators :: Validators Source #
No conditional-GET validators: an unconditional fetch.
Request building
metadataRequest :: Text -> Maybe Secret -> MetadataForm -> Validators -> PackageName -> Either UrlFormationError Request Source #
Build the metadata GET request for a package: the URL is
{baseUrl}/{encoded-name} with the Accept header for the chosen
MetadataForm, Accept-Encoding: gzip, an optional bearer token, and any
relayed conditional-GET Validators.
The package path is derived from an already-parsed PackageName, then the
scope separator is percent-encoded (@scope/name -> @scope%2Fname). Fails
with a UrlFormationError only when the URL cannot be formed (an empty base URL).
artifactRequest :: Text -> Maybe Secret -> PackageName -> Version -> Either UrlFormationError Request Source #
Build the artifact GET request for one version's tarball.
The request is marked non-decompressing (decompress returns False) so the
.tgz bytes are streamed through verbatim: a tarball is opaque binary and must
reach the client byte-for-byte for its dist.integrity to verify. The artifact
URL is the registry-served tarball location, derived like metadataRequest but
addressing the version's artifact path. Exposed so the web layer can bracket it
for bounded-memory streaming (see the module header).
Fails with a UrlFormationError only when the URL cannot be formed.
artifactRequestByFile :: Text -> Maybe Secret -> PackageName -> Text -> Either UrlFormationError Request Source #
Build the artifact GET request addressing a tarball by its __preserved
on-the-wire filename__, at {baseUrl}{encoded-pkg}-/{filename}.
The serve path fetches an artifact by the exact filename the client requested:
the authoritative name for the bytes: rather than reconstructing it from
(package, version) as artifactRequest does, so a registry whose tarball naming
differs from the proxy's own convention still resolves. The filename is taken
verbatim (the classifier has already passed it through the component-safety gate),
and the package segment is the same scope-percent-encoded path artifactRequest
uses. The request is marked non-decompressing for the same reason: a .tgz is
opaque binary streamed byte-for-byte so its dist.integrity verifies. Exposed so
the web layer can bracket it for bounded-memory streaming.
Fails with a UrlFormationError only when the URL cannot be formed.
artifactRequestByUrl :: Text -> Maybe Secret -> Text -> Either UrlFormationError Request Source #
Build the artifact GET request addressing a tarball at its __authoritative
upstream location__: the absolute url the projection preserved from the
upstream's dist.tarball: rather than reconstructing it from (base, package,
file).
The artifact location is server-chosen data, not a derivable fact: a registry may
serve a version's tarball from a different host or a path the npm - convention
cannot rebuild. Honouring the preserved location is what lets Écluse front those
registries; the URL it fetches is the same one the served packument's
dist.integrity is paired with, so the bytes still verify.
The request is marked non-decompressing for the same reason as artifactRequest:
a .tgz is opaque binary streamed byte-for-byte. Fails with a UrlFormationError
only when the url cannot be parsed into a request.
artifactFileUrl :: Text -> PackageName -> Text -> Either UrlFormationError Text Source #
The artifact (tarball) URL addressing a preserved filename:
{baseUrl}{encoded-name}-/{encoded-filename}. The filename is the exact
on-the-wire name (not {base}-{version}.tgz rebuilt from the coordinate), so the
bytes are fetched by the name the client requested; it is percent-encoded as a
single component (encodeComponent) so a once-decoded escape
in it cannot reach the upstream raw. Exposed so the serve path can record the
public artifact location on a mirror job (the same URL its public fetch targets).
Fails with a UrlFormationError only when the URL cannot be formed.
packageUrl :: Text -> PackageName -> Either UrlFormationError Text Source #
Shared internals
encodePackagePath :: PackageName -> Text Source #
addValidators :: Validators -> Request -> Request Source #