| OLD | NEW |
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 define("mojo/public/js/router", [ | 5 define("mojo/public/js/router", [ |
| 6 "mojo/public/js/codec", | 6 "mojo/public/js/codec", |
| 7 "mojo/public/js/core", | 7 "mojo/public/js/core", |
| 8 "mojo/public/js/connector", | 8 "mojo/public/js/connector", |
| 9 "mojo/public/js/validator", | 9 "mojo/public/js/validator", |
| 10 ], function(codec, core, connector, validator) { | 10 ], function(codec, core, connector, validator) { |
| 11 | 11 |
| 12 var Connector = connector.Connector; | 12 var Connector = connector.Connector; |
| 13 var MessageReader = codec.MessageReader; | 13 var MessageReader = codec.MessageReader; |
| 14 var Validator = validator.Validator; | 14 var Validator = validator.Validator; |
| 15 | 15 |
| 16 function Router(handle, connectorFactory) { | 16 function Router(handle, connectorFactory) { |
| 17 if (!core.isHandle(handle)) | 17 if (!core.isHandle(handle)) |
| 18 throw new Error("Router constructor: Not a handle"); | 18 throw new Error("Router constructor: Not a handle"); |
| 19 if (connectorFactory === undefined) | 19 if (connectorFactory === undefined) |
| 20 connectorFactory = Connector; | 20 connectorFactory = Connector; |
| 21 this.connector_ = new connectorFactory(handle); | 21 this.connector_ = new connectorFactory(handle); |
| 22 this.incomingReceiver_ = null; | 22 this.incomingReceiver_ = null; |
| 23 this.errorHandler_ = null; | 23 this.errorHandler_ = null; |
| 24 this.nextRequestID_ = 0; | 24 this.nextRequestID_ = 0; |
| 25 this.completers_ = new Map(); | 25 this.completers_ = new Map(); |
| 26 this.payloadValidators_ = []; | 26 this.payloadValidators_ = []; |
| 27 this.testingController_ = null; |
| 27 | 28 |
| 28 this.connector_.setIncomingReceiver({ | 29 this.connector_.setIncomingReceiver({ |
| 29 accept: this.handleIncomingMessage_.bind(this), | 30 accept: this.handleIncomingMessage_.bind(this), |
| 30 }); | 31 }); |
| 31 this.connector_.setErrorHandler({ | 32 this.connector_.setErrorHandler({ |
| 32 onError: this.handleConnectionError_.bind(this), | 33 onError: this.handleConnectionError_.bind(this), |
| 33 }); | 34 }); |
| 34 } | 35 } |
| 35 | 36 |
| 36 Router.prototype.close = function() { | 37 Router.prototype.close = function() { |
| 37 this.completers_.clear(); // Drop any responders. | 38 this.completers_.clear(); // Drop any responders. |
| 38 this.connector_.close(); | 39 this.connector_.close(); |
| 40 this.testingController_ = null; |
| 39 }; | 41 }; |
| 40 | 42 |
| 41 Router.prototype.accept = function(message) { | 43 Router.prototype.accept = function(message) { |
| 42 this.connector_.accept(message); | 44 this.connector_.accept(message); |
| 43 }; | 45 }; |
| 44 | 46 |
| 45 Router.prototype.reject = function(message) { | 47 Router.prototype.reject = function(message) { |
| 46 // TODO(mpcomplete): no way to trasmit errors over a Connection. | 48 // TODO(mpcomplete): no way to trasmit errors over a Connection. |
| 47 }; | 49 }; |
| 48 | 50 |
| (...skipping 25 matching lines...) Expand all Loading... |
| 74 }; | 76 }; |
| 75 | 77 |
| 76 Router.prototype.setErrorHandler = function(handler) { | 78 Router.prototype.setErrorHandler = function(handler) { |
| 77 this.errorHandler_ = handler; | 79 this.errorHandler_ = handler; |
| 78 }; | 80 }; |
| 79 | 81 |
| 80 Router.prototype.encounteredError = function() { | 82 Router.prototype.encounteredError = function() { |
| 81 return this.connector_.encounteredError(); | 83 return this.connector_.encounteredError(); |
| 82 }; | 84 }; |
| 83 | 85 |
| 86 Router.prototype.enableTestingMode = function() { |
| 87 this.testingController_ = new RouterTestingController(this.connector_); |
| 88 return this.testingController_; |
| 89 }; |
| 90 |
| 84 Router.prototype.handleIncomingMessage_ = function(message) { | 91 Router.prototype.handleIncomingMessage_ = function(message) { |
| 85 var noError = validator.validationError.NONE; | 92 var noError = validator.validationError.NONE; |
| 86 var messageValidator = new Validator(message); | 93 var messageValidator = new Validator(message); |
| 87 var err = messageValidator.validateMessageHeader(); | 94 var err = messageValidator.validateMessageHeader(); |
| 88 for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i) | 95 for (var i = 0; err === noError && i < this.payloadValidators_.length; ++i) |
| 89 err = this.payloadValidators_[i](messageValidator); | 96 err = this.payloadValidators_[i](messageValidator); |
| 90 | 97 |
| 91 if (err == noError) | 98 if (err == noError) |
| 92 this.handleValidIncomingMessage_(message); | 99 this.handleValidIncomingMessage_(message); |
| 93 else | 100 else |
| 94 this.handleInvalidIncomingMessage_(message, err); | 101 this.handleInvalidIncomingMessage_(message, err); |
| 95 }; | 102 }; |
| 96 | 103 |
| 97 Router.prototype.handleValidIncomingMessage_ = function(message) { | 104 Router.prototype.handleValidIncomingMessage_ = function(message) { |
| 105 if (this.testingController_) |
| 106 return; |
| 107 |
| 98 if (message.expectsResponse()) { | 108 if (message.expectsResponse()) { |
| 99 if (this.incomingReceiver_) { | 109 if (this.incomingReceiver_) { |
| 100 this.incomingReceiver_.acceptWithResponder(message, this); | 110 this.incomingReceiver_.acceptWithResponder(message, this); |
| 101 } else { | 111 } else { |
| 102 // If we receive a request expecting a response when the client is not | 112 // If we receive a request expecting a response when the client is not |
| 103 // listening, then we have no choice but to tear down the pipe. | 113 // listening, then we have no choice but to tear down the pipe. |
| 104 this.close(); | 114 this.close(); |
| 105 } | 115 } |
| 106 } else if (message.isResponse()) { | 116 } else if (message.isResponse()) { |
| 107 var reader = new MessageReader(message); | 117 var reader = new MessageReader(message); |
| 108 var requestID = reader.requestID; | 118 var requestID = reader.requestID; |
| 109 var completer = this.completers_.get(requestID); | 119 var completer = this.completers_.get(requestID); |
| 110 this.completers_.delete(requestID); | 120 this.completers_.delete(requestID); |
| 111 completer.resolve(message); | 121 completer.resolve(message); |
| 112 } else { | 122 } else { |
| 113 if (this.incomingReceiver_) | 123 if (this.incomingReceiver_) |
| 114 this.incomingReceiver_.accept(message); | 124 this.incomingReceiver_.accept(message); |
| 115 } | 125 } |
| 116 } | 126 }; |
| 117 | 127 |
| 118 Router.prototype.handleInvalidIncomingMessage_ = function(message, error) { | 128 Router.prototype.handleInvalidIncomingMessage_ = function(message, error) { |
| 119 this.close(); | 129 if (!this.testingController_) { |
| 120 } | 130 // TODO(yzshen): Consider logging and notifying the embedder. |
| 131 // TODO(yzshen): This should also trigger connection error handler. |
| 132 // Consider making accept() return a boolean and let the connector deal |
| 133 // with this, as the C++ code does. |
| 134 this.close(); |
| 135 return; |
| 136 } |
| 137 |
| 138 this.testingController_.onInvalidIncomingMessage(error); |
| 139 }; |
| 121 | 140 |
| 122 Router.prototype.handleConnectionError_ = function(result) { | 141 Router.prototype.handleConnectionError_ = function(result) { |
| 123 this.completers_.forEach(function(value) { | 142 this.completers_.forEach(function(value) { |
| 124 value.reject(result); | 143 value.reject(result); |
| 125 }); | 144 }); |
| 126 if (this.errorHandler_) | 145 if (this.errorHandler_) |
| 127 this.errorHandler_(); | 146 this.errorHandler_(); |
| 128 this.close(); | 147 this.close(); |
| 129 }; | 148 }; |
| 130 | 149 |
| 131 // The TestRouter subclass is only intended to be used in unit tests. | 150 // The RouterTestingController is used in unit tests. It defeats valid message |
| 132 // It defeats valid message handling and delgates invalid message handling. | 151 // handling and delgates invalid message handling. |
| 133 | 152 |
| 134 function TestRouter(handle, connectorFactory) { | 153 function RouterTestingController(connector) { |
| 135 Router.call(this, handle, connectorFactory); | 154 this.connector_ = connector; |
| 155 this.invalidMessageHandler_ = null; |
| 136 } | 156 } |
| 137 | 157 |
| 138 TestRouter.prototype = Object.create(Router.prototype); | 158 RouterTestingController.prototype.waitForNextMessage = function() { |
| 139 | 159 this.connector_.waitForNextMessageForTesting(); |
| 140 TestRouter.prototype.handleValidIncomingMessage_ = function() { | |
| 141 }; | 160 }; |
| 142 | 161 |
| 143 TestRouter.prototype.handleInvalidIncomingMessage_ = | 162 RouterTestingController.prototype.setInvalidIncomingMessageHandler = |
| 144 function(message, error) { | 163 function(callback) { |
| 145 this.validationErrorHandler(error); | 164 this.invalidMessageHandler_ = callback; |
| 146 }; | 165 }; |
| 166 |
| 167 RouterTestingController.prototype.onInvalidIncomingMessage = |
| 168 function(error) { |
| 169 if (this.invalidMessageHandler_) |
| 170 this.invalidMessageHandler_(error); |
| 171 }; |
| 147 | 172 |
| 148 var exports = {}; | 173 var exports = {}; |
| 149 exports.Router = Router; | 174 exports.Router = Router; |
| 150 exports.TestRouter = TestRouter; | |
| 151 return exports; | 175 return exports; |
| 152 }); | 176 }); |
| OLD | NEW |