-- SPDX-FileCopyrightText: 2026 Alexandra de Wit
--
-- SPDX-License-Identifier: MIT
-- TupleSections: local convenience for pairing a parsed capture with the remainder in
-- 'takeProject' and 'artifactCoordinate'. See docs/style.md §2.
{-# LANGUAGE TupleSections #-}

{- | The PyPI route table itself: the router, the table as data, the capture values, and the leaf
parsers. "Ecluse.Core.Registry.PyPI.Route" curates what a caller outside needs of it.

Importing this module opts out of the public surface's stability promises. It exists so a spec can
match one route or one parser on its own.
-}
module Ecluse.Core.Registry.PyPI.Route.Internal (
    -- * The mount's router
    pypiRouter,

    -- * The table, as data
    pypiRoutes,
    pypiRouteSpecs,

    -- * The served file URL (rendered from the route that claims it)
    distributionPath,

    -- * The capture values and leaf parsers
    PyPICap (..),
    takeProject,
    artifactCoordinate,
) where

import Data.List.NonEmpty qualified as NE
import Data.Text qualified as T
import Network.HTTP.Types (
    Method,
    ResponseHeaders,
    Status,
    status200,
    status304,
    status401,
    status403,
    status404,
    status405,
    status406,
    status500,
    status502,
    status503,
 )

import Ecluse.Core.Ecosystem (Ecosystem (PyPI))
import Ecluse.Core.Package (PackageName)
import Ecluse.Core.Registry.PyPI.Project (FileCoordinate (fcVersionKey), canonicalName, fileCoordinate, isCanonicalName, projectName)
import Ecluse.Core.Registry.PyPI.Wire (simpleIndexMediaType)
import Ecluse.Core.Server.Context (
    MountRouter,
    ResponseAction (AnswerRefusal),
    RouteAction (RouteAction),
 )
import Ecluse.Core.Server.Contract (
    BodySchema (SchemaDocumented, SchemaText),
    PassthroughBody (PassthroughBytes, PassthroughEmpty, PassthroughStream),
    PassthroughResponse,
    ResponseChoice (FirstResponse, SecondResponse),
    ResponseContract,
    ResponseValue,
    chooseContract,
    emptyContract,
    mediaContract,
    optionalBodyContract,
    passthroughContract,
    passthroughResponse,
    responseValue,
 )
import Ecluse.Core.Server.Path (Filename, mkFilename)
import Ecluse.Core.Server.Pipeline.Packument (PackumentReplies (..), packumentAction)
import Ecluse.Core.Server.Pipeline.Tarball (tarballAction)
import Ecluse.Core.Server.Pipeline.Tarball.Types (TarballReplies (..))
import Ecluse.Core.Server.Response (HelpMessage, Refusal, mkRefusal, refusalHelp)
import Ecluse.Core.Server.Route (
    Capture (Capture),
    MediaNegotiation (AcceptsAnything, AcceptsOnly),
    MethodMatch (MethodPost, MethodRead),
    PatternSeg (SegCap, SegLit),
    Route (Route),
    RouteName (RouteName),
    refusing,
    renderRoute,
    routerOf,
    safeSegment,
 )
import Ecluse.Core.Server.RouteDescription (RouteSpec, catchAllSpecs, specsOf, unsupportedPathParam)
import Ecluse.Core.Version (Version, mkVersion)

-- | Match the first applicable route, otherwise answer with the 404 fallback.
pypiRouter :: MountRouter
pypiRouter :: MountRouter
pypiRouter = RouteAction -> [Route PyPICap] -> MountRouter
forall v. RouteAction -> [Route v] -> MountRouter
routerOf RouteAction
pypiNotFound [Route PyPICap]
pypiRoutes

-- Refuse unmatched paths with 404.
pypiNotFound :: RouteAction
pypiNotFound :: RouteAction
pypiNotFound = ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseAction (ResponseValue (Maybe LByteString))
-> RouteAction
forall response.
ResponseContract response -> ResponseAction response -> RouteAction
RouteAction ResponseContract (ResponseValue (Maybe LByteString))
unsupportedContract ((Maybe HelpMessage -> ResponseValue (Maybe LByteString))
-> ResponseAction (ResponseValue (Maybe LByteString))
forall response.
(Maybe HelpMessage -> response) -> ResponseAction response
AnswerRefusal (Text
-> ResponseHeaders
-> Maybe HelpMessage
-> ResponseValue (Maybe LByteString)
declaredRefusal Text
"no route claims this path" []))

-- | PyPI's routes, in matching order.
pypiRoutes :: [Route PyPICap]
pypiRoutes :: [Route PyPICap]
pypiRoutes =
    [ Route PyPICap
artifactRoute
    , Route PyPICap
simpleIndexRoute
    , Route PyPICap
uploadRoute
    ]

-- @GET \/simple\/{project}\/{file}@: a distribution file, streamed.
artifactRoute :: Route PyPICap
artifactRoute :: Route PyPICap
artifactRoute =
    RouteName
-> MethodMatch
-> MediaNegotiation PassthroughResponse
-> [PatternSeg PyPICap]
-> (ByteString
    -> [PyPICap] -> Maybe (ResponseAction PassthroughResponse))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract PassthroughResponse
-> Route PyPICap
forall v response.
RouteName
-> MethodMatch
-> MediaNegotiation response
-> [PatternSeg v]
-> (ByteString -> [v] -> Maybe (ResponseAction response))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract response
-> Route v
Route
        (Text -> RouteName
RouteName Text
"distribution")
        MethodMatch
MethodRead
        MediaNegotiation PassthroughResponse
forall response. MediaNegotiation response
AcceptsAnything
        [Text -> PatternSeg PyPICap
forall v. Text -> PatternSeg v
SegLit Text
"simple", Capture PyPICap -> PatternSeg PyPICap
forall v. Capture v -> PatternSeg v
SegCap Capture PyPICap
capProject, Capture PyPICap -> PatternSeg PyPICap
forall v. Capture v -> PatternSeg v
SegCap Capture PyPICap
capFile]
        ByteString
-> [PyPICap] -> Maybe (ResponseAction PassthroughResponse)
buildArtifact
        Text
"Stream a distribution file (wheel or sdist)"
        Text
"The file's bytes are streamed verbatim with bounded memory, so the client verifies them \
        \against the `sha256` the served index advertised. `/simple/{project}/{file}` is the one \
        \spelling every rewritten file URL agrees with. Upstream statuses, headers, and media \
        \types are relayed transparently; a locally generated refusal is a bare status."
        Maybe RequestSpec
forall a. Maybe a
Nothing
        ResponseContract PassthroughResponse
pypiArtifactContract

-- @GET \/simple\/{project}@: the filtered PEP 691 JSON index.
simpleIndexRoute :: Route PyPICap
simpleIndexRoute :: Route PyPICap
simpleIndexRoute =
    RouteName
-> MethodMatch
-> MediaNegotiation PyPIIndexResponse
-> [PatternSeg PyPICap]
-> (ByteString
    -> [PyPICap] -> Maybe (ResponseAction PyPIIndexResponse))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract PyPIIndexResponse
-> Route PyPICap
forall v response.
RouteName
-> MethodMatch
-> MediaNegotiation response
-> [PatternSeg v]
-> (ByteString -> [v] -> Maybe (ResponseAction response))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract response
-> Route v
Route
        (Text -> RouteName
RouteName Text
"simpleIndex")
        MethodMatch
MethodRead
        (NonEmpty ByteString
-> (Maybe HelpMessage -> PyPIIndexResponse)
-> MediaNegotiation PyPIIndexResponse
forall response.
NonEmpty ByteString
-> (Maybe HelpMessage -> response) -> MediaNegotiation response
AcceptsOnly (ByteString
simpleIndexMediaType ByteString -> [ByteString] -> NonEmpty ByteString
forall a. a -> [a] -> NonEmpty a
:| []) (ResponseHeaders -> Maybe HelpMessage -> PyPIIndexResponse
notAcceptable []))
        [Text -> PatternSeg PyPICap
forall v. Text -> PatternSeg v
SegLit Text
"simple", Capture PyPICap -> PatternSeg PyPICap
forall v. Capture v -> PatternSeg v
SegCap Capture PyPICap
capProject]
        ByteString -> [PyPICap] -> Maybe (ResponseAction PyPIIndexResponse)
buildIndex
        Text
"Fetch a project's Simple index"
        Text
"Returns Écluse's merged-and-filtered PEP 691 JSON index: files merged across upstreams \
        \and gated, each file URL rewritten to resolve back through this proxy. \
        \`/simple/{project}/` and `/simple/{project}` both match, because the router strips a \
        \trailing empty segment. A non-canonical (non-PEP-503) project name matches no route and \
        \takes the `404`, with no redirect. A client that requires HTML and admits no JSON gets \
        \`406`: Écluse serves the JSON form alone."
        Maybe RequestSpec
forall a. Maybe a
Nothing
        ResponseContract PyPIIndexResponse
pypiIndexContract

-- @POST \/legacy@: the documented upload refusal.
uploadRoute :: Route PyPICap
uploadRoute :: Route PyPICap
uploadRoute =
    RouteName
-> MethodMatch
-> MediaNegotiation (ResponseValue (Maybe LByteString))
-> [PatternSeg PyPICap]
-> (ByteString
    -> [PyPICap]
    -> Maybe (ResponseAction (ResponseValue (Maybe LByteString))))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract (ResponseValue (Maybe LByteString))
-> Route PyPICap
forall v response.
RouteName
-> MethodMatch
-> MediaNegotiation response
-> [PatternSeg v]
-> (ByteString -> [v] -> Maybe (ResponseAction response))
-> Text
-> Text
-> Maybe RequestSpec
-> ResponseContract response
-> Route v
Route
        (Text -> RouteName
RouteName Text
"upload")
        MethodMatch
MethodPost
        MediaNegotiation (ResponseValue (Maybe LByteString))
forall response. MediaNegotiation response
AcceptsAnything
        [Text -> PatternSeg PyPICap
forall v. Text -> PatternSeg v
SegLit Text
"legacy"]
        ((Maybe HelpMessage -> ResponseValue (Maybe LByteString))
-> ByteString
-> [PyPICap]
-> Maybe (ResponseAction (ResponseValue (Maybe LByteString)))
forall response v.
(Maybe HelpMessage -> response)
-> ByteString -> [v] -> Maybe (ResponseAction response)
refusing (Text
-> ResponseHeaders
-> Maybe HelpMessage
-> ResponseValue (Maybe LByteString)
declaredRefusal Text
"publishing is not enabled on this mount" []))
        Text
"Upload a first-party distribution (not supported)"
        Text
"A PyPI mount registers no publish capability, so an upload is answered `405` rather \
        \than relayed. The route is declared so the refusal is the documented one rather than \
        \the deny-by-default `404` an unrouted path takes."
        Maybe RequestSpec
forall a. Maybe a
Nothing
        ResponseContract (ResponseValue (Maybe LByteString))
pypiUploadContract

-- The named hand-authored schema the manifest holds for the index Écluse assembles.
simpleIndexSchema :: Text
simpleIndexSchema :: Text
simpleIndexSchema = Text
"PyPISimpleIndex"

-- The closed Simple-index response sum: every status the index route may answer.
type PyPIIndexResponse =
    ResponseChoice
        (ResponseValue LByteString)
        ( ResponseChoice
            (ResponseValue ())
            ( ResponseChoice
                (ResponseValue (Maybe LByteString))
                ( ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    ( ResponseChoice
                        (ResponseValue (Maybe LByteString))
                        ( ResponseChoice
                            (ResponseValue (Maybe LByteString))
                            ( ResponseChoice
                                (ResponseValue (Maybe LByteString))
                                (ResponseChoice (ResponseValue (Maybe LByteString)) (ResponseValue (Maybe LByteString)))
                            )
                        )
                    )
                )
            )
        )

pypiIndexContract :: ResponseContract PyPIIndexResponse
pypiIndexContract :: ResponseContract PyPIIndexResponse
pypiIndexContract =
    ResponseContract (ResponseValue LByteString)
-> ResponseContract
     (ResponseChoice
        (ResponseValue ())
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseChoice
                          (ResponseValue (Maybe LByteString))
                          (ResponseValue (Maybe LByteString)))))))))
