| Safe Haskell | None |
|---|---|
| Language | GHC2021 |
Ecluse.Core.Registry.Npm.Request
Description
Request shaping and URL building for the npm data plane. The ecosystem-agnostic mechanics (the redirect-pin finaliser, conditional-GET validators, URL parsing, the path join, the opaque-artifact request core) live in Ecluse.Core.Registry.Request; this module holds only npm's own protocol facts and composes them through that shared home.
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. The artifact builders (
artifactRequestByFile,artifactRequestByUrl) mark their request non-decompressing so a.tgzis opaque binary that reaches the client byte-for-byte (itsdist.integritystays valid);artifactRequestByUrlcomposes npm's bearer attach with the sharedartifactRequestByUrl.
Synopsis
- data MetadataForm
- = Abbreviated
- | Full
- metadataAccept :: MetadataForm -> ByteString
- data Validators = Validators {}
- noValidators :: Validators
- metadataRequest :: Text -> Maybe Secret -> MetadataForm -> Validators -> PackageName -> 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
- encodePackagePath :: PackageName -> Text
- withToken :: Maybe Secret -> 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 (re-exported from the shared request home)
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.Request Methods showsPrec :: Int -> Validators -> ShowS # show :: Validators -> String # showList :: [Validators] -> ShowS # | |
| Eq Validators Source # | |
Defined in Ecluse.Core.Registry.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).
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), 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 metadataRequest builds. The request is
marked non-decompressing: 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 npm's artifact GET request addressing a tarball at its __authoritative
upstream location__: the absolute url the projection preserved from the upstream's
dist.tarball. The baseUrl is ignored (the location is absolute); npm's bearer
credential is attached through the shared
artifactRequestByUrl, which marks the request
non-decompressing and pins the redirect count. See that symbol for the opaque-bytes
rationale.
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 #