The %eyre
vane serves one purpose: receiving inbound HTTP requests from browsers and clients pretending to be browsers. To facilitate this communication, %eyre
does two things: 1. provide an API for traditional clients to talk to; and 2. provide a mechanism for saving state that allows the server to keep track of identities/sessions, subscription data, and active connections.
This document outlines the following:
-
perk
, apork
subset that defines what URLs the client can send to%eyre
. -
the values stored on the client, both statically in cookies and dynamically as the
window.urb
object, which facilitate this transaction. -
kiss
, the requests%eyre
will accept. -
gift
, the responses it will give to those requests. -
note
, the set of arvo requests that %eyre makes to the other vanes. -
whir
, awire
subset, the associated dynamic state -
sign
, the responses%eyre
accepts -
bolo
, the state stored between separate events.
There exist several URL forms accepted by %eyre
.
The simplest of them is a static %f
functional publish request:
GET /<ship>/[desk]/[case]/path/to/file.[mark]
e.g.
/~pittyp-pittyp/main/5/lib/urb.js
A case
of 0 signifies the most recent version.
A shorter form:
/[desk]/path/to.[mark]
is interpreted as case 0 of the requested desk
on the current ship.
Auxiliary paths start with /~/
, and provide other functionality, such as:
When a new version of a page becomes available, it is useful to propagate it to the client. This is accomplished through long-polling endpoints:
/~/on/[desk]/[case].json
[#on-change] produces a version number of the revision following the providedcase
, blocking until it is available./~/on/<ship>/[desk]/[case].json
is similar./~/on.json?<ship>/[desk1]/[case]/path/inside&<ship>/[desk2]/[case]/path/inside&...
listens to more specific paths, producing{<beam>:[case]}
upon any update./~/on/<ship>?/[desk]/[case].js
is a lightweight script that polls for the above. It is primarily used in error messages.
Authenticated requests are accomplished through sessions, tracked with cookies which are set on the first such request.
-
/~/as/[user]/...
is an authenticated request to...
, whereuser
can be a@p
ship,'own'
, or'anon'
.'anon'
is a randomly-generated per-session submarine, and requires no further authentication.'own'
represents the serving ship. The short form of/~/as/own/
is/~~/
- Auth requests are handled in three ways:
- I. If the session is associated with the
ship
, serve...
, storing the ship as the session's default ship. For example, /~/as/sivtyv-barnel/main/pub/test.html is an authenticated request of /main/pub/test.html with the identity of~sivtyv-barnel
. - II. If the session is not associated with the
ship
in the path, the client is redirected to a login page, where a password can be entered. Successful authentication results in a page refresh to the requested path. - III. otherwise, send a message to the claimed ship, and redirect the user to
https://[foregin-host]/~/am/[ses]/...#[current-host]&?code=[code]
-
/~/am/[ses]/...#original-host
similarly serves a login page. Upon success, inform theship
of the success and redirect it back tohttp://[original-host]/~/as/<this-ship>/...
-
/~/auth.json
returns{oryx,user,auth}
: a CSRF token, active user, and all allowed users respectively. -
/~/at/{...}.js
is an alternate form of/~/auth.json
, which injects a line into the served js file that sets{oryx, user, auth}
on thewindow.urb
object. (XX always inject?)
So far, all the paths specified have been GET requests. Authentication, however, requires sending data. This is also done at the /~/auth.json
endpoint.
POST {oryx,ship,code} /~/auth.json?PUT
is used by the login script to authorize a user, and returns the same result asGET
, additionally containing either{ok:true}
or{fail:'type',mess:"Error message"}
POST {oryx,ship?} /~/auth.json?DELETE
revokes authorization. Response as above.
POST {oryx, xyro} /~/to/[app]/[mark].json
, wherexyro
is data that will be converted to themark
. In the simplest case,/~/do/hello/json.json
will passxyro
through verbatim, sending[%json xyro]
to the++poke
arm of app%hello
.POST {oryx, xyro} /~/to/<ship>/[app]/[mark].json
is a foreign message send, as above.
/~/of/[ixor]
[#of-ixor] is anEventSource
: a conceptually infinite file containing a stream of events. By default, it sends a newline every 30 seconds serving to signal that the connection is alive to both the server and IP middleware./~/of/[ixor]?poll={n}
is a long-polling fallback interface. Produces event number {n}, blocking until it occurs.
Its contexts can be affected by POST
requests with a body of {oryx}
, and a query string of PUT
or DELETE
. They return either {mark}
(which may be null
), or {fail, mess}
/~/in/<ship>/[desk]/[case].json
is a dual to/~/on
. It bindsmod
events, containing<beak>
followed by the updated version number./~/is/[app]/path/to.[mark]
bindsrush
events, formatted with a first line of[app] /path/to
, and the rest containing subscription data. Additionally,mean
events formatted similarly may arrive, also converted to the relevant mark.
These interfaces will temporarily exist to aid development, and are to be considered unstable.
/~/debug/...
access normally inaccessible pages. For example,/~/debug/as.html
will present the login page, regardless of current session status.
Authenticated users receive a cookie on the domain of *.urbit.org
.
A window.urb
object is initialized by poll.js
to contain the following values:
ship
, by default the serving shiprevs
, the (normalized, nonzero) case of the deskauto
, a boolean specifying whether auto-reload should occur. By default it is set if the request case is0
.
It is common(possibly automatic XX) to extend it with the contents of /~/auth.json
[#auth-json]:
oryx
is a unique CSRF token that identifies this view, bound to the session cookieixor
is a hash oforyx
, used as an insecure view identifieruser
is the authenticated/generated ship nameauth
is a list of identities usable by this session
Finally, /main/lib/urb.js
adds helpers:
app
is an optional app name to send messages to by defaultsend({data,mark?='json',app?=urb.app,ship?}, cb?)
delivers messagesbind({path,app?=urb.app}, cb)
subscribes by pathdrop({path,app?=urb.app}, cb?)
pulls the subscriptionutil
is an object containing methods for converting between JavaScript types and Hoon atom odors.
When the vere
process is re/started, a TCP port is bound, HTTP requests on which are the scope of this document. The %born
gift informs eyre of this occurrence, which in turn updates its state.
Gifts given in response: none.
The primary %eyre
request type comes from the host system, and constitutes an inbound http request. It consists of five parts:
I. p=[? @if]
: a loobean determining whether the request is being made over https, and the client source, an IPv6 address possibly encoding an IPv4 one as .0.0.0.0.0.ffff.wwxx.yyzz
II. q=meth
, an http method
III. r=@t
, the unparsed URL
IV. s=mess
, an associative list of header keys/values
V. t=(unit octs)
, the request body, if any.
After r
is parsed to a purl
, the pork
(relative path) determines the resource being served. The first step in handling an http request is classifying its intent.
- A ford request results in a
%boil
note. /~/[name].js
is generated from session or view state, and served as%js
./~/am
generates a login page./~/as
is resolved further if authenticated, generates a similar login page if the claimed ship is local, and otherwise is saved to session state and sends a "login"%a
message to the foreign ship./~/at
and/~/auth.json
generate a neworyx
and store it in the session state./~/in
and/~/is
affect view state, possibly sending subscriptions or unsubscriptions to%c
and%g
respectively, and are generated from view state./~/on/<beak>
is saved to thebolo
bybeak
, and translated to a%warp
note if thebeak
is new./~/of
fails if theixor
is unknown, and otherwise is stored in theixor
, receiving a partial response and all events after its last-seen header. If it has apoll
parameter, the response is full, and only occurs if the body is non-empty./~/to
transforms into a%g
message.
Gifts given in response: a %thou
, or a %that
followed by multiple %thar
s.
Sent when an unresponded-to request is cancelled.
Sent when a partial response or body fails to arrive. Its duct
is the same as that of the original request. This is handled by waiting for the client to reconnect, and if this not occur, unwinding all subscription state.
Gifts given in response: None.
Sometimes, messages are received from other ships. They are expected to take the from of a gram
.
Gifts given in response: %nice
or %mean
.
???
There are three messages of note, all concerning authentication [#foreign]
[/lon ses]
[#lon] is a login request, which contains the session wishing to authenticate.- if the session is already authorized, a reply of
[/aut ses]
from (%eyre on) a foreign ship prescribes that the session is henceforth allowed to act on its behalf. All waiting/~/as
are resolved as succesful. - otherwise,
[/hat ses hart]
contains the ship's preferred hostname. This can then be used to redirect the client. All waiting/~/as
are given307 Redirect
s to/~/am
on the provided host.
Gifts given in response: ??
A %nice
is given upon receiving an ames message, indicating succesful receipt. %mean
is currently unused directly, but reserved for error conditions.
Most requests are served with one coherent response, consisting of
p=@ud
, an HTTP status codeq=mess
, response headersr=(unit octs)
, an optional body
EventStream responses consist of multiple sequential chunks. Treated as %thou
, except the request is kept open.
Complementing %that
, %thar
is a body chunk, containing an event. An empty %thar
signals for the connection to be closed.
Body chunks, besides [1 '\0a']
(a heartbeat newline), are encoded from even
events. The stem becomes the event
field, and the content, data
lines.
There are three events that a client subscription will be given.
[%mod beam @ud]
[#even-mod] is a%c
update, and contains the path and new version number.[%rush [term path] wain]
[#even-rush] is sourced subscription data.[%mean [term path] ares]
is a sourced subscription error.
The %a
interface provides conveyance of messages over UDP.
Signs a %woot
upon message arrival.
All open subscriptions require a "heartbeat" newline every ~s30
. When this fails to arrive, a complementary timer is set for ~m1
, after which the client is considered to have departed.
The %b
timer interface is used to schedule the next such event, or cancel past scheduled ones when a connection closes.
Signs a %wake
upon timer activation.
Knowledge of filesystem changes, requested by /~/on
and /~/in
, comes via the %c
interface. Besides the XX requesting ship, A request contains the target ship, desk, and version or range of versions.
Signs a %writ
upon change.
The %f
interface converts nouns from one form to another.
Signs a %made
containing the computation result.
The silk
s used are as follows:
The simplest functional request is the construction of a page.
- The
mark
is the request extension, defaulting to%html
. - A
beam
(path in%clay
) is decoded from the request path. - A
/web/<nyp ced quy>
virtual path is appended, span-encoding method, auth, and query string.
This is used when communicating with apps, in both directions.
- Client messages are encoded as JSON objects, but can contain many different marks. Ones sent to non-
json.json
endpoints are%cast
to he relevant mark, with acage
of[%json p:!>(*json) jon]
, prior to being sent onwards to applications with[%g %mess]
. - Subscription responses also come in arbitrary marks, but are required to be sent as whichever mark an endpoint is subscribed to. They get
%cast
prior to being sent back as a%that
EventSource segment.
The end goal of many a userspace hymn.hook
is to provide UI for a %gall
app. To accommodate this, various functionality needs to be interfaced with.
After a /~/to
POST has been received, and possibly converted to the correct mark, it is sent to %g
for processing. The hapt
is the destination, the ship
is the source, the cage
is the marked message data.
Signs a %nice
or %mean
, in userspace or upon crashing.
An /~/is
PUT, if not already registered, results in a new subscription. A request for such contains the destination hapt
, requesting ship
, and app-internal path
.
Signs a %nice
on init, %rush
on data, and a %mean
in subscription termination.
A %took
must be sent to acknowledge the receipt of subscription data, which in this case occurs automatically.
Causes no signs.
An /~/is
DELETE is used to remove a subscription, and is converted straightforwardly to a %nuke
. Additionally, when a client disconnects, all of its subscriptions are %nuke
d to reflect their experiation.
Signs an empty %mean
for each open subscription that is closed.
Various state can be associated with requests, but not necessarily be returned in responses to them.
If the response should be sent statelessly further up the duct, the wire
is empty. This is used in %f
pure functional page generation, and %c
subscriptions on behalf of /~/on
and /~/in
requests.
The first element of a %b
timer path distinguishes between live(%y) and dying(%n) channels.
Designates which stream to act upon. Present on %b
timer cards.
Present on %f
translations of message marks
Subscription requests. Present on %g
subscription requests, and %f
translations of %rush
subscription data.
The goal of requests is to cause some manner of result. Specifically,
A message which has been acknowledged remotely.
Timer activate. If this is a %y
timer, send a newline to each /~/of/[oryx]
; if %n
and the oryx
still has no listeners, wipe its state/subscriptions.
This message signifies a beak
has changed, and listeners to that beak
should be updated. Results in %mod
events to concerned streams, and full responses to relevant long-polls.
Further action depends on the wire
. It can:
- Be empty, designating direct request data, which is served back up the
duct
. - Contain an app name, which designates an app message has been converted to the correct
mark
, and can now be sent to the app with an emptywire
. - Contain an
oryx
, app, andpath
, designating subscription data. If the subscription is active in the relevantstem
, it is acknowledged with a%took
and given as a%rush
event to all listeners. Otherwise, the subscription is%nuke
d.
The %g
interface sends several responses.
These are given as a response to %mess
, with an empty wire, and %show
s, with a subscription wire.
The former is served back to the requester(i.e. the remaining duct), and the latter returned to the client.
A %rush
arrives on a subscription wire, and is then sent for conversion to the correct mark. An unexpected %rush
is %nuke
d.
There is a quantity of data that persists between events.
(jar ship hart)
remembered hostnames in order of preference, made accessible through.^
- The default values(for self) are
http://<ship>.urbit.org:80
if not on a fake network, followed byhttps://0.0.0.0:[port]
.
- The default values(for self) are
(jug beak (each duct oryx))
,/~/on
and/~/in
endpoints listening to%c
updates.(map ixor oryx)
open/~/of
streams.(map oryx stem)
, open view state.(map hole sink)
, session state.(map hole ,[ship ?])
, foreign session names, along with their origin ships and whether they are authorized to act on our behalf.
Each hole
has associated authentication state.
priv
, a random secret that verifies the session, stored in cookie.[ship (set ship)]
, theship
a session is acting as and any others it has been authorized with.(jug ship ,[path duct])
, authentication/~/as
requests waiting on foreign ships.(set oryx)
, views associated with this session. Dual ofhole
instem
.
Each oryx
has active subscription state.
hole
, session in which this view resides. Dual of(set oryx)
insink
.ixor
[#ixor], a cached hash of theoryx
that is used as a subscription id, by the/~/of
EventStream.[,@u (map ,@u even)]
, queued events. Has a maximum size.(unit ,[duct @u ?])
, http connection, its last received event, and whether it is a long-poll request.(set beam)
, subscribed/~/in
points. Mirrored inbolo
.(map ,[hasp path] mark)
, subscribed/~/is
points
- An
oryx
is a CSRF token used for authenticated requests mean.json
[#mean-json] is a rendering of hoonares
: an error message formatted as{fail:'type',mess:"Error message"}
urb.js
[#urb-js] is the standard client-side implementation of the%eyre
protocols, normally found in/=main=/lib
- The act of "serving" [#mime], refers to the wrapping of a
%mime
cage in an HTTP200 Success
response, and errors or other marks being sent to ford for conversion. Inside asign
, this conversion occurs along the samewire
; otherwise, thewire
is empty.
For more information, see http://dev.w3.org/html5/eventsource/
An EventSource is a stream of events, encoded in a conceptually infinite GET
request. Each event is formatted as
id: {number}
event: {type}
data: {contents}
data: {more-contents}
Data lines are joined by ASCII 10
newline characters; multiple newlines signify separate events. The id
is used in a Last-Event-ID
HTTP request header upon reconnection.