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 }
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.
Creates a session: its own connection pool, cookie jar and default options.
Session := Http(Options)
Any of the request options, applied as defaults to every request made through this session, plus the session options.
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.
Type: Number
Seconds to wait, default 30. -1 waits indefinitely. See the Timeout option for exactly what it bounds.
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.
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.
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.
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.
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>.
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.
Type: Any
A value encoded with Json.Encode and sent as application/json. Giving both Body and Json throws a ValueError.
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.
Type: Function object
See OnData.
These configure the session's connection and are accepted only by Http(Options); giving one per request throws a ValueError.
[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)).
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.
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.
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.
Continue := OnData(Chunk, Received, Total)
Receives the body as it arrives, so a large response never has to become a large script value.
Type: Buffer
The bytes received since the previous call.
Type: Integer
The total number of bytes received so far, including this chunk.
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.
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.
class Http.Response extends Object
What a server answered. A response is never constructed by a script.
Type: Integer
The status code, such as 200 or 404.
Type: String
The reason phrase, such as "OK".
Type: Boolean
Whether the status is in the 2xx range.
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.
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.
Type: Buffer
The body's raw bytes.
Type: String
Where the response came from, which differs from the requested URL after a redirect. Redirects are followed automatically.
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.
Type: Clr
The underlying HttpResponseMessage, whose body has already been read.
A response is returned whatever its status code; check IsSuccess.
What does throw:
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()