-> ResponseContract PyPIIndexResponse
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
        (Status
-> Text
-> BodySchema
-> ResponseContract (ResponseValue LByteString)
mediaContract Status
status200 Text
"The filtered Simple index." (ByteString -> Text -> BodySchema
SchemaDocumented ByteString
simpleIndexMediaType Text
simpleIndexSchema))
        ( ResponseContract (ResponseValue ())
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
-> ResponseContract
     (ResponseChoice
        (ResponseValue ())
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseChoice
                          (ResponseValue (Maybe LByteString))
                          (ResponseValue (Maybe LByteString)))))))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
            (Status -> Text -> ResponseContract (ResponseValue ())
emptyContract Status
status304 Text
"The client's validator matched the assembled index.")
            ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status401 Text
"Edge authentication failed.")
                ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                    (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status403 Text
"Private access was refused, or no release survived policy and admission.")
                    ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                        (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status404 Text
"A first-party project the private upstream does not have. It is never fetched from the public upstream.")
                        ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                            (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status406 Text
"The request requires a representation this index does not serve; only the PEP 691 JSON form exists.")
                            ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString)))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                                (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status500 Text
"A permanent or internal inability to decide.")
                                ( ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract (ResponseValue (Maybe LByteString))
-> ResponseContract
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString)))
forall a b.
ResponseContract a
-> ResponseContract b -> ResponseContract (ResponseChoice a b)
chooseContract
                                    (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status502 Text
"A responding upstream returned an index for a different project.")
                                    (Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status503 Text
"A transient upstream or advisory condition; retry (see `Retry-After`).")
                                )
                            )
                        )
                    )
                )
            )
        )

