Repository: serverless/serverless (JavaScript)
Date: 2018-09-01 18:17:44+00:00
Task type: Bug Fix

Issue:
Cannot use " in body for scheduling
<!--
1. If you have a question and not a bug/feature request please ask it at http://forum.serverless.com
2. Please check if an issue already exists so there are no duplicates
3. Check out and follow our Guidelines: https://github.com/serverless/serverless/blob/master/CONTRIBUTING.md
4. Fill out the whole template so we have a good overview on the issue
5. Do not remove any section of the template. If something is not applicable leave it empty but leave it in the Issue
6. Please follow the template, otherwise we'll have to ask you to update it
-->

# This is a Bug Report

## Description

With the following schedule configuration:
```
      - schedule:
          rate: rate(1 minute)
          enabled: true
          input:
            path: /switch
            httpMethod: POST
            headers:
              Content-Type: application/json
            queryStringParameters: {}
            body: '{ "functionId": "..." }'
```
I get the following exception:
```
SyntaxError: Unexpected token f
    at Object.parse (native)
    at /usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/compile/events/schedule/index.js:123:41
    at Array.forEach (native)
    at /usr/local/lib/node_modules/serverless/lib/plugins/aws/deploy/compile/events/schedule/index.js:21:28
```
The `f` comes from the `functionId` in the body. If I remove the f, the error becomes `Unexpected token u` (from "unctionId").

Looking at the code, the problem is with escaping the input in `lib/plugins/aws/deploy/compile/events/schedule/index.js` in the variable `scheduleTemplate`. The quotes in the body get transformed to `\"` in `Input`, and then to `\\"` in `scheduleTemplate`. Note the missing backslash - only the original backslack gets escaped, not the quotes.

I was able to hack a quick fix together and it works (not suggesting as a fix, just to illustrate that this would fix it). The original `scheduleTemplate` was renamed to `scheduleTemplate2` before:
```
const scheduleTemplate = scheduleTemplate2.replace(/\\\\"/g, '\\\\\\"');
```

## Additional Data

* ***Serverless Framework Version you're using***: 1.4.0, also tried with 1.5.0
* ***Operating System***: Xubuntu 16.10
* ***Stack Trace***:
* ***Provider Error messages***:



Issue discussion:

Solution patch:
diff --git a/lib/plugins/aws/package/compile/events/schedule/index.js b/lib/plugins/aws/package/compile/events/schedule/index.js
index 5ec91bd4646..42cd9f9978d 100644
--- a/lib/plugins/aws/package/compile/events/schedule/index.js
+++ b/lib/plugins/aws/package/compile/events/schedule/index.js
@@ -61,6 +61,20 @@ class AwsCompileScheduledEvents {
               }
 
               if (Input && typeof Input === 'object') {
+                if (_.has(Input, 'body') && typeof Input.body === 'string') {
+                  try {
+                    Input.body = JSON.parse(Input.body);
+                  } catch (error) {
+                    const errorMessage = [
+                      'The body of the schedule event associated with',
+                      ` ${functionName} was passed as a string`,
+                      ' but it failed to parse to a JSON object.',
+                      ' Please check the docs for more info.',
+                    ].join('');
+                    throw new this.serverless.classes
+                      .Error(errorMessage);
+                  }
+                }
                 Input = JSON.stringify(Input);
               }
               if (Input && typeof Input === 'string') {


Test patch:
diff --git a/lib/plugins/aws/package/compile/events/schedule/index.test.js b/lib/plugins/aws/package/compile/events/schedule/index.test.js
index bb3eb72a0c6..af6a7d0befd 100644
--- a/lib/plugins/aws/package/compile/events/schedule/index.test.js
+++ b/lib/plugins/aws/package/compile/events/schedule/index.test.js
@@ -287,6 +287,46 @@ describe('AwsCompileScheduledEvents', () => {
       expect(() => awsCompileScheduledEvents.compileScheduledEvents()).to.throw(Error);
     });
 
+    it('should not throw an error when Input body is a valid JSON string', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                input: {
+                  body: '{ "functionId": "..." }',
+                },
+              },
+            },
+          ],
+        },
+      };
+
+      expect(() => awsCompileScheduledEvents.compileScheduledEvents()).not.to.throw(Error);
+    });
+
+    it('should throw an error when Input body is an invalid JSON string', () => {
+      awsCompileScheduledEvents.serverless.service.functions = {
+        first: {
+          events: [
+            {
+              schedule: {
+                rate: 'rate(10 minutes)',
+                enabled: false,
+                input: {
+                  body: 'an invalid input body',
+                },
+              },
+            },
+          ],
+        },
+      };
+
+      expect(() => awsCompileScheduledEvents.compileScheduledEvents()).to.throw(Error);
+    });
+
     it('should not create corresponding resources when scheduled events are not given', () => {
       awsCompileScheduledEvents.serverless.service.functions = {
         first: {