Http

class Http extends Object

Sends HTTP requests. The static shortcuts share one stateless client and are enough for a single call; a session — Http(Options) — carries default headers, credentials and a cookie jar across its own requests.

The class is exported by the KS module:

#Import "Ks" { Http }

Table of Contents

Static Methods

Res := Http.Get(Url , Options)
Res := Http.Post(Url , Body, Options)
Res := Http.Request(Method, Url , Body, Options)

Res := Http.Download(Url, Path , Options)

Task := Http.GetAsync(Url , Options)
Task := Http.PostAsync(Url , Body, Options)
Task := Http.RequestAsync(Method, Url , Body, Options)
Task := Http.DownloadAsync(Url, Path , Options)

Method is any HTTP method, such as PUT or DELETE, and is uppercased before it is sent.

Body is equivalent to the Body option.

The synchronous forms return an Http.Response. Like Sleep, they let timers, hotkeys and the GUI run while they wait.

The Async forms return a Task carrying that response, so a request composes with Await, Then, Task.WhenAll and Task.WhenAny.

Http()

Creates a session: its own connection pool, cookie jar and default options.

Session := Http(Options)

Parameters

Options

Type: Map or Object

Any of the request options, applied as defaults to every request made through this session, plus the session options.

Session Properties

Headers

Type: Map

The headers sent with every request through this session, as a live case-insensitive Map that can be read and modified. The Map is read at the moment a request is sent, so changing it does not affect a request already in flight.

Timeout

Type: Number

Seconds to wait, default 30. -1 waits indefinitely. See the Timeout option for exactly what it bounds.

BaseUrl

Type: String

Resolved against a request URL which is not already absolute, so a session's calls name only their path. An absolute URL ignores it. Resolution follows the rule a browser uses for a link, so a BaseUrl ending in / keeps its whole path and one that does not loses its last segment.

OnData

Type: Function object

The callback every request through this session streams its body to, unless the request names its own. Reads back as "" when there is none, and assigning "" removes it.

Session Methods

Res := Session.Get(Url , Options)
Res := Session.Post(Url , Body, Options)
Res := Session.Request(Method, Url , Body, Options)
Task := Session.GetAsync(Url , Options)
Task := Session.PostAsync(Url , Body, Options)
Task := Session.RequestAsync(Method, Url , Body, Options)
Res := Session.Download(Url, Path , Options)
Task := Session.DownloadAsync(Url, Path , Options)
Session.Close()
Client := Session.ToClr()

Download saves the body to Path and returns a Response whose Body is empty. A non-2xx body is saved too, so check IsSuccess before trusting the file. Path is opened only once the response headers have arrived, so a request which gets no reply leaves an existing file unchanged. Giving OnData throws a ValueError, and a session's OnData is not applied. For ftp URLs, use the global Download.

The request methods behave as the static ones, with the session's headers, cookies, credentials, base URL and timeout applied. ToClr returns the underlying HttpClient as an ordinary Clr object, for settings this class does not surface.

Close releases the session's connections, and a session that has been closed refuses further requests. A session which is freed also releases its connections.

Request Options

Options are given as a Map or an object, with PascalCase keys. An unrecognized key throws a ValueError.

Headers, Timeout, OnData and BaseUrl may be given per request or as session defaults, and a session reads and writes each of them back as a property. A request's own value wins; Headers merges key by key, and a request value of "" removes a header for that request only.

Body and Json describe one request, so giving either to Http(Options) throws a ValueError.

Headers

Type: Map

Header names to values, compared case-insensitively as HTTP compares them. Content-Type is applied to the body, and a request with no body ignores every Content-* name. Every other name is sent as given.

Unless it is overridden, a request carries User-Agent: Keysharp/<version>.

Body

Type: String or Buffer

The request body. A string is sent as UTF-8 text/plain, a Buffer as application/octet-stream; an explicit Content-Type header replaces either. Any other object throws a TypeError.

Json

Type: Any

A value encoded with Json.Encode and sent as application/json. Giving both Body and Json throws a ValueError.

Timeout

Type: Number

A positive number of seconds, default 30, or -1 to wait indefinitely. A value that cannot be converted to a number throws a TypeError; an invalid number throws a ValueError.

It limits the wait for the response headers and then for each further piece of the body, not the transfer as a whole.

OnData

Type: Function object

See OnData.

Session Options

These configure the session's connection and are accepted only by Http(Options); giving one per request throws a ValueError.

Auth

Type: Array or String

[User, Password], or the string "Default" for the logged-in user's credentials.

The server's 401 challenge selects the scheme: Basic, Digest, NTLM, Negotiate or Kerberos. Credentials are sent only in answer to such a challenge, so preemptive Basic authentication, a bearer token or an API key is given as a header instead, such as Map("Authorization", "Basic " Base64.Encode(User ":" Password)).