-- A refusal has no body unless operator help text is configured.
refusalContract :: Status -> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract :: Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status Text
description =
    Status
-> Text
-> BodySchema
-> ResponseContract (ResponseValue (Maybe LByteString))
optionalBodyContract Status
status (Text
description Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" The body is empty unless `server.helpMessage` is configured.") (ByteString -> BodySchema
SchemaText ByteString
"text/plain")

pypiIndexReplies :: PackumentReplies PyPIIndexResponse
pypiIndexReplies :: PackumentReplies PyPIIndexResponse
pypiIndexReplies =
    PackumentReplies
        { packumentOk :: ResponseHeaders -> LByteString -> PyPIIndexResponse
packumentOk = \ResponseHeaders
headers LByteString
body -> ResponseValue LByteString -> PyPIIndexResponse
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> LByteString -> ResponseValue LByteString
forall a. ResponseHeaders -> a -> ResponseValue a
responseValue ResponseHeaders
headers LByteString
body)
        , packumentNotModified :: ResponseHeaders -> PyPIIndexResponse
packumentNotModified = \ResponseHeaders
headers -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue ()
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> () -> ResponseValue ()
forall a. ResponseHeaders -> a -> ResponseValue a
responseValue ResponseHeaders
headers ()))
        , packumentUnauthorised :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentUnauthorised = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal)))
        , packumentForbidden :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentForbidden = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal))))
        , packumentNotFound :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentNotFound = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString)))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal)))))
        , packumentInternal :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentInternal = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString)))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseValue (Maybe LByteString)))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString)))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal)))))))
        , packumentBadGateway :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentBadGateway = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString)))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseValue (Maybe LByteString)))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseValue (Maybe LByteString))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString)))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseValue (Maybe LByteString))
