Documentation
¶
Overview ¶
Package http is a pure-Go (CGO-free) reimplementation of the deterministic core of Ruby's `http` gem — the chainable "http.rb" HTTP client (HTTP.get/post/…), NOT Ruby's stdlib net/http. It reproduces the chainable client DSL, the request/response objects, the status/headers/content-type/ cookie value model, the form/JSON/params body encodings, redirect following, and the HTTP::Error tree that http.rb raises — without any Ruby runtime.
What it is — and isn't ¶
Everything http.rb does *around* the wire is deterministic and needs no interpreter, so it lives here as pure Go: branching the chainable client (headers/auth/basic_auth/accept/timeout/follow/via/persistent), building the request (URL, merged headers, form/JSON/raw/params body encoding), following redirects, and exposing the Response (status predicates, headers, content-type, JSON parse, cookies). The HTTP round-trip itself is a host seam: the Transport performs the transport. The default production Transport is NetTransport, backed by net/http; tests inject a TransportFunc stub, and the core opens no socket itself.
Flow ¶
resp, err := http.NewClient().
Headers(http.KV{Key: "X-Trace", Val: "1"}).
Auth("Bearer tok").
Accept("json").
Timeout(30).
Follow().
Get("https://api.example.com/widgets")
if err != nil { /* an *http.Error: TimeoutError, ConnectionError, … */ }
_ = resp.Status().Success() // true for 2xx
_ = resp.Body().String() // raw body
v, _ := resp.Parse() // parsed JSON (by Content-Type)
A POST with a body encoding:
resp, err := http.Post("https://api.example.com/widgets",
http.JSON(map[string]any{"name": "gadget"}))
Value model ¶
A host (go-embedded-ruby / rbgo) maps its Ruby HTTP::Client / HTTP::Request / HTTP::Response / HTTP::Headers / HTTP::Response::Status objects to and from these Go shapes, and supplies the production Transport.
Index ¶
- Constants
- Variables
- func BasicAuthHeader(user, pass string) string
- func EscapeFormComponent(s string) string
- func NormalizeHeaderName(name string) string
- func Persistent(host string, block func(*Client) error) error
- type Client
- func Accept(typ string) *Client
- func Auth(value string) *Client
- func BasicAuth(user, pass string) *Client
- func Cookies(kv ...KV) *Client
- func Encoding(enc string) *Client
- func Follow(opts ...FollowOptions) *Client
- func Header(key, val string) *Client
- func NewClient() *Client
- func Nodelay() *Client
- func Through(host string, port int, userpass ...string) *Client
- func Timeout(seconds int) *Client
- func Use(features ...string) *Client
- func Via(host string, port int, userpass ...string) *Client
- func (c *Client) Accept(typ string) *Client
- func (c *Client) Auth(value string) *Client
- func (c *Client) BasicAuth(user, pass string) *Client
- func (c *Client) Connect(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Cookies(kv ...KV) *Client
- func (c *Client) DefaultOptions() *Options
- func (c *Client) Delete(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Encoding(enc string) *Client
- func (c *Client) Follow(opts ...FollowOptions) *Client
- func (c *Client) Get(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Head(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Header(key, val string) *Client
- func (c *Client) Headers(kv ...KV) *Client
- func (c *Client) Nodelay() *Client
- func (c *Client) Options(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Patch(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Persistent(host string, block func(*Client) error) error
- func (c *Client) Post(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Put(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Request(verb, uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Through(host string, port int, userpass ...string) *Client
- func (c *Client) Timeout(seconds int) *Client
- func (c *Client) TimeoutOps(connect, read, write int) *Client
- func (c *Client) Trace(uri string, opts ...RequestOption) (*Response, error)
- func (c *Client) Use(features ...string) *Client
- func (c *Client) Via(host string, port int, userpass ...string) *Client
- func (c *Client) WithTransport(t Transport) *Client
- type ContentType
- type Cookie
- type CookieJar
- type Error
- type ErrorKind
- type FollowOptions
- type Headers
- func (h *Headers) Add(key, val string)
- func (h *Headers) Clone() *Headers
- func (h *Headers) Delete(key string)
- func (h *Headers) Get(key string) (string, bool)
- func (h *Headers) GetAll(key string) []string
- func (h *Headers) Has(key string) bool
- func (h *Headers) Len() int
- func (h *Headers) Merge(other *Headers) *Headers
- func (h *Headers) Pairs() []KV
- func (h *Headers) Set(key, val string)
- func (h *Headers) SetDefault(key, val string)
- type KV
- type NetTransport
- type Options
- type Proxy
- type Request
- type RequestOption
- type Response
- func Delete(uri string, opts ...RequestOption) (*Response, error)
- func Get(uri string, opts ...RequestOption) (*Response, error)
- func Head(uri string, opts ...RequestOption) (*Response, error)
- func NewResponse(status int, headers *Headers, body, version, uri string) *Response
- func Patch(uri string, opts ...RequestOption) (*Response, error)
- func Post(uri string, opts ...RequestOption) (*Response, error)
- func Put(uri string, opts ...RequestOption) (*Response, error)
- func (r *Response) Body() *ResponseBody
- func (r *Response) Code() int
- func (r *Response) ContentType() ContentType
- func (r *Response) Cookies() *CookieJar
- func (r *Response) Headers() *Headers
- func (r *Response) Parse(as ...string) (any, error)
- func (r *Response) Reason() string
- func (r *Response) Request() *Request
- func (r *Response) Status() Status
- func (r *Response) URI() string
- func (r *Response) Version() string
- type ResponseBody
- type Status
- type TimeoutOptions
- type Transport
- type TransportFunc
- type Values
Constants ¶
const DefaultMaxRedirects = 5
DefaultMaxRedirects is HTTP::Redirector's default max_hops.
Variables ¶
var ( ErrError = &Error{Kind: KindError, Message: string(KindError)} ErrConnectionError = &Error{Kind: KindConnectionError, Message: string(KindConnectionError)} ErrRequestError = &Error{Kind: KindRequestError, Message: string(KindRequestError)} ErrResponseError = &Error{Kind: KindResponseError, Message: string(KindResponseError)} ErrStateError = &Error{Kind: KindStateError, Message: string(KindStateError)} ErrTimeoutError = &Error{Kind: KindTimeoutError, Message: string(KindTimeoutError)} ErrHeaderError = &Error{Kind: KindHeaderError, Message: string(KindHeaderError)} )
Sentinel errors for errors.Is matching. A concrete Error whose Kind is the sentinel's Kind (or a descendant of it) matches via Error.Is.
Functions ¶
func BasicAuthHeader ¶
BasicAuthHeader builds the HTTP Basic Authorization header value for a user and password: "Basic " followed by base64("user:password").
func EscapeFormComponent ¶
EscapeFormComponent percent-encodes s the way Ruby's URI.encode_www_form_component (used by HTTP::FormData) does: the set [A-Za-z0-9*-._] is left literal, a space becomes '+', and every other byte becomes %XX with upper-case hex.
func NormalizeHeaderName ¶
NormalizeHeaderName canonicalizes a header name the way http.rb's HTTP::Headers::Normalizer does: split on '-' and '_', capitalize each part (first letter upper, the rest lower) and join with '-'. So "content_type" and "CONTENT-TYPE" both become "Content-Type", and "WWW-Authenticate" becomes "Www-Authenticate".
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is an http.rb chainable client (HTTP::Client, including HTTP::Chainable): an immutable configuration (Options) plus a Transport. Each chainable method (Headers/Auth/Accept/…) returns a new branched client, so a base client can be shared and specialized without mutation, exactly like http.rb's chainable DSL. The verb methods issue requests through the transport.
func Follow ¶
func Follow(opts ...FollowOptions) *Client
Follow starts a chain that follows redirects (HTTP.follow).
func NewClient ¶
func NewClient() *Client
NewClient returns a fresh client with empty options and the DefaultClientTransport. Inject a per-client stub with Client.WithTransport.
func (*Client) Accept ¶
Accept returns a branched client with the Accept header set to the media type for typ (HTTP.accept(:json)). The alias "json"/":json" expands to "application/json"; any other value is used verbatim.
func (*Client) Auth ¶
Auth returns a branched client with the Authorization header set to value verbatim (HTTP.auth("Bearer tok")).
func (*Client) BasicAuth ¶
BasicAuth returns a branched client with HTTP Basic Authorization (HTTP.basic_auth(user:, pass:)): "Basic base64(user:pass)".
func (*Client) Connect ¶
func (c *Client) Connect(uri string, opts ...RequestOption) (*Response, error)
Connect issues a CONNECT request (HTTP.connect).
func (*Client) Cookies ¶
Cookies returns a branched client with the given default cookies added (HTTP.cookies(...)).
func (*Client) DefaultOptions ¶
Options returns the client's current configuration (HTTP::Client#default_options).
func (*Client) Delete ¶
func (c *Client) Delete(uri string, opts ...RequestOption) (*Response, error)
Delete issues a DELETE request (HTTP.delete).
func (*Client) Encoding ¶
Encoding returns a branched client forcing the response body charset (HTTP.encoding("UTF-8")).
func (*Client) Follow ¶
func (c *Client) Follow(opts ...FollowOptions) *Client
Follow returns a branched client that follows redirects (HTTP.follow). Pass a FollowOptions to override max hops / strictness; the default is strict with DefaultMaxRedirects hops.
func (*Client) Get ¶
func (c *Client) Get(uri string, opts ...RequestOption) (*Response, error)
Get issues a GET request (HTTP.get).
func (*Client) Head ¶
func (c *Client) Head(uri string, opts ...RequestOption) (*Response, error)
Head issues a HEAD request (HTTP.head).
func (*Client) Headers ¶
Headers returns a branched client with the given headers merged onto its defaults (HTTP.headers(...)).
func (*Client) Nodelay ¶
Nodelay returns a branched client with TCP_NODELAY requested (HTTP.nodelay).
func (*Client) Options ¶
func (c *Client) Options(uri string, opts ...RequestOption) (*Response, error)
Options issues an OPTIONS request (HTTP.options).
func (*Client) Patch ¶
func (c *Client) Patch(uri string, opts ...RequestOption) (*Response, error)
Patch issues a PATCH request (HTTP.patch).
func (*Client) Persistent ¶
Persistent runs block against a branched client pinned to host, mirroring HTTP.persistent(host) { |http| ... }. Requests to a different host inside the block fail with a StateError. The block's error (if any) is returned.
func (*Client) Post ¶
func (c *Client) Post(uri string, opts ...RequestOption) (*Response, error)
Post issues a POST request (HTTP.post).
func (*Client) Put ¶
func (c *Client) Put(uri string, opts ...RequestOption) (*Response, error)
Put issues a PUT request (HTTP.put).
func (*Client) Request ¶
func (c *Client) Request(verb, uri string, opts ...RequestOption) (*Response, error)
Request builds and performs a request for verb/uri, following redirects when the client is configured to (HTTP::Client#request). It is the general entry point behind the verb methods.
func (*Client) Through ¶
Through is an alias for Client.Via (HTTP.through).
func (*Client) Timeout ¶
Timeout returns a branched client with a global timeout of seconds (HTTP.timeout(30)). The deterministic core does not open sockets; the value is metadata a host transport honors.
func (*Client) TimeoutOps ¶
TimeoutOps returns a branched client with per-operation timeouts (HTTP.timeout(connect:, read:, write:)).
func (*Client) Trace ¶
func (c *Client) Trace(uri string, opts ...RequestOption) (*Response, error)
Trace issues a TRACE request (HTTP.trace).
func (*Client) Use ¶
Use returns a branched client with the named features/middleware enabled (HTTP.use(...)).
func (*Client) Via ¶
Via returns a branched client routing through an HTTP proxy (HTTP.via(host, port)); an optional user and password add proxy auth. The alias Client.Through matches http.rb's `through`.
func (*Client) WithTransport ¶
WithTransport returns a branched client whose round-trips run through t — the host seam. Tests pass a TransportFunc stub; a host wires the real transport.
type ContentType ¶
type ContentType struct {
// MimeType is the media type, stripped and lower-cased ("application/json"),
// or "" when the header has no media type.
MimeType string
// Charset is the charset parameter value, stripped and unquoted, or "" when
// absent.
Charset string
}
ContentType is a parsed Content-Type header, mirroring http.rb's HTTP::ContentType (a Struct of mime_type and charset).
func ParseContentType ¶
func ParseContentType(value string) ContentType
ParseContentType parses a Content-Type header value the way HTTP::ContentType.parse does: the media type is the text before the first ';', stripped and down-cased (empty ⇒ ""); the charset is the value of a case-insensitive `charset=` parameter, stripped and with surrounding quotes removed (absent ⇒ "").
type Cookie ¶
Cookie is a single name/value cookie, the deterministic subset of HTTP::Cookie the client needs to round-trip a session (attributes such as Path/Domain/Expires are host concerns and are not modeled).
type CookieJar ¶
type CookieJar struct {
// contains filtered or unexported fields
}
CookieJar is http.rb's HTTP::CookieJar reduced to its deterministic core: an ordered set of name/value cookies. It parses Set-Cookie response headers into cookies and renders a Cookie request header. Later additions of an existing name overwrite the value in place.
func (*CookieJar) Cookies ¶
Cookies returns the jar's cookies in insertion order. The slice must not be mutated.
func (*CookieJar) HeaderValue ¶
HeaderValue renders the jar as a Cookie request-header value: "name=value; name2=value2" in insertion order (empty ⇒ "").
func (*CookieJar) ParseSetCookie ¶
ParseSetCookie parses a single Set-Cookie header value and stores the name/value pair (the first "name=value" segment; attributes after the first ';' are ignored). A value with no '=' or an empty name is skipped.
type Error ¶
type Error struct {
// Kind names the HTTP:: error subclass (see the Err* sentinels).
Kind ErrorKind
// Message is the error text (Exception#message).
Message string
// Response is the response context for a ResponseError (nil otherwise).
Response *Response
// Cause is the underlying transport error, if any.
Cause error
}
Error is the root of http.rb's error tree (HTTP::Error). Every error carries a message and a Error.Kind naming the concrete HTTP:: subclass; a response error also carries the Error.Response that triggered it, and a transport error wraps the underlying cause. Match with errors.Is against the Err* sentinels — a superclass sentinel matches its subclasses, mirroring Ruby's rescue of a superclass.
type ErrorKind ¶
type ErrorKind string
ErrorKind identifies an http.rb error subclass.
const ( KindError ErrorKind = "HTTP::Error" KindConnectionError ErrorKind = "HTTP::ConnectionError" KindRequestError ErrorKind = "HTTP::RequestError" KindResponseError ErrorKind = "HTTP::ResponseError" KindStateError ErrorKind = "HTTP::StateError" KindTimeoutError ErrorKind = "HTTP::TimeoutError" KindHeaderError ErrorKind = "HTTP::HeaderError" )
The http.rb error subclasses, named as in the gem (HTTP::*).
type FollowOptions ¶
FollowOptions configures redirect following, mirroring the `follow` option and HTTP::Redirector. MaxHops caps the redirect chain (default DefaultMaxRedirects); Strict keeps the original verb on 301/302/307/308 (http.rb's default), while a non-strict follow downgrades 301/302 to GET.
type Headers ¶
type Headers struct {
// contains filtered or unexported fields
}
Headers is http.rb's HTTP::Headers: an ordered, case-insensitive header map whose names are normalized to canonical HTTP header casing (see NormalizeHeaderName) and which may carry multiple values per name (Set-Cookie, …). Lookups are case-insensitive; Headers.Get returns the first value, Headers.GetAll every value in order.
func NewHeaders ¶
NewHeaders builds a Headers from ordered entries (each added, so repeated keys accumulate as multiple values — use Headers.Set semantics via KV with distinct keys for single values).
func (*Headers) Add ¶
Add appends a value for key without removing existing ones (HTTP::Headers#add), so a name may hold several values.
func (*Headers) Delete ¶
Delete removes every value for key (case-insensitive), preserving order of the rest.
func (*Headers) Get ¶
Get returns the first value for key (case-insensitive) and whether present (HTTP::Headers#[]).
func (*Headers) Merge ¶
Merge overlays other onto a copy of h: each of other's names replaces (via Headers.Set) the corresponding entry, so merged defaults are overridden.
func (*Headers) Pairs ¶
Pairs returns the header entries in insertion order (normalized names). The slice must not be mutated.
func (*Headers) Set ¶
Set replaces every value for key with a single value (HTTP::Headers#set / []=). The name is normalized; any existing occurrences are removed first.
func (*Headers) SetDefault ¶
SetDefault sets key→val only when key is absent (case-insensitive).
type KV ¶
KV is one ordered key/value header (or form/query) entry, the convenient literal for the variadic constructors.
type NetTransport ¶
type NetTransport struct {
// Client performs the request; defaults to http.DefaultClient.
Client httpClient
}
NetTransport is the default Transport: it turns a Request into a net/http request, executes it with its Client, and maps the response (or a transport failure) back to a Response or an Error. A timeout maps to a TimeoutError, any other transport failure to a ConnectionError.
func DefaultTransport ¶
func DefaultTransport() *NetTransport
DefaultTransport returns the default net/http-backed Transport.
type Options ¶
type Options struct {
// Headers are the default headers applied to every request.
Headers *Headers
// Cookies are the default cookies sent with every request.
Cookies *CookieJar
// Proxy is the upstream proxy (nil ⇒ direct), set by Via.
Proxy *Proxy
// Follow configures redirect following (nil ⇒ do not follow).
Follow *FollowOptions
// Timeout carries the request timeouts (nil ⇒ unset), set by Timeout.
Timeout *TimeoutOptions
// Persistent is the host a persistent client is pinned to ("" ⇒ per-request).
Persistent string
// Features are the enabled feature/middleware names (HTTP#use).
Features []string
// Encoding forces the response body charset (HTTP#encoding).
Encoding string
// Nodelay disables Nagle's algorithm (HTTP#nodelay); host-honored metadata.
Nodelay bool
}
Options is the immutable per-client configuration, mirroring HTTP::Options (a client's default_options). The chainable methods on Client branch a client by cloning its Options and tweaking one field, exactly as http.rb's HTTP::Chainable#branch does.
type Proxy ¶
Proxy is an upstream HTTP proxy, mirroring the `proxy` option built by HTTP::Chainable#via.
type Request ¶
type Request struct {
// Verb is the upper-case HTTP method ("GET", "POST", …).
Verb string
// URL is the fully-built request URL (with any `params:` query merged in).
URL string
// Headers are the outgoing headers.
Headers *Headers
// Body is the encoded request body (form/JSON/raw); "" when there is none.
Body string
// Cookies are the cookies to send (rendered into the Cookie header by the
// transport or already merged by the client).
Cookies *CookieJar
// Proxy is the upstream proxy, when configured.
Proxy *Proxy
}
Request is a prepared HTTP request handed to a Transport, mirroring HTTP::Request: the verb, the target URL, the fully-merged headers (defaults overlaid by per-request headers and any encoded body's Content-Type), the encoded body, and the cookies/proxy the client is configured with.
type RequestOption ¶
type RequestOption func(*reqBuild)
RequestOption configures a single request body/query, mirroring the keyword arguments to http.rb's verb methods (`form:`, `json:`, `body:`, `params:`).
func Body ¶
func Body(s string) RequestOption
Body sends s as the raw request body verbatim (http.rb `body:`).
func Form ¶
func Form(v *Values) RequestOption
Form sends v as an application/x-www-form-urlencoded body (http.rb `form:`).
func JSON ¶
func JSON(v any) RequestOption
JSON sends v JSON-encoded with Content-Type application/json; charset=utf-8 (http.rb `json:`).
func Params ¶
func Params(v *Values) RequestOption
Params merges v into the request URL's query string (http.rb `params:`).
type Response ¶
type Response struct {
// contains filtered or unexported fields
}
Response is the result of a request, mirroring HTTP::Response: the status (with its predicates), headers, body, parsed content type, cookies, and the version/URI. Build one with NewResponse (a transport does this); read it via the accessors.
func Delete ¶
func Delete(uri string, opts ...RequestOption) (*Response, error)
Delete issues a DELETE request with a fresh default client (HTTP.delete).
func Get ¶
func Get(uri string, opts ...RequestOption) (*Response, error)
Get issues a GET request with a fresh default client (HTTP.get).
func Head ¶
func Head(uri string, opts ...RequestOption) (*Response, error)
Head issues a HEAD request with a fresh default client (HTTP.head).
func NewResponse ¶
NewResponse builds a Response from the parts a transport produces. The cookies are derived from the Set-Cookie response headers. A nil headers is treated as empty.
func Patch ¶
func Patch(uri string, opts ...RequestOption) (*Response, error)
Patch issues a PATCH request with a fresh default client (HTTP.patch).
func Post ¶
func Post(uri string, opts ...RequestOption) (*Response, error)
Post issues a POST request with a fresh default client (HTTP.post).
func Put ¶
func Put(uri string, opts ...RequestOption) (*Response, error)
Put issues a PUT request with a fresh default client (HTTP.put).
func (*Response) Body ¶
func (r *Response) Body() *ResponseBody
Body returns the response body (HTTP::Response#body).
func (*Response) ContentType ¶
func (r *Response) ContentType() ContentType
ContentType returns the parsed Content-Type header (HTTP::Response#content_type). A missing header yields the zero ContentType.
func (*Response) Cookies ¶
Cookies returns the cookies parsed from the response's Set-Cookie headers (HTTP::Response#cookies).
func (*Response) Parse ¶
Parse decodes the body according to its media type, mirroring HTTP::Response#parse. With no argument it uses the response's Content-Type; an optional override forces a media type (":json"/"json"/"application/json" all select JSON). Only JSON is decoded by the deterministic core; any other media type yields an Error of kind KindError ("unknown MIME type"), and a malformed JSON body yields a KindError wrapping the decode failure.
func (*Response) Request ¶
Request returns the Request that produced this response, when the client set it (HTTP::Response#request); nil for a bare NewResponse.
type ResponseBody ¶
type ResponseBody struct {
// contains filtered or unexported fields
}
ResponseBody is the body of a Response, mirroring http.rb's HTTP::Response::Body. The deterministic core carries the fully-read body as a string; a streaming host transport may fill it lazily, but callers observe it through ResponseBody.String/ResponseBody.To_s.
func (*ResponseBody) String ¶
func (b *ResponseBody) String() string
String returns the body as a string (HTTP::Response::Body#to_s). It also satisfies fmt.Stringer.
func (*ResponseBody) To_s ¶
func (b *ResponseBody) To_s() string
To_s is the http.rb-named alias for ResponseBody.String (Body#to_s), for hosts that surface the Ruby method name.
type Status ¶
type Status int
Status is an HTTP status code with http.rb's HTTP::Response::Status query methods. The zero value is code 0 (a nil status, as http.rb models a response with no status line).
func (Status) ClientError ¶
ClientError reports whether the code is 4xx (#client_error?).
func (Status) Informational ¶
Informational reports whether the code is 1xx (#informational?).
func (Status) Reason ¶
Reason returns the reason phrase for the status code, or "" when the code has no registered phrase (HTTP::Response::Status#reason). The table mirrors HTTP::Response::Status::REASONS.
func (Status) ServerError ¶
ServerError reports whether the code is 5xx (#server_error?).
type TimeoutOptions ¶
TimeoutOptions carries http.rb's timeout configuration. Mode is "" for the default (global) timeout or "per_operation" when connect/read/write are set individually. Values are in seconds; 0 means unset. The deterministic core does not open sockets, so these are metadata a host transport honors.
type Transport ¶
Transport is the host seam that performs the HTTP round-trip, mirroring the role http.rb's HTTP::Client delegates to its socket/connection. Given a prepared Request, a Transport returns the finished Response or a transport Error (ConnectionError / TimeoutError).
The default production Transport is DefaultTransport (backed by net/http). The core opens no socket itself: every request runs through whatever Transport the client is configured with, so tests inject a TransportFunc stub and never touch the network.
var DefaultClientTransport Transport = DefaultTransport()
DefaultClientTransport is the Transport a NewClient — and thus every package-level shortcut (Get/Post/Auth/…) — starts with. A host wires the production transport here once; tests swap in a stub so the package-level entry points never open a socket.
type TransportFunc ¶
TransportFunc adapts a function to the Transport interface — the convenient way to inject a stub in tests or a custom transport in a host.
type Values ¶
type Values struct {
// contains filtered or unexported fields
}
Values is an ordered, multi-valued string map used for form bodies and query params, mirroring the Hashes http.rb threads into `form:` and `params:`. Insertion order is preserved (http.rb's FormData encoder keeps Hash order), and a key with several values is encoded array-style ("key[]=a&key[]=b"), as HTTP::FormData::Urlencoded does.
func (*Values) Add ¶
Add appends val under key, preserving insertion order. Repeated Adds under one key make it array-valued for encoding.
func (*Values) AddNil ¶
AddNil records a bare key with no value ("key" with no '='), matching a nil Hash value in http.rb's urlencoder.
func (*Values) Encode ¶
Encode renders the values as an application/x-www-form-urlencoded string, byte-faithful to HTTP::FormData::Urlencoded: keys and values are escaped with EscapeFormComponent (space→'+', unreserved [A-Za-z0-9*-._] literal, else %XX), a multi-valued key is emitted array-style ("key[]=..."), and a bare (nil) key is emitted with no '='.
