Given the ubiquity of HTTP(S) out there today, especially the number of useful HTTP-only APIs, it would be great if mIRC had basic HTTP client abstractions to avoid the complexity (and limitations) of manually writing /sock code to send HTTP requests.
The following is one of many proposals for how the commands might work. There might be existing scripts that could be used for reference, but here's a simplistic API:
Synchronous identifier mode (easy-mode):
; A simplistic SYNCHRONOUS HTTP request function. Returns the
; status code and body, but does not provide access to headers.
; For complex HTTP requests, use the asynchronous function.
;
; Returns <status code> [response body]
$httpreq(<method>, <full URI>, [biohuN], [body], [&outbin],
[<Header: value>, ...])
Switches:
b: indicates that a body is provided.
i: indicates that the body token is a binvar.
o: indicates that the outbin binvar is provided to store output.
In this case, $httpreq returns ONLY the status code.
h: indicates that a list of "Header: value" parameters are provided.
uN: timeout the request after N seconds if there is no response.
(XXX: support decimals or make this milliseconds?)
Example:
//echo -a Response: $httpreq(GET, http://example.org/res?q=foo, h,
Authorization: my-api-token)
; echos: Response: 200 SomeDataHere
Asynchronous session-based evented mode:
; Opens/closes an HTTP session.
; No error if the handle is already open.
/httpopen <handle>
/httpclose <handle>
; Starts a request but doesn't send it.
; Error if /httpstart was executed without matching /httpsend.
/httpstart [-os] <handle> <method> <full URI>
-o: open the handle if not already open
-s: call /httpsend immediately (no body/headers)
; Adds a header to a request
; Error if no pending /httpstart transaction exists.
/httpheader [-b] <handle> <header> <value>
-b: the value parameter is a binvar.
; Adds a body to a request
; Error if no pending /httpstart transaction exists.
/httpbody [-b] <handle> <body|&binvar>
-b: the body parameter is a binvar.
; Sends the last built request on handle
; Error if no pending /httpstart transaction exists.
/httpsend <handle>
; Handles a response from a request on a session
on HTTPRESPONSE:<handle>:<uri matchtext>:
<comma separated matchtext statuscodes?>:/commands
The event would expose a few identifiers:
$httphandle - the handle of the session
$httpuri - the URI of the response (matches the URI of the
resource we called in /httpstart)
$httpstatus - the status code
$httpheader(N/Name) - the Nth header in the response or the
header named Name if text is provided.
$httpbody - the response body
Possibly also /httpread <%var|&binvar> which would copy the
body into a var/binvar.
Full example usage:
alias makereq {
httpstart -o mysession POST http://example.org/posts/create
httpheader mysession Authorization: my-api-token
httpbody mysession The body to send
httpsend mysession
}
; Handle initial success response
on *:HTTPRESPONSE:mysession:*/posts/create:200: {
; more correct to use 2* as status code match
echo -a Success! Creation data: $httpbody
; I can now make a follow-up request using the same session
; using any stored cookie data.
httpstart $httphandle GET $httpheader(Post-URI)
httpheader $httphandle Authorization: my-api-token
httpsend $httphandle
}
; Handle follow-up request
on *:HTTPRESPONSE:mysession:*:2*: {
echo -a Post body: $httpbody
}
; Handle failures
on *:HTTPRESPONSE:mysession:*:4*,5*: { ; handle 4xx 5xx responses
echo -a Error occurred when retrieving $httpuri
}
Note that the session based mode allows for important useful benefits, namely:
1. It can use keep-alive connections to efficiently make multiple requests.
2. It would follow redirects (3xx responses), which are non-trivial to handle manually.
3. It would (optionally?) keep track of Cookie data. This is a must for many "login-to-post" scraper scripts out there, which send down session IDs for follow up authentication. Currently, manually scripting socket code to interact with these kinds of websites is extremely complex. I could see this being turned off, but if this is optional it should be on by default.
4. It would transparently handle HTTPS connections using mIRC's already existing SSL libraries and certificate management experience.
There might be better API choices here. It's possible to merge the session concept into the identifier mode too. Ultimately the important part is simplifying the overhead in crafting an HTTP request. The use case would be scripts making requests to APIs like Google, IMDb, GitHub, Dropbox, IFTT, etc., or even just their own scripted services to check for script updates and download them. A lot of these should be simple one-liners (or 3-4) but are much more complex due to the manual socket scripting that is currently required-- not to mention out of reach for typical users. HTTP abstractions would allow less advanced scripters to interact with simple HTTP APIs.
Note that this doesn't really solve the remaining problem of processing the response data, but it's a good first step. I suppose if this were implemented, it would be great to have a follow-up set of abstractions for JSON processing, like, say a $json() identifier that could pull data out using some query language a la JSONPath or jq.