forall a b. a -> ResponseChoice a b
FirstResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal))))))))
        , packumentUnavailable :: ResponseHeaders -> Refusal -> PyPIIndexResponse
packumentUnavailable = \ResponseHeaders
headers Refusal
refusal -> ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString)))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseValue (Maybe LByteString)))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseValue (Maybe LByteString))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString)))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseValue (Maybe LByteString))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal))))))))
        }

-- The @406@ arm, which the router selects before any handler runs.
notAcceptable :: ResponseHeaders -> Maybe HelpMessage -> PyPIIndexResponse
notAcceptable :: ResponseHeaders -> Maybe HelpMessage -> PyPIIndexResponse
notAcceptable ResponseHeaders
headers Maybe HelpMessage
help =
    ResponseChoice
  (ResponseValue ())
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString))))))))
-> PyPIIndexResponse
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString)))))))
-> ResponseChoice
     (ResponseValue ())
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseChoice
                       (ResponseValue (Maybe LByteString))
                       (ResponseValue (Maybe LByteString))))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString))))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseChoice
                    (ResponseValue (Maybe LByteString))
                    (ResponseValue (Maybe LByteString)))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString)))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseChoice
                 (ResponseValue (Maybe LByteString))
                 (ResponseValue (Maybe LByteString))))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseChoice
  (ResponseValue (Maybe LByteString))
  (ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseValue (Maybe LByteString))))
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseChoice
              (ResponseValue (Maybe LByteString))
              (ResponseValue (Maybe LByteString)))))
