From 227752282b434c2d35d1b139f24ea979c40cac6a Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Wed, 31 Jan 2018 15:20:09 -0500
Subject: [PATCH 01/13] respect the whitelist of actions specified in meta tags

---
 src/service/standard-actions-impl.js     | 17 ++++++-
 test/functional/test-standard-actions.js | 59 ++++++++++++++++++++++++
 2 files changed, 75 insertions(+), 1 deletion(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index 950fd62e9211..d2e82f424116 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -68,6 +68,17 @@ export class StandardActions {
     /** @const @private {!./viewport/viewport-impl.Viewport} */
     this.viewport_ = Services.viewportForDoc(ampdoc);
 
+    // A meta[name="amp-action-whitelist"] tag, if present, contains, 
+    // in its content attribute, a whitelist of actions on the special AMP target. 
+    const meta =
+        this.ampdoc.getRootNode().head.querySelector('meta[name="amp-action-whitelist"]');
+    // Cache the whitelist of allowed AMP actions (if provided).
+    if (meta) {
+      /** @const @private {!Array<string>} */
+      this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
+          .map(action => action.trim());
+    }
+
     this.installActions_(this.actions_);
   }
 
@@ -101,10 +112,14 @@ export class StandardActions {
    * @param {number=} opt_actionIndex
    * @param {!Array<!./action-impl.ActionInfoDef>=} opt_actionInfos
    * @return {?Promise}
-   * @throws {Error} If action is not recognized.
+   * @throws {Error} If action is not recognized or is not whitelisted.
    */
   handleAmpTarget(invocation, opt_actionIndex, opt_actionInfos) {
     const method = invocation.method;
+    if (this.ampActionWhitelist_ &&
+      !this.ampActionWhitelist_.includes(method)) {
+      throw user().createError('AMP action', method, 'is not whitelisted');
+    }
     switch (method) {
       case 'pushState':
       case 'setState':
diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index 922fe1e1ff69..c08ac0a57f0d 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -20,6 +20,7 @@ import {StandardActions} from '../../src/service/standard-actions-impl';
 import {Services} from '../../src/services';
 import {installHistoryServiceForDoc} from '../../src/service/history-impl';
 import {setParentWindow} from '../../src/service';
+import {createElementWithAttributes} from '../../src/dom';
 
 
 describes.sandboxed('StandardActions', {}, () => {
@@ -352,6 +353,64 @@ describes.sandboxed('StandardActions', {}, () => {
       standardActions.handleAmpTarget(invocation);
       expect(printStub).to.be.calledOnce;
     });
+
+    it('should not implement print when not whitelisted', () => {
+      window.document.head.appendChild(
+          createElementWithAttributes(window.document, 'meta', {
+            name: 'amp-action-whitelist',
+            content: 'pushState,setState',
+          }));
+
+      standardActions = new StandardActions(ampdoc);
+
+      const windowApi = {
+        print: () => {},
+      };
+      const printStub = sandbox.stub(windowApi, 'print');
+      const invocation = {
+        method: 'print',
+        satisfiesTrust: () => true,
+        target: {
+          ownerDocument: {
+            defaultView: windowApi,
+          },
+        },
+      };
+      expect(() => standardActions.handleAmpTarget(invocation)).to.throw();
+      expect(printStub).to.not.be.called;
+    });
+
+    it('should implement pushState when whitelisted', () => {
+      window.document.head.appendChild(
+          createElementWithAttributes(window.document, 'meta', {
+            name: 'amp-action-whitelist',
+            content: 'setState, pushState',
+          }));
+
+      standardActions = new StandardActions(ampdoc);
+
+      const pushStateWithExpression = sandbox.stub();
+      // Bind.pushStateWithExpression() doesn't resolve with a value,
+      // but add one here to check that the promise is chained.
+      pushStateWithExpression.returns(Promise.resolve('push-state-complete'));
+
+      window.services.bind = {
+        obj: {pushStateWithExpression},
+      };
+
+      const args = {
+        [OBJECT_STRING_ARGS_KEY]: '{foo: 123}',
+      };
+      const target = ampdoc;
+      const satisfiesTrust = () => true;
+      const pushState = {method: 'pushState', args, target, satisfiesTrust};
+
+      return standardActions.handleAmpTarget(pushState, 0, []).then(result => {
+        expect(result).to.equal('push-state-complete');
+        expect(pushStateWithExpression).to.be.calledOnce;
+        expect(pushStateWithExpression).to.be.calledWith('{foo: 123}');
+      });
+    });
   });
 
   describes.fakeWin('adoptEmbedWindow', {}, env => {

From d68b396da0002220766c1451221a3e24e9415aa6 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Wed, 31 Jan 2018 16:18:10 -0500
Subject: [PATCH 02/13] fixed the failing tests

---
 src/service/standard-actions-impl.js | 15 +++++++++------
 1 file changed, 9 insertions(+), 6 deletions(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index d2e82f424116..d9c2e7d9584d 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -70,13 +70,16 @@ export class StandardActions {
 
     // A meta[name="amp-action-whitelist"] tag, if present, contains, 
     // in its content attribute, a whitelist of actions on the special AMP target. 
-    const meta =
+    if(this.ampdoc.getRootNode() && this.ampdoc.getRootNode().head) {
+      const meta =
         this.ampdoc.getRootNode().head.querySelector('meta[name="amp-action-whitelist"]');
-    // Cache the whitelist of allowed AMP actions (if provided).
-    if (meta) {
-      /** @const @private {!Array<string>} */
-      this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
-          .map(action => action.trim());
+    
+      // Cache the whitelist of allowed AMP actions (if provided).
+      if (meta) {
+        /** @const @private {!Array<string>} */
+        this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
+            .map(action => action.trim());
+      }
     }
 
     this.installActions_(this.actions_);

From f1dd89b066e2165625582391c69e6051567e4b31 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Wed, 31 Jan 2018 16:32:06 -0500
Subject: [PATCH 03/13] lint fix

---
 src/service/standard-actions-impl.js | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index d9c2e7d9584d..b3b481682a35 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -68,12 +68,13 @@ export class StandardActions {
     /** @const @private {!./viewport/viewport-impl.Viewport} */
     this.viewport_ = Services.viewportForDoc(ampdoc);
 
-    // A meta[name="amp-action-whitelist"] tag, if present, contains, 
-    // in its content attribute, a whitelist of actions on the special AMP target. 
-    if(this.ampdoc.getRootNode() && this.ampdoc.getRootNode().head) {
+    // A meta[name="amp-action-whitelist"] tag, if present, contains,
+    // in its content attribute, a whitelist of actions on the special AMP target.
+    if (this.ampdoc.getRootNode() && this.ampdoc.getRootNode().head) {
       const meta =
-        this.ampdoc.getRootNode().head.querySelector('meta[name="amp-action-whitelist"]');
-    
+        this.ampdoc.getRootNode().head
+            .querySelector('meta[name="amp-action-whitelist"]');
+
       // Cache the whitelist of allowed AMP actions (if provided).
       if (meta) {
         /** @const @private {!Array<string>} */

From 3d5b478cd40703a7e1dd43ce32681add13068a19 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Tue, 6 Feb 2018 17:53:39 -0500
Subject: [PATCH 04/13] Fixed some of the concerns in the review

---
 src/service/standard-actions-impl.js     | 38 ++++++++++++++++--------
 test/functional/test-standard-actions.js |  4 +--
 2 files changed, 28 insertions(+), 14 deletions(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index b3b481682a35..cf377a6f44ec 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -68,24 +68,34 @@ export class StandardActions {
     /** @const @private {!./viewport/viewport-impl.Viewport} */
     this.viewport_ = Services.viewportForDoc(ampdoc);
 
-    // A meta[name="amp-action-whitelist"] tag, if present, contains,
-    // in its content attribute, a whitelist of actions on the special AMP target.
-    if (this.ampdoc.getRootNode() && this.ampdoc.getRootNode().head) {
+    /** @const @private {?Array<string>} */
+    this.ampActionWhitelist_ = null;
+
+    this.installActions_(this.actions_);
+  }
+
+  /**
+   * @return {?Array<string>} the whitelist of allowed AMP actions
+   * (if provided in a meta tag).
+   * @private
+   */
+  createWhitelist_() {
+    const head = this.ampdoc.getRootNode().head;
+    if (head) {
+      // A meta[name="amp-action-whitelist"] tag, if present, contains,
+      // in its content attribute, a whitelist of actions on the special AMP target.
       const meta =
-        this.ampdoc.getRootNode().head
-            .querySelector('meta[name="amp-action-whitelist"]');
+        head.querySelector('meta[name="amp-action-whitelist"]');
 
-      // Cache the whitelist of allowed AMP actions (if provided).
       if (meta) {
-        /** @const @private {!Array<string>} */
-        this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
+        return meta.getAttribute('content').split(',')
             .map(action => action.trim());
       }
     }
-
-    this.installActions_(this.actions_);
+    return null;
   }
 
+
   /** @override */
   adoptEmbedWindow(embedWin) {
     this.installActions_(Services.actionServiceForDoc(embedWin.document));
@@ -119,10 +129,14 @@ export class StandardActions {
    * @throws {Error} If action is not recognized or is not whitelisted.
    */
   handleAmpTarget(invocation, opt_actionIndex, opt_actionInfos) {
+    if (!this.ampActionWhitelist_) {
+      // Cache the whitelist of allowed AMP actions (if provided).
+      this.ampActionWhitelist_ = this.createWhitelist_();
+    }
     const method = invocation.method;
     if (this.ampActionWhitelist_ &&
-      !this.ampActionWhitelist_.includes(method)) {
-      throw user().createError('AMP action', method, 'is not whitelisted');
+      !this.ampActionWhitelist_.includes('AMP.' + method)) {
+      throw user().createError('AMP.${method}$ is not whitelisted.');
     }
     switch (method) {
       case 'pushState':
diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index c08ac0a57f0d..e87b5227031d 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -358,7 +358,7 @@ describes.sandboxed('StandardActions', {}, () => {
       window.document.head.appendChild(
           createElementWithAttributes(window.document, 'meta', {
             name: 'amp-action-whitelist',
-            content: 'pushState,setState',
+            content: 'AMP.pushState,AMP.setState',
           }));
 
       standardActions = new StandardActions(ampdoc);
@@ -384,7 +384,7 @@ describes.sandboxed('StandardActions', {}, () => {
       window.document.head.appendChild(
           createElementWithAttributes(window.document, 'meta', {
             name: 'amp-action-whitelist',
-            content: 'setState, pushState',
+            content: 'AMP.setState, AMP.pushState',
           }));
 
       standardActions = new StandardActions(ampdoc);

From 08dcca557edf8a4ccf38737bd645f2c11742172e Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Tue, 6 Feb 2018 19:47:15 -0500
Subject: [PATCH 05/13] Faking the window

---
 test/functional/test-standard-actions.js | 23 +++++++++++------------
 1 file changed, 11 insertions(+), 12 deletions(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index e87b5227031d..1115041e4e52 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -355,14 +355,13 @@ describes.sandboxed('StandardActions', {}, () => {
     });
 
     it('should not implement print when not whitelisted', () => {
-      window.document.head.appendChild(
-          createElementWithAttributes(window.document, 'meta', {
-            name: 'amp-action-whitelist',
-            content: 'AMP.pushState,AMP.setState',
-          }));
-
+      const fakeMeta = {
+          getAttribute: (key) => 'AMP.pushState,AMP.setState',
+      }
+      const querySelectorStub = sandbox.stub(window.document.head,
+          'querySelector').callsFake(selector => fakeMeta);
       standardActions = new StandardActions(ampdoc);
-
+      
       const windowApi = {
         print: () => {},
       };
@@ -381,11 +380,11 @@ describes.sandboxed('StandardActions', {}, () => {
     });
 
     it('should implement pushState when whitelisted', () => {
-      window.document.head.appendChild(
-          createElementWithAttributes(window.document, 'meta', {
-            name: 'amp-action-whitelist',
-            content: 'AMP.setState, AMP.pushState',
-          }));
+      const fakeMeta = {
+          getAttribute: (key) => 'AMP.setState,AMP.pushState',
+      }
+      const querySelectorStub = sandbox.stub(window.document.head,
+          'querySelector').callsFake(selector => fakeMeta);
 
       standardActions = new StandardActions(ampdoc);
 

From 96a0132c1b49468463eb88c9d18425be18069a76 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Wed, 7 Feb 2018 10:32:28 -0500
Subject: [PATCH 06/13] ran lint --fix

---
 test/functional/test-standard-actions.js | 19 +++++++++----------
 1 file changed, 9 insertions(+), 10 deletions(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index 1115041e4e52..a5c8fe2d84e5 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -20,7 +20,6 @@ import {StandardActions} from '../../src/service/standard-actions-impl';
 import {Services} from '../../src/services';
 import {installHistoryServiceForDoc} from '../../src/service/history-impl';
 import {setParentWindow} from '../../src/service';
-import {createElementWithAttributes} from '../../src/dom';
 
 
 describes.sandboxed('StandardActions', {}, () => {
@@ -356,12 +355,12 @@ describes.sandboxed('StandardActions', {}, () => {
 
     it('should not implement print when not whitelisted', () => {
       const fakeMeta = {
-          getAttribute: (key) => 'AMP.pushState,AMP.setState',
-      }
-      const querySelectorStub = sandbox.stub(window.document.head,
-          'querySelector').callsFake(selector => fakeMeta);
+        getAttribute: () => 'AMP.pushState,AMP.setState',
+      };
+      sandbox.stub(window.document.head,
+          'querySelector').callsFake(() => fakeMeta);
       standardActions = new StandardActions(ampdoc);
-      
+
       const windowApi = {
         print: () => {},
       };
@@ -381,10 +380,10 @@ describes.sandboxed('StandardActions', {}, () => {
 
     it('should implement pushState when whitelisted', () => {
       const fakeMeta = {
-          getAttribute: (key) => 'AMP.setState,AMP.pushState',
-      }
-      const querySelectorStub = sandbox.stub(window.document.head,
-          'querySelector').callsFake(selector => fakeMeta);
+        getAttribute: () => 'AMP.setState,AMP.pushState',
+      };
+      sandbox.stub(window.document.head,
+          'querySelector').callsFake(() => fakeMeta);
 
       standardActions = new StandardActions(ampdoc);
 

From 191e70839dcbde35e74b19123990c5b5f1d96bb9 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Wed, 7 Feb 2018 11:21:13 -0500
Subject: [PATCH 07/13] simplifying the functional tests

---
 test/functional/test-standard-actions.js | 28 ++++++++----------------
 1 file changed, 9 insertions(+), 19 deletions(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index a5c8fe2d84e5..defc0400d3e2 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -387,27 +387,17 @@ describes.sandboxed('StandardActions', {}, () => {
 
       standardActions = new StandardActions(ampdoc);
 
-      const pushStateWithExpression = sandbox.stub();
-      // Bind.pushStateWithExpression() doesn't resolve with a value,
-      // but add one here to check that the promise is chained.
-      pushStateWithExpression.returns(Promise.resolve('push-state-complete'));
-
-      window.services.bind = {
-        obj: {pushStateWithExpression},
-      };
-
-      const args = {
-        [OBJECT_STRING_ARGS_KEY]: '{foo: 123}',
+      const handleAmpBindActionStub =
+        sandbox.stub(standardActions, 'handleAmpBindAction_');
+      const invocation = {
+        method: 'pushState',
+        satisfiesTrust: () => true,
+        target: ampdoc,
       };
-      const target = ampdoc;
-      const satisfiesTrust = () => true;
-      const pushState = {method: 'pushState', args, target, satisfiesTrust};
 
-      return standardActions.handleAmpTarget(pushState, 0, []).then(result => {
-        expect(result).to.equal('push-state-complete');
-        expect(pushStateWithExpression).to.be.calledOnce;
-        expect(pushStateWithExpression).to.be.calledWith('{foo: 123}');
-      });
+      expect(() =>
+        standardActions.handleAmpTarget(invocation, 0, [])).to.not.throw();
+      expect(handleAmpBindActionStub).to.be.calledOnce;
     });
   });
 

From 21362cde2131d7aa41079850960e507b3eb641d6 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Fri, 9 Feb 2018 16:28:35 -0500
Subject: [PATCH 08/13] more code review fixes

---
 src/service/standard-actions-impl.js | 34 ++++++++++++++++------------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index cf377a6f44ec..7b784bf226f7 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -75,24 +75,28 @@ export class StandardActions {
   }
 
   /**
-   * @return {?Array<string>} the whitelist of allowed AMP actions
-   * (if provided in a meta tag).
+   * Searches for a meta tag containing whitelist of actions on
+   * the special AMP target, e.g.,
+   * <meta name="amp-action-whitelist" content="AMP.setState,AMP.pushState">
+   * @return {?Array<string>} the whitelist of actions on the
+   * special AMP target.
    * @private
    */
   createWhitelist_() {
     const head = this.ampdoc.getRootNode().head;
-    if (head) {
-      // A meta[name="amp-action-whitelist"] tag, if present, contains,
-      // in its content attribute, a whitelist of actions on the special AMP target.
-      const meta =
-        head.querySelector('meta[name="amp-action-whitelist"]');
-
-      if (meta) {
-        return meta.getAttribute('content').split(',')
-            .map(action => action.trim());
-      }
+    if (!head) {
+      return null;
     }
-    return null;
+    // A meta[name="amp-action-whitelist"] tag, if present, contains,
+    // in its content attribute, a whitelist of actions on the special AMP target.
+    const meta =
+      head.querySelector('meta[name="amp-action-whitelist"]');
+    if (!meta) {
+      return null;
+    }
+
+    return meta.getAttribute('content').split(',')
+        .map(action => action.trim());
   }
 
 
@@ -135,8 +139,8 @@ export class StandardActions {
     }
     const method = invocation.method;
     if (this.ampActionWhitelist_ &&
-      !this.ampActionWhitelist_.includes('AMP.' + method)) {
-      throw user().createError('AMP.${method}$ is not whitelisted.');
+      !this.ampActionWhitelist_.includes(`AMP.${method}`)) {
+      throw user().createError(`AMP.${method}$ is not whitelisted.`);
     }
     switch (method) {
       case 'pushState':

From 792386e165602a611e68584f1149269aa39a46bf Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Fri, 9 Feb 2018 17:01:45 -0500
Subject: [PATCH 09/13] using real window in test

---
 test/functional/test-standard-actions.js | 34 +++++++++++++-----------
 1 file changed, 19 insertions(+), 15 deletions(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index defc0400d3e2..41d9c46e696b 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -20,7 +20,7 @@ import {StandardActions} from '../../src/service/standard-actions-impl';
 import {Services} from '../../src/services';
 import {installHistoryServiceForDoc} from '../../src/service/history-impl';
 import {setParentWindow} from '../../src/service';
-
+import {createElementWithAttributes} from '../../src/dom';
 
 describes.sandboxed('StandardActions', {}, () => {
   let standardActions;
@@ -352,14 +352,23 @@ describes.sandboxed('StandardActions', {}, () => {
       standardActions.handleAmpTarget(invocation);
       expect(printStub).to.be.calledOnce;
     });
+  });
+
+  describes.realWin('#whitelist', {
+    amp: {
+      ampdoc: 'single',
+    },
+  }, env => {
+    beforeEach(() => {
+      env.win.document.head.appendChild(
+          createElementWithAttributes(env.win.document, 'meta', {
+            name: 'amp-action-whitelist',
+            content: 'AMP.pushState,AMP.setState',
+          }));
+    });
 
     it('should not implement print when not whitelisted', () => {
-      const fakeMeta = {
-        getAttribute: () => 'AMP.pushState,AMP.setState',
-      };
-      sandbox.stub(window.document.head,
-          'querySelector').callsFake(() => fakeMeta);
-      standardActions = new StandardActions(ampdoc);
+      standardActions = new StandardActions(env.ampdoc);
 
       const windowApi = {
         print: () => {},
@@ -379,26 +388,21 @@ describes.sandboxed('StandardActions', {}, () => {
     });
 
     it('should implement pushState when whitelisted', () => {
-      const fakeMeta = {
-        getAttribute: () => 'AMP.setState,AMP.pushState',
-      };
-      sandbox.stub(window.document.head,
-          'querySelector').callsFake(() => fakeMeta);
-
-      standardActions = new StandardActions(ampdoc);
+      standardActions = new StandardActions(env.ampdoc);
 
       const handleAmpBindActionStub =
         sandbox.stub(standardActions, 'handleAmpBindAction_');
       const invocation = {
         method: 'pushState',
         satisfiesTrust: () => true,
-        target: ampdoc,
+        target: env.ampdoc,
       };
 
       expect(() =>
         standardActions.handleAmpTarget(invocation, 0, [])).to.not.throw();
       expect(handleAmpBindActionStub).to.be.calledOnce;
     });
+
   });
 
   describes.fakeWin('adoptEmbedWindow', {}, env => {

From 94ebecaef65664fe40721d1012c3311c3c7c266c Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Tue, 13 Feb 2018 11:59:01 -0500
Subject: [PATCH 10/13] a few suggestions by Su

---
 src/service/standard-actions-impl.js     | 22 +++++++++++-----------
 test/functional/test-standard-actions.js |  2 +-
 2 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index 7b784bf226f7..3e20e757e99e 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -78,11 +78,14 @@ export class StandardActions {
    * Searches for a meta tag containing whitelist of actions on
    * the special AMP target, e.g.,
    * <meta name="amp-action-whitelist" content="AMP.setState,AMP.pushState">
-   * @return {?Array<string>} the whitelist of actions on the
-   * special AMP target.
+   * @return {?Array<string>} the whitelist of actions on the special AMP target.
    * @private
    */
-  createWhitelist_() {
+  getAmpActionWhitelist_() {
+    if (this.ampActionWhitelist_) {
+      return this.ampActionWhitelist_;
+    }
+
     const head = this.ampdoc.getRootNode().head;
     if (!head) {
       return null;
@@ -95,8 +98,9 @@ export class StandardActions {
       return null;
     }
 
-    return meta.getAttribute('content').split(',')
+    this.ampActionWhitelist_ = meta.getAttribute('content').split(',')
         .map(action => action.trim());
+    return this.ampActionWhitelist_;
   }
 
 
@@ -133,14 +137,10 @@ export class StandardActions {
    * @throws {Error} If action is not recognized or is not whitelisted.
    */
   handleAmpTarget(invocation, opt_actionIndex, opt_actionInfos) {
-    if (!this.ampActionWhitelist_) {
-      // Cache the whitelist of allowed AMP actions (if provided).
-      this.ampActionWhitelist_ = this.createWhitelist_();
-    }
     const method = invocation.method;
-    if (this.ampActionWhitelist_ &&
-      !this.ampActionWhitelist_.includes(`AMP.${method}`)) {
-      throw user().createError(`AMP.${method}$ is not whitelisted.`);
+    if (this.getAmpActionWhitelist_() &&
+      !this.getAmpActionWhitelist_().includes(`AMP.${method}`)) {
+      throw user().createError(`AMP.${method} is not whitelisted.`);
     }
     switch (method) {
       case 'pushState':
diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index 41d9c46e696b..40ae61b8e73e 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -354,7 +354,7 @@ describes.sandboxed('StandardActions', {}, () => {
     });
   });
 
-  describes.realWin('#whitelist', {
+  describes.realWin('whitelist of actions on the special AMP target', {
     amp: {
       ampdoc: 'single',
     },

From 9d23e139d275f70ada3526f10f4a9ace2ddd63b2 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Thu, 22 Feb 2018 13:58:40 -0500
Subject: [PATCH 11/13] fixing import orders

---
 test/functional/test-standard-actions.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index cf19d4b40c47..7c47b0a8cc5f 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -15,12 +15,12 @@
  */
 
 import {AmpDocSingle} from '../../src/service/ampdoc-impl';
+import {createElementWithAttributes} from '../../src/dom';
 import {OBJECT_STRING_ARGS_KEY} from '../../src/service/action-impl';
 import {Services} from '../../src/services';
 import {StandardActions} from '../../src/service/standard-actions-impl';
 import {installHistoryServiceForDoc} from '../../src/service/history-impl';
 import {setParentWindow} from '../../src/service';
-import {createElementWithAttributes} from '../../src/dom';
 
 describes.sandboxed('StandardActions', {}, () => {
   let standardActions;

From d064930b06b47c03e469a1f062ed9f7658c73669 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Thu, 22 Feb 2018 14:55:14 -0500
Subject: [PATCH 12/13] fixed lint errors

---
 test/functional/test-standard-actions.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/test/functional/test-standard-actions.js b/test/functional/test-standard-actions.js
index 7c47b0a8cc5f..ff9a12db007f 100644
--- a/test/functional/test-standard-actions.js
+++ b/test/functional/test-standard-actions.js
@@ -15,10 +15,10 @@
  */
 
 import {AmpDocSingle} from '../../src/service/ampdoc-impl';
-import {createElementWithAttributes} from '../../src/dom';
 import {OBJECT_STRING_ARGS_KEY} from '../../src/service/action-impl';
 import {Services} from '../../src/services';
 import {StandardActions} from '../../src/service/standard-actions-impl';
+import {createElementWithAttributes} from '../../src/dom';
 import {installHistoryServiceForDoc} from '../../src/service/history-impl';
 import {setParentWindow} from '../../src/service';
 

From 2de17104df224a2f688fb069b0b86a9cb56fe046 Mon Sep 17 00:00:00 2001
From: hamousavi <hamousavi@users.noreply.github.com>
Date: Thu, 22 Feb 2018 17:52:59 -0500
Subject: [PATCH 13/13] removing const identifier

---
 src/service/standard-actions-impl.js | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/service/standard-actions-impl.js b/src/service/standard-actions-impl.js
index cb797529aa2d..cd915a881214 100644
--- a/src/service/standard-actions-impl.js
+++ b/src/service/standard-actions-impl.js
@@ -67,7 +67,7 @@ export class StandardActions {
     /** @const @private {!./viewport/viewport-impl.Viewport} */
     this.viewport_ = Services.viewportForDoc(ampdoc);
 
-    /** @const @private {?Array<string>} */
+    /** @private {?Array<string>} */
     this.ampActionWhitelist_ = null;
 
     this.installActions_(this.actions_);
