-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
216 additions
and
26 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
HTTPL: JSON encoded message streams with HTTP semantics | ||
======================================================= | ||
|
||
--- | ||
|
||
HTTPL is used in Local.js to communicate over Browser messaging channels (postMessage, WebRTC DataChannels). The channels offer guarantees on order and delivery which are similar to that of TCP, while HTTPL provides stream multiplexing. For unordered channels, HTTPL supports head-of-line blocking. | ||
|
||
Unlike HTTP, HTTPL is full-duplex, meaning the request and response can stream simultaneously. | ||
|
||
JSON encoding was chosen over HTTP's format to take advantage of the browser's native JSON library. It's a larger message format (it includes more syntax and labeling) but it parses much faster than a JS routine for HTTP does. | ||
|
||
--- | ||
|
||
### Message Types | ||
|
||
The format consists of 4 kinds of request messages: the header, the body chunk, the end, and the close. They are: | ||
|
||
```javascript | ||
// header | ||
{ | ||
sid: 1, // stream id | ||
mid: (isReorderingMessages) ? 1 : undefined, // message id | ||
method: 'POST', // request method | ||
path: '/foo?k=v', // target resource | ||
headers: { | ||
accept: 'text/html', | ||
'content-type': 'application/json', | ||
host: 'myworker.js' | ||
} | ||
} | ||
``` | ||
|
||
```javascript | ||
// chunk | ||
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, body: '{"foo":"bar"}' } | ||
``` | ||
|
||
```javascript | ||
// end | ||
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, end: true } | ||
``` | ||
|
||
```javascript | ||
// close | ||
{ sid: 1, mid: (isReorderingMessages) ? ++midCounter : undefined, close : true } | ||
``` | ||
|
||
These messages can be combined together if the client chooses to buffer them, though at the time of this writing local.js hasn't implemented that process yet. | ||
|
||
```javascript | ||
{ | ||
sid: 1, | ||
method: 'POST', | ||
path: '/foo', | ||
headers: { | ||
accept: 'text/html', | ||
'content-type': 'application/json', | ||
host: 'myworker.js' | ||
} | ||
body: '{"foo":"bar"}', | ||
end: true, | ||
close: true | ||
} | ||
``` | ||
|
||
The `body` attribute on chunk messages are always strings in the native encoding of the given content-type. Multiple chunk messages can be issued to spread the content across the messages sequentially. | ||
|
||
The difference between end and close messages are subtle, but important. An end message signals the end of the request, but not the transaction. The requester is still listening for response data. The close message then signals that the client has ceased listening to the response. Typically, the server sends the close message, with an exception being server-sent event-streams, which clients often close. | ||
|
||
The response has the same four types of messages, but with slightly different semantics. Here are all four combined: | ||
|
||
```javascript | ||
{ | ||
sid: 1, // stream id | ||
mid: (isReorderingMessages) ? midCounter++ : undefined, // message id | ||
status: 200, // status code | ||
reason: 'Ok', // short explanation of the response | ||
headers: { 'content-type': 'text/html' }, | ||
body: '<h1>success</h1>', | ||
end: true, | ||
close: true | ||
} | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
Hypermedia Indexing Protocol | ||
============================ | ||
|
||
--- | ||
|
||
Local.js uses the [Web Linking](http://tools.ietf.org/html/rfc5988) standard to export metadata about services in the form of links. | ||
|
||
```javascript | ||
local.dispatch({ method: 'HEAD', url: 'http://foobar.com' }) | ||
``` | ||
```text | ||
> HEAD http://foobar.com HTTP/1.1 | ||
< HTTP/1.1 204 no content | ||
< Link: <http://foobar.com>; rel="self service", | ||
< <http://foobar.com/mail>; rel="collection"; id="mailboxes", | ||
< <http://foobar.com/users>; rel="collection"; id="users" | ||
``` | ||
```javascript | ||
.then(function(res) { | ||
local.queryLinks(res, { rel: 'collection' }); | ||
// => [ | ||
// { href: "http://foobar.com/mail", rel: "collection", id: "mailboxes" }, | ||
// { href: "http://foobar.com/users", rel: "collection", id: "users" } | ||
// ] | ||
}); | ||
``` | ||
|
||
--- | ||
|
||
### URI Templates | ||
|
||
Servers can use [URI Templates](http://tools.ietf.org/html/rfc6570) in their exported links (with [fxa/uritemplate-js](https://github.com/fxa/uritemplate-js)). | ||
|
||
```javascript | ||
local.dispatch({ method: 'HEAD', url: 'http://foobar.com/users' }) | ||
``` | ||
```text | ||
> HEAD http://foobar.com/users HTTP/1.1 | ||
< HTTP/1.1 204 no content | ||
< Link: <http://foobar.com>; rel="up service via", | ||
< <http://foobar.com/users{?fname,lname}>; rel="self collection"; id="users", | ||
< <http://foobar.com/users/admin>; rel="item"; id="admin", | ||
< <http://foobar.com/users/{id}>; rel="item" | ||
``` | ||
```javascript | ||
.then(function(res) { | ||
var selfLink = local.web.queryLinks(res, { rel: 'self collection' })[0]; | ||
local.UriTemplate.parse(selfLink.href).expand({ fname: 'Bob', lname: 'Robertson' }); | ||
// => http://foobar.com/users?fname=Bob&lname=Robertson | ||
|
||
var itemLinks = local.web.queryLinks(res, { rel: 'item' }); | ||
local.UriTemplate.parse(itemLinks[1].href).expand({ id: 'brobertson' }); | ||
// => http://foobar.com/users/brobertson | ||
}); | ||
``` | ||
|
||
--- | ||
|
||
### Index Navigation | ||
|
||
The [Agent](#docs/en/0.6.2/api/agent.md) follows queries by issuing HEAD requests, searching the links, and issuing subsequent HEAD requests based on matches. The navigations are followed "lazily," meaning that the HEAD requests are only sent when the application calls a dispatch function. | ||
|
||
> Read about link headers in [[The Hypermedia Indexing Protocol]] | ||
```javascript | ||
local.agent('http://foobar.com') | ||
.follow({ rel: 'collection', id: 'users' }) | ||
.follow({ rel: 'item', id: 'brobertson' }) | ||
.dispatch({ method: 'GET', headers: { accept: 'application/json' }}) | ||
``` | ||
```text | ||
> HEAD http://foobar.com | ||
< HTTP/1.1 204 no content | ||
< Link: <http://foobar.com>; rel="self service", | ||
< <http://foobar.com/mail>; rel="collection"; id="mailboxes", | ||
< <http://foobar.com/users>; rel="collection"; id="users" | ||
> HEAD http://foobar.com/users HTTP/1.1 | ||
< HTTP/1.1 204 no content | ||
< Link: <http://foobar.com>; rel="up service via foobar.com/-service", | ||
< <http://foobar.com/users/admin>; rel="item"; id="admin", | ||
< <http://foobar.com/users/{id}>; rel="item" | ||
> GET http://foobar.com/users/brobertson HTTP/1.1 | ||
< HTTP/1.1 200 ok | ||
> Accept: application/json | ||
< ... | ||
``` | ||
|
||
Notice that the item navigation did not find a full match. The navigator first looks for an exact match, then for a match with all attributes either matching or present in the URI template. In this case, `{ rel: 'item', id: 'brobertson' }` matched with `<http://foobar.com/users/{id}>; rel="item"`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.