forall a b. b -> ResponseChoice a b
SecondResponse (ResponseValue (Maybe LByteString)
-> ResponseChoice
     (ResponseValue (Maybe LByteString))
     (ResponseChoice
        (ResponseValue (Maybe LByteString))
        (ResponseChoice
           (ResponseValue (Maybe LByteString))
           (ResponseValue (Maybe LByteString))))
forall a b. a -> ResponseChoice a b
FirstResponse (Text
-> ResponseHeaders
-> Maybe HelpMessage
-> ResponseValue (Maybe LByteString)
declaredRefusal Text
"no representation this index serves is acceptable" ResponseHeaders
headers Maybe HelpMessage
help))))))

-- Upstream-controlled artifact responses and local refusals share one open response contract.
pypiArtifactContract :: ResponseContract PassthroughResponse
pypiArtifactContract :: ResponseContract PassthroughResponse
pypiArtifactContract =
    Text -> ResponseContract PassthroughResponse
passthroughContract
        Text
"An upstream-controlled distribution response is relayed transparently. Local authentication, policy, availability, and internal failures answer a bare status under their own code."

pypiArtifactReplies :: TarballReplies PassthroughResponse
pypiArtifactReplies :: TarballReplies PassthroughResponse
pypiArtifactReplies =
    TarballReplies
        { tarballError :: Status -> ResponseHeaders -> Refusal -> PassthroughResponse
tarballError = \Status
status ResponseHeaders
headers Refusal
refusal -> Status -> ResponseHeaders -> PassthroughBody -> PassthroughResponse
passthroughResponse Status
status ResponseHeaders
headers (Refusal -> PassthroughBody
artifactRefusalBody Refusal
refusal)
        , tarballStream :: Status -> ResponseHeaders -> StreamingBody -> PassthroughResponse
tarballStream = \Status
status ResponseHeaders
headers StreamingBody
body -> Status -> ResponseHeaders -> PassthroughBody -> PassthroughResponse
passthroughResponse Status
status ResponseHeaders
headers (StreamingBody -> PassthroughBody
PassthroughStream StreamingBody
body)
        , tarballEmpty :: Status -> ResponseHeaders -> PassthroughResponse
tarballEmpty = \Status
status ResponseHeaders
headers -> Status -> ResponseHeaders -> PassthroughBody -> PassthroughResponse
passthroughResponse Status
status ResponseHeaders
headers PassthroughBody
PassthroughEmpty
        }

pypiUploadContract :: ResponseContract (ResponseValue (Maybe LByteString))
pypiUploadContract :: ResponseContract (ResponseValue (Maybe LByteString))
pypiUploadContract = Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status405 Text
"Publishing is not enabled on this mount."

unsupportedContract :: ResponseContract (ResponseValue (Maybe LByteString))
unsupportedContract :: ResponseContract (ResponseValue (Maybe LByteString))
unsupportedContract = Status
-> Text -> ResponseContract (ResponseValue (Maybe LByteString))
refusalContract Status
status404 Text
"Unrecognised path; deny by default."

-- Écluse's own wording stays off the wire: PyPI's refusal is a bare status, so the body is the
-- operator help message alone and nothing at all when none is configured.
helpBody :: ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody :: ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers Refusal
refusal = ResponseHeaders
-> Maybe LByteString -> ResponseValue (Maybe LByteString)
forall a. ResponseHeaders -> a -> ResponseValue a
responseValue ResponseHeaders
headers (Refusal -> Maybe LByteString
helpBytes Refusal
refusal)

{- The body of a refusal the route table decides rather than the pipeline, rendered through
'helpBody' too so a configured help message reaches every arm alike. -}
declaredRefusal :: Text -> ResponseHeaders -> Maybe HelpMessage -> ResponseValue (Maybe LByteString)
declaredRefusal :: Text
-> ResponseHeaders
-> Maybe HelpMessage
-> ResponseValue (Maybe LByteString)
declaredRefusal Text
reason ResponseHeaders
headers Maybe HelpMessage
help = ResponseHeaders -> Refusal -> ResponseValue (Maybe LByteString)
helpBody ResponseHeaders
headers (Maybe HelpMessage -> Text -> Refusal
mkRefusal Maybe HelpMessage
help Text
reason)

