Repository: fraserxu/electron-pdf (js)

Issue:
Support custom headers to be passed through
--cookies is supported, but there may be scenarios where the caller needs to pass other headers.
Therefore, a new `--requestHeaders` option (`-r` for short) is required.

Pull request:
Fixes #236, add --requestHeaders option

Patch:
diff --git a/README.md b/README.md
index c43211a..d6c5dbc 100644
--- a/README.md
+++ b/README.md
@@ -255,6 +255,8 @@ available from the Electron API.  See the following options for usage.
                                  false - default
     -p | --pageSize            String - Can be A3, A4, A5, Legal, Letter, Tabloid or an Object containing height and width in microns
                                 "A4" - default
+    -r | --requestHeaders      String - A valid JSON String that will be parsed into an Object where each key/value pair is: <headerName>: <headerValue>
+                                 Example: '{"Authorization": "Bearer token", "X-Custom-Header": "Hello World"}'  
     -l | --landscape           Boolean - true for landscape, false for portrait (don't pass a string on the CLI, just the `-l` flag)
                                  false - default
     -m | --marginsType          Integer - Specify the type of margins to use
diff --git a/lib/exportJob.js b/lib/exportJob.js
index 5eb2d20..39b264d 100644
--- a/lib/exportJob.js
+++ b/lib/exportJob.js
@@ -382,18 +382,24 @@ class ExportJob extends EventEmitter {
    * @private
    */
   _loadURL (window, url) {
-    const loadOpts = {}
-    loadOpts.extraHeaders = ''
-    if (this.args.acceptLanguage) {
-      loadOpts.extraHeaders += `Accept-Language: ${this.args.acceptLanguage}\n`
-    }
-    if (this.args.disableCache) {
-      loadOpts.extraHeaders += 'pragma: no-cache\n'
+    const loadOpts = {
+      extraHeaders: _.join(this._getHeaders(), '\n')
     }
     this.emit(`${RENDER_EVENT_PREFIX}loadurl`, { url: url })
     window.loadURL(wargs.urlWithArgs(url, null), loadOpts)
   }
 
+  _getHeaders () {
+    const headers = []
+    this.args.acceptLanguage && headers.push(`Accept-Language: ${this.args.acceptLanguage}`)
+    this.args.disableCache && headers.push('pragma: no-cache')
+    // Request headers to pass through
+    if (this.args.requestHeaders) {
+      _.each(JSON.parse(this.args.requestHeaders), (v, k) => headers.push(`${k}: ${v}`))
+    }
+    return headers
+  }
+
   // Page Load & Rendering
 
   /**
diff --git a/lib/options.js b/lib/options.js
index 8abea6e..8eb9f75 100644
--- a/lib/options.js
+++ b/lib/options.js
@@ -8,7 +8,10 @@ var options = {
     'output': 'o',
 
     'acceptLanguage': [],
+
+    // JSON String
     'browserConfig': [],
+
     'cookie': ['cookies'],
     'css': 'c',
     'disableCache': 'd',
@@ -18,6 +21,10 @@ var options = {
     'orientation': ['o', 'orientations'],
     'outputWait': 'w',
     'pageSize': 'p',
+
+    // JSON String of key/value pairs (e.g. `{"Authentication": "Bearer Token"}` )
+    'requestHeaders': 'r',
+
     'printBackground': 'b',
     'printSelectionOnly': 's',
     'trustRemoteContent': 't',
diff --git a/package-lock.json b/package-lock.json
index fc4bdfb..aaa0fa7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
 {
   "name": "electron-pdf",
-  "version": "4.0.0",
+  "version": "4.0.2",
   "lockfileVersion": 1,
   "requires": true,
   "dependencies": {
@@ -1907,9 +1907,9 @@
       }
     },
     "electron": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/electron/-/electron-4.0.2.tgz",
-      "integrity": "sha512-H0pmSvOVuC+Mq/+cYNXbCDBmqq5d1xYUVdBOjqGJuwuwJeP7qDHF35JA3cq+ARzq/CbwlXq98zdW6i6+x3U24g==",
+      "version": "4.0.6",
+      "resolved": "https://registry.npmjs.org/electron/-/electron-4.0.6.tgz",
+      "integrity": "sha512-r2ow/EmDibjoCNJp35mB1CcPs2xBF9fp2eoWuUOJmpVQyzdba6EnqsSD1BxwXzF9vQ5WkQ2UbfXBIvpomrdioQ==",
       "requires": {
         "@types/node": "10.12.18",
         "electron-download": "4.1.1",
diff --git a/package.json b/package.json
index 46e6122..c12f0fb 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
 {
   "name": "electron-pdf",
-  "version": "4.0.1",
+  "version": "4.0.2",
   "description": "A command line tool to generate PDF from URL, HTML or Markdown files",
   "main": "lib/index.js",
   "scripts": {
@@ -45,7 +45,7 @@
   "dependencies": {
     "async": "^2.0.1",
     "debug": "^2.3.2",
-    "electron": "4.0.2",
+    "electron": "4.0.6",
     "eventemitter2": "^2.1.3",
     "github-markdown-css": "^2.0.9",
     "highlight.js": "^9.0.0",


Test patch:
diff --git a/test/exportJob-test.js b/test/exportJob-test.js
index af2d903..22af9f2 100644
--- a/test/exportJob-test.js
+++ b/test/exportJob-test.js
@@ -1,4 +1,4 @@
-import { test } from 'ava'
+import { beforeEach, test } from 'ava'
 
 import _ from 'lodash'
 
@@ -6,12 +6,15 @@ import validator from 'validator'
 
 import ExportJob from '../lib/exportJob'
 
-const args = {}
-const options = {
-  pageSize: 'Letter'
-}
+let job, args, options
 
-let job = new ExportJob(['input'], 'output.pdf', args, options)
+beforeEach(() => {
+  args = {}
+  options = {
+    pageSize: 'Letter'
+  }
+  job = new ExportJob(['input'], 'output.pdf', args, options)
+})
 
 // Construction
 /**
@@ -94,6 +97,34 @@ test('setSessionCookie_multiple', t => {
   })
 })
 
+// Header Tests
+test('_getHeaders all possible headers', t => {
+  args.acceptLanguage = 'en'
+  args.disableCache = true
+  args.requestHeaders = `{"H1": "V1", "H2": "V2"}`
+  const headers = job._getHeaders()
+  const expected = [
+    'Accept-Language: en',
+    'pragma: no-cache',
+    'H1: V1',
+    'H2: V2'
+  ]
+  t.deepEqual(headers, expected)
+})
+
+test('_getHeaders --requestHeaders single value only', t => {
+  args.requestHeaders = `{"H1": "V1"}`
+  const headers = job._getHeaders()
+  const expected = ['H1: V1']
+  t.deepEqual(headers, expected)
+})
+
+test('_getHeaders empty', t => {
+  const headers = job._getHeaders()
+  const expected = []
+  t.deepEqual(headers, expected)
+})
+
 // PDF Completion Tests
 
 test.cb('handlePDF_electronError', t => {