Documentation
¶
Overview ¶
Package httpclient bounds an API client's requests to its configured origin and owns the URL shapes adapters use to configure and address an API: base URLs, origins, and path segments.
Example ¶
package main
import (
"context"
"errors"
"fmt"
"net/http"
"github.com/Tangerg/scope/core/httpclient"
)
func main() {
ctx := context.Background()
host := &http.Client{}
client, err := httpclient.New(ctx, httpclient.Config{
HTTPClient: host,
BaseURL: "https://api.example/v1",
})
if err != nil {
panic(err)
}
redirect, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.example:9443/result", nil)
if err != nil {
panic(err)
}
err = client.CheckRedirect(redirect, nil)
fmt.Println("independent client:", client != host)
fmt.Println("host transport unchanged:", host.Transport == nil)
fmt.Println("other port rejected:", errors.Is(err, httpclient.ErrOriginNotAllowed))
}
Output: independent client: true host transport unchanged: true other port rejected: true
Index ¶
- Constants
- Variables
- func New(_ context.Context, config Config) (*http.Client, error)
- func NewDeliveryClient(config DeliveryConfig) (*http.Client, error)
- func ParseBaseURL(raw string) (*url.URL, error)
- func PathSegment(value string) string
- func Restrict(client *http.Client, allowed Origins) (*http.Client, error)
- type Config
- type DeliveryConfig
- type Destination
- type Origin
- type Origins
- type ResponseBodyLimit
- func (r ResponseBodyLimit) Apply(request *http.Request, next func(*http.Request) (*http.Response, error)) (*http.Response, error)
- func (r ResponseBodyLimit) ApplyErrors(request *http.Request, next func(*http.Request) (*http.Response, error)) (*http.Response, error)
- func (r ResponseBodyLimit) ApplyEventStream(request *http.Request, next func(*http.Request) (*http.Response, error)) (*http.Response, error)
- type ResponseBudget
- type ResponseError
Examples ¶
Constants ¶
const DefaultMaxJSONResponseBytes = 32 << 20
Variables ¶
var ErrOriginNotAllowed = errors.New("httpclient: request origin is not authorized")
ErrOriginNotAllowed prevents an API credential or request body from reaching an origin other than the one configured by its owner.
Functions ¶
func New ¶
New copies the client value before applying origin restrictions, so SDK initialization and redirect policy changes cannot mutate the host's client. The host retains ownership of the shared transport and cookie jar. Its redirect policy runs before the final destination and authority checks.
func NewDeliveryClient ¶ added in v0.62.0
func NewDeliveryClient(config DeliveryConfig) (*http.Client, error)
NewDeliveryClient returns a copy of the configured client that sends no cookie jar, never follows a redirect from HTTPS to HTTP, reaches only the Destination, and strips credentials outside CredentialOrigin.
func ParseBaseURL ¶ added in v0.62.0
ParseBaseURL admits a configured API base URL: an absolute HTTP(S) URL with a host and an optional base path. User information would carry a credential the binding does not own, and a query or fragment cannot prefix the resource paths appended to it. The raw text is checked because url.URL drops an empty fragment.
func PathSegment ¶ added in v0.62.0
PathSegment encodes value as exactly one URL path segment. Escaping alone leaves "." and ".." literal, and reference resolution would then drop the segment or climb to its parent, so their dots are percent-encoded too. An empty value encodes to an empty segment; callers own presence validation.
Types ¶
type Config ¶
type Config struct {
// A nil Transport, including a typed nil, uses http.DefaultTransport.
HTTPClient *http.Client
BaseURL string
// RejectRedirects binds resource-scoped requests to the original URL, even
// when a same-origin server redirects to a different tenant or resource.
RejectRedirects bool
}
type DeliveryConfig ¶ added in v0.62.0
type DeliveryConfig struct {
HTTPClient *http.Client
// Destination authorizes every request and every redirect.
Destination Destination
// CredentialOrigin is the one origin that may still receive credentials,
// such as an API that serves its own files; the zero value strips them
// from every request.
CredentialOrigin Origin
// CredentialHeaders names provider credentials removed alongside
// Authorization, Proxy-Authorization, and Cookie.
CredentialHeaders []string
}
DeliveryConfig restricts a client that follows provider-issued output URLs. Such a URL is data, not a grant of the host's network or credentials.
type Destination ¶ added in v0.62.0
Destination authorizes the target of one request, including the authority written to the wire. Origins is the fixed-set Destination; a provider whose output hosts follow a rule supplies its own.
type Origin ¶
type Origin struct {
// contains filtered or unexported fields
}
Origin is an immutable HTTP origin. Only hierarchical URLs are admitted, so Opaque cannot replace the checked authority on the wire. Equality includes the scheme, host, and effective port; its zero value authorizes no requests.
func NewOrigin ¶
NewOrigin takes the origin of an absolute, hierarchical HTTP(S) URL. Its path, query, and fragment name a resource and do not affect the origin.
func ParseOrigin ¶ added in v0.62.0
ParseOrigin admits a configured origin: a base URL with no path beyond "/", so a value that names a resource cannot be mistaken for the authority it grants.
type Origins ¶ added in v0.62.0
type Origins []Origin
Origins is a set of authorized origins. A request is authorized when its destination, including the authority written to the wire, is one of them.
type ResponseBodyLimit ¶ added in v0.61.0
type ResponseBodyLimit int64
ResponseBodyLimit admits bytes as they are read, before a decoder can allocate for an untrusted response. The HTTP client still owns retries and body closure.
func (ResponseBodyLimit) ApplyErrors ¶ added in v0.61.0
func (r ResponseBodyLimit) ApplyErrors(request *http.Request, next func(*http.Request) (*http.Response, error)) (*http.Response, error)
Successful streaming bodies have a per-event contract, so their error envelopes must be bounded without imposing a limit on the entire stream.
func (ResponseBodyLimit) ApplyEventStream ¶ added in v0.61.0
func (r ResponseBodyLimit) ApplyEventStream(request *http.Request, next func(*http.Request) (*http.Response, error)) (*http.Response, error)
For SDKs with LF/CRLF SSE framing, each wire event has its own budget, including comments, BOM, and delimiters. Empty lines reset admission, so long-lived streams retain backpressure without a total byte ceiling. This wrapper preserves bytes; the SDK remains responsible for interpreting them.
type ResponseBudget ¶ added in v0.62.0
type ResponseBudget struct {
// contains filtered or unexported fields
}
ResponseBudget is one aggregate byte grant shared by every response of an operation, such as the pages of a listing, so a scan that follows a server's pagination cannot read more in total than its caller granted. Each body is read in full against what remains; a successful body must be one JSON value. It is not safe for concurrent use.
func NewResponseBudget ¶ added in v0.62.0
func NewResponseBudget(maxBytes int64) (*ResponseBudget, error)
type ResponseError ¶ added in v0.60.0
type ResponseError struct {
// contains filtered or unexported fields
}
ResponseError exposes transport evidence without turning a remote response body into public diagnostics. It makes no claim about provider execution.
func NewResponseError ¶ added in v0.60.0
func NewResponseError(statusCode int, header http.Header) *ResponseError
func (*ResponseError) Error ¶ added in v0.60.0
func (r *ResponseError) Error() string
func (*ResponseError) HTTPStatus ¶ added in v0.60.0
func (r *ResponseError) HTTPStatus() int
func (*ResponseError) RequestID ¶ added in v0.60.0
func (r *ResponseError) RequestID() string