-- The artifact relay's refusal, which is the same body under the transparent-relay contract.
artifactRefusalBody :: Refusal -> PassthroughBody
artifactRefusalBody :: Refusal -> PassthroughBody
artifactRefusalBody Refusal
refusal = PassthroughBody
-> (LByteString -> PassthroughBody)
-> Maybe LByteString
-> PassthroughBody
forall b a. b -> (a -> b) -> Maybe a -> b
maybe PassthroughBody
PassthroughEmpty LByteString -> PassthroughBody
PassthroughBytes (Refusal -> Maybe LByteString
helpBytes Refusal
refusal)

-- The operator help message as body bytes, absent when none is configured.
helpBytes :: Refusal -> Maybe LByteString
helpBytes :: Refusal -> Maybe LByteString
helpBytes = (Text -> LByteString) -> Maybe Text -> Maybe LByteString
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (ByteString -> LByteString
forall l s. LazyStrict l s => s -> l
fromStrict (ByteString -> LByteString)
-> (Text -> ByteString) -> Text -> LByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Text -> ByteString
forall a b. ConvertUtf8 a b => a -> b
encodeUtf8) (Maybe Text -> Maybe LByteString)
-> (Refusal -> Maybe Text) -> Refusal -> Maybe LByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Refusal -> Maybe Text
refusalHelp

-- @GET \/simple\/{project}@: a project unit is an index read.
buildIndex :: Method -> [PyPICap] -> Maybe (ResponseAction PyPIIndexResponse)
buildIndex :: ByteString -> [PyPICap] -> Maybe (ResponseAction PyPIIndexResponse)
buildIndex ByteString
method = \case
    [PyPIProject PackageName
name] -> ResponseAction PyPIIndexResponse
-> Maybe (ResponseAction PyPIIndexResponse)
forall a. a -> Maybe a
Just (PackumentReplies PyPIIndexResponse
-> ByteString -> PackageName -> ResponseAction PyPIIndexResponse
forall response.
PackumentReplies response
-> ByteString -> PackageName -> ResponseAction response
packumentAction PackumentReplies PyPIIndexResponse
pypiIndexReplies ByteString
method PackageName
name)
    [PyPICap]
_ -> Maybe (ResponseAction PyPIIndexResponse)
forall a. Maybe a
Nothing

-- 'artifactCoordinate' applies the cross-capture path-confusion check, so a file naming another
-- project falls through to the @404@ rather than having a coordinate fabricated for it.
buildArtifact :: Method -> [PyPICap] -> Maybe (ResponseAction PassthroughResponse)
buildArtifact :: ByteString
-> [PyPICap] -> Maybe (ResponseAction PassthroughResponse)
buildArtifact ByteString
method = \case
    [PyPIProject PackageName
name, PyPIFile Text
file] -> do
        (version, filename) <- PackageName -> Text -> Maybe (Version, Filename)
artifactCoordinate PackageName
name Text
file
        pure (tarballAction pypiArtifactReplies method name version filename)
    [PyPICap]
_ -> Maybe (ResponseAction PassthroughResponse)
forall a. Maybe a
Nothing

-- | Positional captures distinguish parsed projects from checked distribution filenames.
data PyPICap
    = PyPIProject PackageName
    | PyPIFile Text

-- Render project captures canonically so the parser can read them back.
renderCapture :: PyPICap -> [Text]
renderCapture :: PyPICap -> [Text]
renderCapture = \case
    PyPIProject PackageName
name -> [PackageName -> Text
canonicalName PackageName
name]
    PyPIFile Text
file -> [Text
file]

-- Accept canonical projects only. Non-canonical spellings receive 404 rather than redirects.
capProject :: Capture PyPICap
capProject :: Capture PyPICap
capProject =
    Text
-> Text
-> ([Text] -> Maybe (PyPICap, [Text]))
-> (PyPICap -> [Text])
-> Capture PyPICap
forall v.
Text
-> Text
-> ([Text] -> Maybe (v, [Text]))
-> (v -> [Text])
-> Capture v
Capture
        Text
"project"
        Text