Proxy

Type: String

A proxy URL, with credentials in the usual http://user:pass@host:port userinfo form. "" forces a direct connection. Omitting it uses the system proxy.

IgnoreCertificateErrors

Type: Boolean

Accepts any server certificate, for a self-signed host on a private network. It disables the check that a connection is going where it claims, so it should name a specific host's session rather than be switched on globally.

Handler

Type: Clr

An HttpMessageHandler built through Clr, used exactly as given. Client certificates, TLS version pinning, a custom validation callback, cookie policy, redirect policy, connection limits and HTTP/2 settings are all configured this way.

Giving Auth, Proxy or IgnoreCertificateErrors alongside it throws a ValueError. Close does not dispose it.

OnData

Continue := OnData(Chunk, Received, Total)

Receives the body as it arrives, so a large response never has to become a large script value.

Chunk

Type: Buffer

The bytes received since the previous call.

Received

Type: Integer

The total number of bytes received so far, including this chunk.

Total

Type: Integer

The body length the server declared, or -1 when it declared none.

Bytes accumulate for about 100 ms, or up to 1 MB, before each call. Body and Text on the response are then empty.

The callback runs in its own script thread on the real thread which made the request, and the transfer waits for it to return. Time spent in the callback does not count toward Timeout. The callback starts even when Critical, #MaxThreads or a higher-priority thread would otherwise keep a new thread from starting. Each transfer with OnData keeps the script running until it ends.

The callback may declare fewer than three parameters; it is passed only as many as it accepts. An error raised inside it fails the request without calling OnError at the throw site.

Stopping a transfer

Returning a non-zero Integer stops the transfer. Any other return value, or none, continues it.

The task is then canceled. The Async form leaves a Task whose Status is "Canceled"; the synchronous form throws what Await throws for canceled work.

Take care with a fat arrow, whose value is its last expression. This stops after the first chunk, because RawWrite returns the number of bytes written:

Http.Get(Url, {OnData: (Chunk, *) => File.RawWrite(Chunk)})       ; wrong
Http.Get(Url, {OnData: (Chunk, *) => (File.RawWrite(Chunk), 0)})  ; right

To stop a transfer from a hotkey or button, set a variable which the callback checks and returns. A transfer stops only between chunks.

Http.Response

class Http.Response extends Object

What a server answered. A response is never constructed by a script.

Status

Type: Integer

The status code, such as 200 or 404.

StatusText

Type: String

The reason phrase, such as "OK".

IsSuccess

Type: Boolean

Whether the status is in the 2xx range.

Headers

Type: Map

The response and content headers together, in one case-insensitive Map. A header sent more than once is joined with ", ", as HTTP itself defines.

Text

Type: String

The body decoded as text, using the charset the response names, and UTF-8 when it names none or names one this platform does not know.

Body

Type: Buffer

The body's raw bytes.

Url

Type: String

Where the response came from, which differs from the requested URL after a redirect. Redirects are followed automatically.

Json()

Type: Any

The body decoded as JSON, the same as Json.Decode(Res.Text). Call Json.Decode directly to pass its CaseSense or NullValue options.

ToClr()

Type: Clr

The underlying HttpResponseMessage, whose body has already been read.

Errors

A response is returned whatever its status code; check IsSuccess.

What does throw:

Examples

A request and its JSON answer.

#Import "Ks" { Http }

Res := Http.Get("https://api.github.com/repos/keysharp-org/Keysharp")
if Res.IsSuccess
    MsgBox Res.Json()["stargazers_count"]
else
    MsgBox "HTTP " Res.Status ": " Res.Text

A session, whose headers and cookies apply to each of its calls.

#Import "Ks" { Http, Url, Task, Await }

Api := Http({BaseUrl: "https://example.com/api/", Headers: Map("Authorization", "Bearer " Token)})
Api.Post("items", , {Json: {Name: "widget", Count: 2}})
Items := Api.Get("items?q=" Url.Encode(Query)).Json()

; Two requests at once.
Both := Await(Task.WhenAll(Api.GetAsync("items"), Api.GetAsync("users")))

Streaming to a file with a progress bar.

#Import "Ks" { Http }

Gui1 := Gui(), Bar := Gui1.Add("Progress", "w300"), Gui1.Show()
File := FileOpen("big.iso", "w")
Http.Get(Url, {OnData: (Chunk, Received, Total) =>
    (File.RawWrite(Chunk), Bar.Value := Total > 0 ? 100 * Received / Total : 0, 0)})
File.Close()

Download, Json, Url, Base64, Task, Await, Clr