Index: chrome/browser/resources/print_preview/cloud_print_interface.js |
diff --git a/chrome/browser/resources/print_preview/cloud_print_interface.js b/chrome/browser/resources/print_preview/cloud_print_interface.js |
index 71906609e34f38e0294056e4763df5003bd7bf08..af93ddd271641868486aaec13f84e937cf13b70f 100644 |
--- a/chrome/browser/resources/print_preview/cloud_print_interface.js |
+++ b/chrome/browser/resources/print_preview/cloud_print_interface.js |
@@ -47,11 +47,12 @@ cr.define('cloudprint', function() { |
this.userSessionIndex_ = {}; |
/** |
- * Last received XSRF token. Sent as a parameter in every request. |
- * @type {string} |
+ * Stores last received XSRF tokens for each user account. Sent as |
+ * a parameter with every request. |
+ * @type {!Object.<string, string>} |
* @private |
*/ |
- this.xsrfToken_ = ''; |
+ this.xsrfTokens_ = {}; |
/** |
* Pending requests delayed until we get access token. |
@@ -175,15 +176,7 @@ cr.define('cloudprint', function() { |
search: function(opt_origin) { |
var origins = |
opt_origin && [opt_origin] || CloudPrintInterface.CLOUD_ORIGINS_; |
- // Terminate outstanding search requests for all requested origins. |
- this.outstandingCloudSearchRequests_ = |
- this.outstandingCloudSearchRequests_.filter(function(request) { |
- if (origins.indexOf(request.origin) >= 0) { |
- request.xhr.abort(); |
- return false; |
- } |
- return true; |
- }); |
+ this.abortSearchRequests_(origins); |
this.search_(true, origins); |
this.search_(false, origins); |
}, |
@@ -206,9 +199,13 @@ cr.define('cloudprint', function() { |
params.push(new HttpParam('q', '^recent')); |
} |
origins.forEach(function(origin) { |
- var cpRequest = |
- this.buildRequest_('GET', 'search', params, origin, |
- this.onSearchDone_.bind(this, isRecent)); |
+ var cpRequest = this.buildRequest_( |
+ 'GET', |
+ 'search', |
+ params, |
+ origin, |
+ this.userInfo_.activeUser, |
Toscano
2014/04/11 04:24:00
Hmm, seems like a hidden contract that the search
Aleksey Shlyapnikov
2014/04/11 19:09:29
Done.
|
+ this.onSearchDone_.bind(this, isRecent)); |
this.outstandingCloudSearchRequests_.push(cpRequest); |
this.sendOrQueueRequest_(cpRequest); |
}, this); |
@@ -241,9 +238,13 @@ cr.define('cloudprint', function() { |
'__google__chrome_version=' + chromeVersion), |
new HttpParam('tag', '__google__os=' + navigator.platform) |
]; |
- var cpRequest = this.buildRequest_('POST', 'submit', params, |
- destination.origin, |
- this.onSubmitDone_.bind(this)); |
+ var cpRequest = this.buildRequest_( |
+ 'POST', |
+ 'submit', |
+ params, |
+ destination.origin, |
+ destination.account, |
+ this.onSubmitDone_.bind(this)); |
this.sendOrQueueRequest_(cpRequest); |
}, |
@@ -251,36 +252,46 @@ cr.define('cloudprint', function() { |
* Sends a Google Cloud Print printer API request. |
* @param {string} printerId ID of the printer to lookup. |
* @param {!print_preview.Destination.Origin} origin Origin of the printer. |
+ * @param {string=} account Account this printer is registered for. When |
+ * provided for COOKIES {@code origin}, and users sessions are still not |
+ * known, will be checked against the response (both success and failure |
+ * to get printer) and, if the active user account is not the one |
+ * requested, {@code account} is activated and printer request reissued. |
*/ |
- printer: function(printerId, origin) { |
+ printer: function(printerId, origin, account) { |
var params = [ |
new HttpParam('printerid', printerId), |
new HttpParam('use_cdd', 'true'), |
new HttpParam('printer_connection_status', 'true') |
]; |
- var cpRequest = |
- this.buildRequest_('GET', 'printer', params, origin, |
- this.onPrinterDone_.bind(this, printerId)); |
- this.sendOrQueueRequest_(cpRequest); |
+ this.sendOrQueueRequest_(this.buildRequest_( |
+ 'GET', |
+ 'printer', |
+ params, |
+ origin, |
+ account, |
+ this.onPrinterDone_.bind(this, printerId))); |
}, |
/** |
* Sends a Google Cloud Print update API request to accept (or reject) the |
* terms-of-service of the given printer. |
- * @param {string} printerId ID of the printer to accept the |
- * terms-of-service for. |
- * @param {!print_preview.Destination.Origin} origin Origin of the printer. |
- * @param {boolean} isAccepted Whether the user accepted the |
- * terms-of-service. |
+ * @param {!print_preview.Destination} destination Destination to accept ToS |
+ * for. |
+ * @param {boolean} isAccepted Whether the user accepted ToS or not. |
*/ |
- updatePrinterTosAcceptance: function(printerId, origin, isAccepted) { |
+ updatePrinterTosAcceptance: function(destination, isAccepted) { |
var params = [ |
- new HttpParam('printerid', printerId), |
+ new HttpParam('printerid', destination.id), |
new HttpParam('is_tos_accepted', isAccepted) |
]; |
- var cpRequest = |
- this.buildRequest_('POST', 'update', params, origin, |
- this.onUpdatePrinterTosAcceptanceDone_.bind(this)); |
+ var cpRequest = this.buildRequest_( |
+ 'POST', |
+ 'update', |
+ params, |
Vitaly Buka (NO REVIEWS)
2014/04/11 02:32:57
inconsistent
Aleksey Shlyapnikov
2014/04/11 19:09:29
Done.
|
+ destination.origin, |
+ destination.account, |
+ this.onUpdatePrinterTosAcceptanceDone_.bind(this)); |
this.sendOrQueueRequest_(cpRequest); |
}, |
@@ -293,6 +304,10 @@ cr.define('cloudprint', function() { |
this.nativeLayer_, |
print_preview.NativeLayer.EventType.ACCESS_TOKEN_READY, |
this.onAccessTokenReady_.bind(this)); |
+ this.tracker_.add( |
+ this.userInfo_, |
+ print_preview.UserInfo.EventType.ACTIVE_USER_CHANGED, |
+ this.onActiveUserChanged_.bind(this)); |
}, |
/** |
@@ -302,25 +317,28 @@ cr.define('cloudprint', function() { |
* @param {Array.<!HttpParam>} params HTTP parameters to include in the |
* request. |
* @param {!print_preview.Destination.Origin} origin Origin for destination. |
+ * @param {?string} account Account the request is sent for. Can be |
+ * {@code null} or empty string if the request is not cookie bound or |
+ * is sent on behalf of the primary user. |
* @param {function(number, Object, !print_preview.Destination.Origin)} |
* callback Callback to invoke when request completes. |
* @return {!CloudPrintRequest} Partially prepared request. |
* @private |
*/ |
- buildRequest_: function(method, action, params, origin, callback) { |
+ buildRequest_: function(method, action, params, origin, account, callback) { |
var url = this.baseUrl_ + '/' + action + '?xsrf='; |
if (origin == print_preview.Destination.Origin.COOKIES) { |
- if (!this.xsrfToken_) { |
+ var xsrfToken = this.xsrfTokens_[account]; |
+ if (!xsrfToken) { |
// TODO(rltoscano): Should throw an error if not a read-only action or |
// issue an xsrf token request. |
} else { |
- url = url + this.xsrfToken_; |
+ url = url + xsrfToken; |
} |
- params = params || []; |
- if (this.userInfo_.activeUser) { |
- var index = this.userSessionIndex_[this.userInfo_.activeUser] || 0; |
+ if (account) { |
+ var index = this.userSessionIndex_[account] || 0; |
if (index > 0) { |
- params.push(new HttpParam('user', index)); |
+ url += '&user=' + index; |
} |
} |
} |
@@ -356,7 +374,7 @@ cr.define('cloudprint', function() { |
xhr.setRequestHeader(header, headers[header]); |
} |
- return new CloudPrintRequest(xhr, body, origin, callback); |
+ return new CloudPrintRequest(xhr, body, origin, account, callback); |
}, |
/** |
@@ -407,6 +425,49 @@ cr.define('cloudprint', function() { |
}, |
/** |
+ * Updates user info and session index from the {@code request} response. |
+ * @param {!CloudPrintRequest} request Request to extract user info from. |
+ * @private |
+ */ |
+ setUsers_: function(request) { |
+ if (request.origin == print_preview.Destination.Origin.COOKIES) { |
+ var activeUser = request.result['request']['user']; |
Toscano
2014/04/11 04:24:00
Maybe move this to right above line 440 since it's
Aleksey Shlyapnikov
2014/04/11 19:09:29
Done.
|
+ var users = request.result['request']['users'] || []; |
+ this.userSessionIndex_ = {}; |
+ for (var i = 0; i < users.length; i++) { |
+ this.userSessionIndex_[users[i]] = i; |
+ } |
+ this.userInfo_.setUsers(activeUser, users); |
+ } |
+ }, |
+ |
+ /** |
+ * Terminates search requests for requested {@code origins}. |
+ * @param {!Array.<print_preview.Destination.Origin>} origins Origins |
+ * to terminate search requests for. |
+ * @private |
+ */ |
+ abortSearchRequests_: function(origins) { |
+ this.outstandingCloudSearchRequests_ = |
+ this.outstandingCloudSearchRequests_.filter(function(request) { |
+ if (origins.indexOf(request.origin) >= 0) { |
+ request.xhr.abort(); |
+ return false; |
+ } |
+ return true; |
+ }); |
+ }, |
+ |
+ /** |
+ * Called when active user account changes. Terminates all outstanding |
+ * cookie based search requests. |
+ * @private |
+ */ |
+ onActiveUserChanged_: function() { |
+ this.abortSearchRequests_([print_preview.Destination.Origin.COOKIES]); |
Toscano
2014/04/11 04:24:00
Hmm, wouldn't it be simpler to only abort if and o
Aleksey Shlyapnikov
2014/04/11 19:09:29
The thing is, search request reply _is_ the source
Toscano
2014/04/12 02:09:08
But wait, how can you change the user if the first
Aleksey Shlyapnikov
2014/04/12 03:44:03
It's assumed that all search requests issued under
|
+ }, |
+ |
+ /** |
* Called when a native layer receives access token. |
* @param {Event} evt Contains the authentication type and access token. |
* @private |
@@ -424,7 +485,7 @@ cr.define('cloudprint', function() { |
'Bearer ' + event.accessToken); |
this.sendRequest_(request); |
} else { // No valid token. |
- // Without abort status does not exists. |
+ // Without abort status does not exist. |
request.xhr.abort(); |
request.callback(request); |
} |
@@ -443,8 +504,9 @@ cr.define('cloudprint', function() { |
if (request.xhr.status == 200) { |
request.result = JSON.parse(request.xhr.responseText); |
if (request.origin == print_preview.Destination.Origin.COOKIES && |
- request.result['success']) { |
- this.xsrfToken_ = request.result['xsrf_token']; |
+ request.result['success'] && |
+ request.account) { |
+ this.xsrfTokens_[request.account] = request.result['xsrf_token']; |
} |
} |
request.status = request.xhr.status; |
@@ -460,15 +522,21 @@ cr.define('cloudprint', function() { |
* @private |
*/ |
onSearchDone_: function(isRecent, request) { |
+ var lastRequestForThisOrigin = true; |
this.outstandingCloudSearchRequests_ = |
this.outstandingCloudSearchRequests_.filter(function(item) { |
+ if (item != request && item.origin == request.origin) { |
+ lastRequestForThisOrigin = false; |
+ } |
return item != request; |
}); |
+ var activeUser = ''; |
+ if (request.origin == print_preview.Destination.Origin.COOKIES) { |
+ activeUser = request.result['request']['user']; |
+ } |
+ var event = null; |
if (request.xhr.status == 200 && request.result['success']) { |
- var activeUser = ''; |
- if (request.origin == print_preview.Destination.Origin.COOKIES) { |
- activeUser = request.result['request']['user']; |
- } |
+ // Extract printers. |
var printerListJson = request.result['printers'] || []; |
var printerList = []; |
printerListJson.forEach(function(printerJson) { |
@@ -479,25 +547,21 @@ cr.define('cloudprint', function() { |
console.error('Unable to parse cloud print destination: ' + err); |
} |
}); |
- var searchDoneEvent = |
- new Event(CloudPrintInterface.EventType.SEARCH_DONE); |
- searchDoneEvent.printers = printerList; |
- searchDoneEvent.origin = request.origin; |
- searchDoneEvent.isRecent = isRecent; |
- if (request.origin == print_preview.Destination.Origin.COOKIES) { |
- var users = request.result['request']['users'] || []; |
- this.userSessionIndex_ = {}; |
- for (var i = 0; i < users.length; i++) { |
- this.userSessionIndex_[users[i]] = i; |
- } |
- this.userInfo_.setUsers(activeUser, users); |
- } |
- this.dispatchEvent(searchDoneEvent); |
+ // Extract users. |
+ this.setUsers_(request); |
Vitaly Buka (NO REVIEWS)
2014/04/11 02:32:57
setUsers_ -> extractUsers_
Aleksey Shlyapnikov
2014/04/11 19:09:29
It updates userInfo_ state, not just extracts user
|
+ // Dispatch SEARCH_DONE event. |
+ event = new Event(CloudPrintInterface.EventType.SEARCH_DONE); |
+ event.origin = request.origin; |
+ event.printers = printerList; |
+ event.isRecent = isRecent; |
} else { |
- var errorEvent = this.createErrorEvent_( |
- CloudPrintInterface.EventType.SEARCH_FAILED, request); |
- this.dispatchEvent(errorEvent); |
+ event = this.createErrorEvent_( |
+ CloudPrintInterface.EventType.SEARCH_FAILED, |
+ request); |
} |
+ event.user = activeUser; |
+ event.searchDone = lastRequestForThisOrigin; |
+ this.dispatchEvent(event); |
}, |
/** |
@@ -525,6 +589,29 @@ cr.define('cloudprint', function() { |
* @private |
*/ |
onPrinterDone_: function(destinationId, request) { |
+ // Special handling of the first printer request. It does not matter at |
+ // this point, whether printer was found or not. |
+ if (request.origin == print_preview.Destination.Origin.COOKIES && |
+ request.account && |
+ request.result['request']['user'] && |
+ request.result['request']['users'] && |
+ request.account != request.result['request']['user']) { |
+ var users = request.result['request']['users']; |
Toscano
2014/04/11 04:24:00
Let's keep user parsing logic in place. Why not th
Aleksey Shlyapnikov
2014/04/11 19:09:29
Done.
On 2014/04/11 04:24:00, Toscano wrote:
|
+ // In case the user account is known, but not the primary one, |
+ // activate it. |
+ if (users.indexOf(request.account) > 0) { |
+ this.setUsers_(request); |
+ this.userInfo_.activeUser = request.account; |
+ // Repeat the request for the newly activated account. |
+ this.printer( |
+ request.result['request']['params']['printerid'], |
+ request.origin, |
+ request.account); |
+ // Stop processing this request, wait for the new response. |
+ return; |
+ } |
+ } |
+ // Process response. |
if (request.xhr.status == 200 && request.result['success']) { |
var activeUser = ''; |
if (request.origin == print_preview.Destination.Origin.COOKIES) { |
@@ -574,11 +661,14 @@ cr.define('cloudprint', function() { |
* @param {!XMLHttpRequest} xhr Partially prepared http request. |
* @param {string} body Data to send with POST requests. |
* @param {!print_preview.Destination.Origin} origin Origin for destination. |
+ * @param {?string} account Account the request is sent for. Can be |
+ * {@code null} or empty string if the request is not cookie bound or |
+ * is sent on behalf of the primary user. |
Toscano
2014/04/11 04:24:00
If it's nullable, maybe it should be opt_account?
Aleksey Shlyapnikov
2014/04/11 19:09:29
I don't see the benefit of optional here, it's a p
|
* @param {function(!CloudPrintRequest)} callback Callback to invoke when |
* request completes. |
* @constructor |
*/ |
- function CloudPrintRequest(xhr, body, origin, callback) { |
+ function CloudPrintRequest(xhr, body, origin, account, callback) { |
/** |
* Partially prepared http request. |
* @type {!XMLHttpRequest} |
@@ -598,6 +688,12 @@ cr.define('cloudprint', function() { |
this.origin = origin; |
/** |
+ * User account this request is expected to be executed for. |
+ * @type {?string} |
+ */ |
+ this.account = account; |
+ |
+ /** |
* Callback to invoke when request completes. |
* @type {function(!CloudPrintRequest)} |
*/ |