"The project name in PEP 503 canonical form, e.g. `zope-interface`."
        (((PackageName, [Text]) -> (PyPICap, [Text]))
-> Maybe (PackageName, [Text]) -> Maybe (PyPICap, [Text])
forall a b. (a -> b) -> Maybe a -> Maybe b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((PackageName -> PyPICap)
-> (PackageName, [Text]) -> (PyPICap, [Text])
forall a b c. (a -> b) -> (a, c) -> (b, c)
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first PackageName -> PyPICap
PyPIProject) (Maybe (PackageName, [Text]) -> Maybe (PyPICap, [Text]))
-> ([Text] -> Maybe (PackageName, [Text]))
-> [Text]
-> Maybe (PyPICap, [Text])
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Text] -> Maybe (PackageName, [Text])
takeProject)
        PyPICap -> [Text]
renderCapture

-- The segment is checked here; 'artifactCoordinate' reads the release and archive form from it.
capFile :: Capture PyPICap
capFile :: Capture PyPICap
capFile =
    Text
-> Text
-> ([Text] -> Maybe (PyPICap, [Text]))
-> (PyPICap -> [Text])
-> Capture PyPICap
forall v.
Text
-> Text
-> ([Text] -> Maybe (v, [Text]))
-> (v -> [Text])
-> Capture v
Capture
        Text
"file"
        Text
"The distribution file's on-the-wire name, e.g. `requests-2.34.2-py3-none-any.whl`."
        ((Text -> PyPICap) -> [Text] -> Maybe (PyPICap, [Text])
forall v. (Text -> v) -> [Text] -> Maybe (v, [Text])
safeSegment Text -> PyPICap
PyPIFile)
        PyPICap -> [Text]
renderCapture

-- | Reject project spellings that an index would redirect outside the matched route.
takeProject :: [Text] -> Maybe (PackageName, [Text])
takeProject :: [Text] -> Maybe (PackageName, [Text])
takeProject = \case
    Text
seg : [Text]
rest | Text -> Bool
isCanonicalName Text
seg -> (,[Text]
rest) (PackageName -> (PackageName, [Text]))
-> Maybe PackageName -> Maybe (PackageName, [Text])
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Either ParseError PackageName -> Maybe PackageName
forall l r. Either l r -> Maybe r
rightToMaybe (Text -> Either ParseError PackageName
projectName Text
seg)
    [Text]
_ -> Maybe (PackageName, [Text])
forall a. Maybe a
Nothing

-- | Require the file's project identity to match the requested package.
artifactCoordinate :: PackageName -> Text -> Maybe (Version, Filename)
artifactCoordinate :: PackageName -> Text -> Maybe (Version, Filename)
artifactCoordinate PackageName
name Text
file = do
    coordinate <- PackageName -> Text -> Maybe FileCoordinate
fileCoordinate PackageName
name Text
file
    (mkVersion PyPI (fcVersionKey coordinate),) <$> mkFilename file

-- | Render through the distribution route so generated URLs obey its capture rules.
distributionPath :: PackageName -> Text -> Maybe Text
distributionPath :: PackageName -> Text -> Maybe Text
distributionPath PackageName
name Text
file = Text -> [Text] -> Text
T.intercalate Text
"/" ([Text] -> Text) -> Maybe [Text] -> Maybe Text
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> Route PyPICap -> [PyPICap] -> Maybe [Text]
forall v. Route v -> [v] -> Maybe [Text]
renderRoute Route PyPICap
artifactRoute [PackageName -> PyPICap
PyPIProject PackageName
name, Text -> PyPICap
PyPIFile Text
file]

-- | Describe the live router and its deny-by-default catch-all for OpenAPI.
pypiRouteSpecs :: NonEmpty RouteSpec
pypiRouteSpecs :: NonEmpty RouteSpec
pypiRouteSpecs =
    ResponseContract (ResponseValue (Maybe LByteString))
-> ParamSpec -> NonEmpty RouteSpec
forall r. ResponseContract r -> ParamSpec -> NonEmpty RouteSpec
catchAllSpecs ResponseContract (ResponseValue (Maybe LByteString))
unsupportedContract ParamSpec
unsupportedPathParam
        NonEmpty RouteSpec -> [RouteSpec] -> NonEmpty RouteSpec
forall a. NonEmpty a -> [a] -> NonEmpty a
`NE.appendList` (Route PyPICap -> [RouteSpec]) -> [Route PyPICap] -> [RouteSpec]
forall (t :: * -> *) a b. Foldable t => (a -> [b]) -> t a -> [b]
concatMap Route PyPICap -> [RouteSpec]
forall v. Route v -> [RouteSpec]
specsOf [Route PyPICap]
pypiRoutes