Skip to content

Commit

Permalink
Allow asyn protocol handlers
Browse files Browse the repository at this point in the history
This allows protocol implementers to sniff content for contentType detection without blocking.

fix mozilla#56
  • Loading branch information
Gozala committed Aug 8, 2018
1 parent 1ee7977 commit c8201f1
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 23 deletions.
14 changes: 14 additions & 0 deletions demo/protocol/protocol.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ browser.protocol.registerProtocol("dweb", request => {
})()
}
}
case "dweb://async/": {
return new Promise((resolve, reject) => {
setTimeout(resolve, 100, {
contentType: "text/plain",
content: (async function*() {
const encoder = new TextEncoder("utf-8")
yield encoder.encode("Async response yo!").buffer
})()
})
})
}
case "dweb://crash/": {
throw Error("Boom!")
}
case "dweb://text/": {
return {
content: (async function*() {
Expand Down
55 changes: 34 additions & 21 deletions src/protocol/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ interface Response extends Head, Body {
}
interface Handler {
({ url: string }):Response
({ url: string }):Response|Promise<Response>
}
type Status =
Expand Down Expand Up @@ -52,11 +52,11 @@ interface Client {

class Connection {
/*::
requestID:string
port:Out<HandlerOutbox>
content:AsyncIterator<ArrayBuffer>
status:Status
*/
requestID:string
port:Out<HandlerOutbox>
content:AsyncIterator<ArrayBuffer>
status:Status
*/
constructor(
requestID /*:string*/,
port /*:Out<HandlerOutbox>*/,
Expand All @@ -83,10 +83,11 @@ interface Client {
content
})
}
end() {
end(status = 0) {
this.port.sendAsyncMessage(OUTBOX, {
type: "end",
requestID: this.requestID
requestID: this.requestID,
status
})
}
suspend(manager /*:ConnectionManager*/) {
Expand All @@ -112,7 +113,7 @@ interface Client {
close(manager) {
manager.disconnect(this.requestID)
this.status = CLOSED
this.end()
this.end(0)
delete this.port
}
abort(manager /*:ConnectionManager*/) {
Expand All @@ -124,12 +125,12 @@ interface Client {

class Protocol /*::implements ConnectionManager*/ {
/*::
context: BaseContext
handlers: { [string]: Handler }
outbox: Out<HandlerOutbox>
inbox: Inn<HandlerInbox>
connections: {[string]: Connection}
*/
context: BaseContext
handlers: { [string]: Handler }
outbox: Out<HandlerOutbox>
inbox: Inn<HandlerInbox>
connections: {[string]: Connection}
*/
constructor(context /*: BaseContext */) {
this.context = context
this.handlers = {}
Expand All @@ -156,14 +157,26 @@ interface Client {
scheme
})
}
request(request, target /*: Out<HandlerOutbox> */) {
async request(request, target /*: Out<HandlerOutbox> */) {
const { requestID, scheme, url } = request
const handler = this.handlers[request.scheme]
const response = Cu.waiveXrays(handler(Cu.cloneInto(request, handler)))
const connection = new Connection(requestID, target, response.content)
this.connect(connection)
connection.head(response)
connection.resume(this)
try {
delete request.requestID
const promise = Reflect.apply(handler, null, [
Cu.cloneInto(request, handler)
])
const response = Cu.waiveXrays(await promise)
const connection = new Connection(requestID, target, response.content)
this.connect(connection)
connection.head(response)
connection.resume(this)
} catch (error) {
target.sendAsyncMessage(OUTBOX, {
type: "end",
requestID,
status: Cr.NS_ERROR_XPC_JAVASCRIPT_ERROR
})
}
}
connect(connection /*:Connection*/) {
this.connections[connection.requestID] = connection
Expand Down
2 changes: 1 addition & 1 deletion src/protocol/protocol.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
"id": "ProtocolHandler",
"type": "function",
"description": "Protocol handler",
"async": false,
"async": true,
"parameters": [
{
"name": "request",
Expand Down
4 changes: 3 additions & 1 deletion src/protocol/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,9 @@ class Channel /*::implements nsIChannel, nsIRequest*/ {
this.byteOffset += byteLength
}

end(_) {
end({ status }) {
this.readyState = CLOSED
this.status = status
this.contentLength = this.byteOffset
debug && console.log(`end${pid} ${JSON.stringify(this)}`)
this.close()
Expand Down Expand Up @@ -624,6 +625,7 @@ export type Body = {
export type End = {
type: "end",
status:nsresult,
requestID: string
}
Expand Down

0 comments on commit c8201f1

Please sign in to comment.