Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 <import src="/mojo/public/sky/core.sky" as="core" /> | 1 <import src="/mojo/public/sky/core.sky" as="core" /> |
| 2 <import src="/mojo/public/sky/unicode.sky" as="unicode" /> | 2 <import src="/mojo/public/sky/unicode.sky" as="unicode" /> |
| 3 <import src="/mojo/services/network/public/interfaces/network_service.mojom.sky" as="net" /> | 3 <import src="/mojo/services/network/public/interfaces/network_service.mojom.sky" as="net" /> |
| 4 <import src="/mojo/services/network/public/interfaces/url_loader.mojom.sky" as=" loader" /> | 4 <import src="/mojo/services/network/public/interfaces/url_loader.mojom.sky" as=" loader" /> |
| 5 <import src="/sky/framework/shell.sky" as="shell" /> | 5 <import src="/sky/framework/shell.sky" as="shell" /> |
| 6 <script> | 6 <script> |
| 7 // XHR keeps itself alive. | 7 // XHR keeps itself alive. |
| 8 var outstandingRequests = new Set(); | 8 var outstandingRequests = new Set(); |
| 9 | 9 |
| 10 const kPrivate = Symbol("XMLHttpRequestPrivate"); | 10 const kPrivate = Symbol("XMLHttpRequestPrivate"); |
| 11 | 11 |
| 12 class Private { | 12 class Private { |
| 13 constructor() { | 13 constructor() { |
| 14 this.networkService = shell.connectToService( | 14 this.networkService = shell.connectToService( |
| 15 "mojo:network_service", net.NetworkService); | 15 "mojo:network_service", net.NetworkService); |
| 16 this.request = null; | 16 this.request = null; |
| 17 this.loader = null; | 17 this.loader = null; |
| 18 this.headers = new Map(); | 18 this.headers = new Map(); |
| 19 this.responseArrayBuffer = null; | 19 this.responseArrayBuffer = null; |
| 20 this.responseText = null; // Cached to avoid re-decoding each access. | 20 this.responseText = null; // Cached to avoid re-decoding each access. |
| 21 } | 21 } |
| 22 } | 22 } |
| 23 | 23 |
| 24 // Somewhat hacky, but works. | |
| 25 function stringToUTF8Buffer(string) { | |
| 26 var string = unescape(encodeURIComponent(string)); | |
| 27 var charList = string.split(''); | |
| 28 var uintArray = []; | |
| 29 for (var i = 0; i < charList.length; i++) { | |
| 30 uintArray.push(charList[i].charCodeAt(0)); | |
|
esprehn
2014/12/15 21:43:22
This doesn't make sense, the splitting above seems
esprehn
2014/12/15 21:50:56
I think you want:
function stringToUTF8Buffer(str
| |
| 31 } | |
| 32 return new Uint8Array(uintArray); | |
| 33 } | |
| 34 | |
| 24 // https://xhr.spec.whatwg.org | 35 // https://xhr.spec.whatwg.org |
| 25 class XMLHttpRequest { | 36 class XMLHttpRequest { |
| 26 constructor() { | 37 constructor() { |
| 27 this[kPrivate] = new Private; | 38 this[kPrivate] = new Private; |
| 28 this.responseType = ''; // Only text and arraybuffer support for now. | 39 this.responseType = ''; // Only text and arraybuffer support for now. |
| 40 this.status = null; | |
| 41 this.statusText = null; | |
| 29 } | 42 } |
| 30 | 43 |
| 31 onload() { | 44 onload() { |
| 32 } | 45 } |
| 33 | 46 |
| 34 onerror(error) { | 47 onerror(error) { |
| 35 } | 48 } |
| 36 | 49 |
| 37 get responseText() { | 50 get responseText() { |
| 38 if (this.responseType !== '' && this.responseType !== 'text') | 51 if (this.responseType !== '' && this.responseType !== 'text') |
| (...skipping 23 matching lines...) Expand all Loading... | |
| 62 | 75 |
| 63 var priv = this[kPrivate]; | 76 var priv = this[kPrivate]; |
| 64 priv.request = request; | 77 priv.request = request; |
| 65 priv.headers.clear(); | 78 priv.headers.clear(); |
| 66 } | 79 } |
| 67 | 80 |
| 68 setRequestHeader(header, value) { | 81 setRequestHeader(header, value) { |
| 69 this[kPrivate].headers.set(header, value); | 82 this[kPrivate].headers.set(header, value); |
| 70 } | 83 } |
| 71 | 84 |
| 72 send() { | 85 send(body) { |
| 73 var priv = this[kPrivate]; | 86 var priv = this[kPrivate]; |
| 87 // Handle the body before the headers as it can affect Content-Type. | |
| 88 if (body) { | |
| 89 var bodyAsBufferView = null; | |
| 90 if (typeof(body) === "string") { | |
| 91 this.setRequestHeader("Content-Type", "text/plain;charset=UTF-8"); | |
| 92 bodyAsBufferView = stringToUTF8Buffer(body); | |
| 93 } else { | |
| 94 bodyAsBufferView = new Uint8Array(body); | |
| 95 } | |
| 96 var dataPipe = new core.createDataPipe(); | |
| 97 // FIXME: body is currently assumed to be an ArrayBuffer. | |
| 98 var writeResult = core.writeData(dataPipe.producerHandle, | |
| 99 bodyAsBufferView, core.WRITE_DATA_FLAG_ALL_OR_NONE); | |
| 100 core.close(dataPipe.producerHandle); | |
| 101 // FIXME: Much better error handling needed. | |
| 102 console.assert(writeResult.result === core.RESULT_OK); | |
| 103 console.assert(writeResult.numBytes === body.length); | |
| 104 // 'body' is actually an array of body segments. | |
| 105 priv.request.body = [dataPipe.consumerHandle]; | |
| 106 } | |
| 107 | |
| 74 var requestHeaders = []; | 108 var requestHeaders = []; |
| 75 priv.headers.forEach(function(value, key) { | 109 priv.headers.forEach(function(value, key) { |
| 76 requestHeaders.push(key + ': ' + value); | 110 requestHeaders.push(key + ': ' + value); |
| 77 }); | 111 }); |
| 78 priv.request.headers = requestHeaders; | 112 priv.request.headers = requestHeaders; |
| 79 | 113 |
| 80 // FIXME: Factor this into the JS bindings. | 114 // FIXME: Factor this into the JS bindings. |
| 81 var pipe = new core.createMessagePipe(); | 115 var pipe = new core.createMessagePipe(); |
| 82 priv.networkService.createURLLoader(pipe.handle1); | 116 priv.networkService.createURLLoader(pipe.handle1); |
| 83 priv.loader = shell.wrapHandle(pipe.handle0, loader.URLLoader); | 117 priv.loader = shell.wrapHandle(pipe.handle0, loader.URLLoader); |
| 84 | 118 |
| 85 var self = this; | 119 var self = this; |
| 86 outstandingRequests.add(this); | 120 outstandingRequests.add(this); |
| 87 priv.loader.start(priv.request).then(function(result) { | 121 priv.loader.start(priv.request).then(function(result) { |
| 122 self.status = result.response.status_code; | |
| 123 self.statusText = result.response.status_line; | |
| 124 if (result.response.error) | |
| 125 throw new Error(result.response.error.description); | |
| 88 return core.drainData(result.response.body).then(function(result) { | 126 return core.drainData(result.response.body).then(function(result) { |
| 89 outstandingRequests.delete(self); | 127 outstandingRequests.delete(self); |
| 90 priv.responseArrayBuffer = result.buffer; | 128 priv.responseArrayBuffer = result.buffer; |
| 91 // FIXME: Catch exceptions during onload so they don't trip onerror. | 129 // Use a setTimeout to avoid exceptions in onload tripping onerror. |
| 92 self.onload(); | 130 window.setTimeout(function() { |
| 131 self.onload(); | |
| 132 }); | |
| 93 }); | 133 }); |
| 94 }).catch(function(error) { | 134 }).catch(function(error) { |
| 95 outstandingRequests.delete(self); | 135 outstandingRequests.delete(self); |
| 136 // Technically this should throw a ProgressEvent. | |
| 96 self.onerror(error); | 137 self.onerror(error); |
| 97 }); | 138 }); |
| 98 } | 139 } |
| 99 } | 140 } |
| 100 | 141 |
| 101 module.exports = XMLHttpRequest; | 142 module.exports = XMLHttpRequest; |
| 102 </script> | 143 </script> |
| OLD | NEW |