Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2057)

Unified Diff: appengine/monorail/static/js/framework/framework-ajax.js

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/monorail/static/js/framework/framework-ajax.js
diff --git a/appengine/monorail/static/js/framework/framework-ajax.js b/appengine/monorail/static/js/framework/framework-ajax.js
new file mode 100644
index 0000000000000000000000000000000000000000..6b1136b1965b7939c5952e2c98a0f1ff0134d897
--- /dev/null
+++ b/appengine/monorail/static/js/framework/framework-ajax.js
@@ -0,0 +1,136 @@
+/* Copyright 2016 The Chromium Authors. All Rights Reserved.
+ *
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file or at
+ * https://developers.google.com/open-source/licenses/bsd
+ */
+
+
+/**
+ * @fileoverview AJAX-related helper functions.
+ */
+
+
+/**
+ * Builds a POST string from a parameter dictionary.
+ * @param {Object} args parameters to encode.
+ * @param {boolean} opt_includeToken whether to include an XSRF token.
+ * If unspecified, defaults to true. Requires the user to be logged in.
+ * @return {string} encoded POST data.
+ */
+function CS_postData(args, opt_token) {
+ var params = [];
+ for (var key in args) {
+ params.push(key + "=" + encodeURIComponent(String(args[key])));
+ }
+ if (opt_token) {
+ params.push('token=' + encodeURIComponent(opt_token));
+ } else if (opt_token !== false) {
+ params.push('token=' + encodeURIComponent(CS_env.token));
+ }
+ return params.join('&');
+}
+
+/**
+ * Helper for an extremely common kind of XHR: a POST with an XHRF token
+ * where we silently ignore server or connectivity errors. If the token
+ * has expired, get a new one and retry the original request with the new
+ * token.
+ * @param {string} url request destination.
+ * @param {function(event)} callback function to be called
+ * upon successful completion of the request.
+ * @param {Object} args parameters to encode as POST data.
+ */
+function CS_doPost(url, callback, args, opt_token, opt_tokenPath) {
+ if (isTokenExpired()) {
+ var refreshXHR = XH_XmlHttpCreate();
+ var refreshURL = '/hosting/tokenRefresh.do';
+ var refreshArgs = {
+ form_token: opt_token || CS_env.token,
+ form_token_path: opt_tokenPath || 'xhr'
+ };
+ var refreshCallback = function(event) {
+ var xhr = event.target;
+ if (xhr.readyState != 4 || xhr.status != 200)
+ return;
+ var resp = CS_parseJSON(xhr);
+ if (opt_tokenPath)
+ CS_env[opt_tokenPath] = resp.form_token;
+ CS_env.tokenExpiresSec = Number(resp.token_expires_sec);
+ var retryXh = XH_XmlHttpCreate();
+ XH_XmlHttpPOST(
+ retryXh, url, CS_postData(args, resp.form_token), callback);
+ };
+ XH_XmlHttpPOST(
+ refreshXHR, refreshURL, CS_postData(refreshArgs), refreshCallback);
+ } else {
+ var xh = XH_XmlHttpCreate();
+ XH_XmlHttpPOST(
+ xh, url,
+ CS_postData(args, CS_env[opt_tokenPath] || opt_token),
+ callback);
+ }
+}
+
+
+/**
+ * Helper function to strip leading junk characters from a JSON response
+ * and then parse it into a JS constant.
+ *
+ * The reason that "}])'\n" is prepended to the response text is that
+ * it makes it impossible for a hacker to hit one of our JSON servlets
+ * via a <script src="..."> tag and do anything with the result. Even
+ * though a JSON response is just a constant, it could be passed into
+ * hacker code by tricks such as overriding the array constructor.
+ */
+function CS_parseJSON(xhr) {
+ return JSON.parse(xhr.responseText.substr(5));
+}
+
+
+function isTokenExpired(opt_tokenExpiresSec) {
+ var expiresSec = opt_tokenExpiresSec || CS_env.tokenExpiresSec;
+ var tokenExpiresDate = new Date(expiresSec * 1000);
+ return tokenExpiresDate <= new Date();
+}
+
+/**
+ * After we refresh the form token, we need to actually submit the form.
+ * formToSubmit keeps track of which form the user was trying to submit.
+ */
+var formToSubmit = null;
+
+/**
+ * If the form token that was generated when the page was served has
+ * now expired, then request a refreshed token from the server, and
+ * don't submit the form until after it arrives.
+ */
+function refreshTokens(event, formToken, formTokenPath, tokenExpiresSec) {
+ if (!isTokenExpired(tokenExpiresSec))
+ return;
+
+ formToSubmit = event.target;
+ event.preventDefault();
+ CS_doPost("/hosting/tokenRefresh.do", gotXSRFToken,
+ {form_token: formToken,
+ form_token_path: formTokenPath});
+}
+
+/**
+ * If we got a new XSRF token from the server, use it to actually
+ * submit the form that the user wanted to submit.
+ */
+function gotXSRFToken(event) {
+ var xhr = event.target;
+ if (xhr.readyState != 4 || xhr.status != 200)
+ return;
+ var resp = CS_parseJSON(xhr);
+ var freshFormToken = resp["form_token"];
+ var tokenFields = document.querySelectorAll("input[name=token]");
+ for (var i = 0; i < tokenFields.length; ++i) {
+ tokenFields[i].value = freshFormToken;
+ }
+ if (formToSubmit) {
+ formToSubmit.submit();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698