v0.0.6

Change-Id: I2ca6da9bed329a799a1f3726d0062f5df94b40e3
diff --git a/data/rules.json b/data/rules.json
index 06f681a..cc86537 100644
--- a/data/rules.json
+++ b/data/rules.json
@@ -31,8 +31,14 @@
   },
   {
     "disabled": false,
+    "target": ".*",
+    "operator": "addReqHeader",
+    "destination": "X-TEST-ORIGIN=gerrit-fe-dev-helper"
+  },
+  {
+    "disabled": false,
     "target": "",
-    "operator": "injectHtmlCode",
-    "destination": "<span style=\"color: white;font-weight:bold;padding:10px;z-index:10000;display:block;position:fixed;bottom:0;right:0;background-color:red;\">Gerrit dev helper is enabled</span>"
+    "operator": "injectJSCode",
+    "destination": "let helperTip = document.createElement('span'); helperTip.innerHTML = `Gerrit dev helper is enabled`; helperTip.style = 'color: white;font-weight:bold;padding:10px;z-index:10000;display:block;position:fixed;bottom:0;right:0;background-color:red;'; let _errorLog = console.error; let numOfErrors = 0; console.error = (...args) => { _errorLog.call(console, ...args); numOfErrors++; helperTip.innerHTML = `Gerrit dev helper is enabled (${numOfErrors} js errors)`; }; document.body.appendChild(helperTip);"
   }
 ]
\ No newline at end of file
diff --git a/release-notes.md b/release-notes.md
index e27b48b..42540dd 100644
--- a/release-notes.md
+++ b/release-notes.md
@@ -1,3 +1,11 @@
+#### v0.0.6
+
+- Add two new operators:
+  - `addReqHeader` to add arbitrary header when you send a request
+  - `rRespHeader` to remove arbitrary header on any response
+- Modify default rules to show # of js errors in the helper tip
+- Add a new default rule to send x-test-origin with gerrit-fe-dev-helper on all requests when enabled
+
 #### v0.0.5
 
 - set crossorigin to anonymous to help debug js error from plugin
diff --git a/src/background.ts b/src/background.ts
index a190deb..9450992 100644
--- a/src/background.ts
+++ b/src/background.ts
@@ -78,6 +78,17 @@
     'name': 'Cache-Control',
     'value': 'max-age=0, no-cache, no-store, must-revalidate'
   });
+
+  const matches = rules.filter(isValidRule)
+                    .filter(
+                        rule => rule.operator === Operator.REMOVE_RESPONSE_HEADER
+                            && !rule.disabled
+                            && new RegExp(rule.target).test(resp.url));
+  matches.forEach(rule => {
+    const removedHeaders = rule.destination.split(",").map(name => name.toLowerCase());
+    resp.responseHeaders = resp.responseHeaders
+      .filter(h => !removedHeaders.includes(h.name.toLowerCase()));
+  });
   return {responseHeaders: resp.responseHeaders};
 }
 
@@ -130,6 +141,24 @@
     });
   }
 
+  const matches = rules.filter(isValidRule)
+                    .filter(
+                        rule => rule.operator === Operator.ADD_REQUEST_HEADER
+                            && !rule.disabled
+                            && new RegExp(rule.target).test(details.url));
+  matches.forEach(rule => {
+    const addedHeaders = rule.destination.split(",")
+    addedHeaders.forEach(addedHeader => {
+      const partial = addedHeader.split("=");
+      if (partial.length === 2) {
+        details.requestHeaders.push({
+          'name': partial[0],
+          'value': partial[1]
+        });
+      }
+    });
+  });
+
   return {requestHeaders: details.requestHeaders};
 }
 
diff --git a/src/content_script.ts b/src/content_script.ts
index e0fa3e7..dc7dbf6 100644
--- a/src/content_script.ts
+++ b/src/content_script.ts
@@ -23,6 +23,22 @@
   return true;
 }
 
+let numOfSnackBars = 0;
+function createSnackBar(message: string) {
+  const errorSnack = document.createElement('div');
+  errorSnack.style.position = 'absolute';
+  errorSnack.style.top = `${numOfSnackBars * 40}px`;
+  errorSnack.style.right = '10px';
+  errorSnack.style.backgroundColor = 'black';
+  errorSnack.style.color = 'white';
+  errorSnack.style.padding = '10px';
+  errorSnack.style.zIndex = '100';
+  errorSnack.innerHTML = message;
+  document.body.appendChild(errorSnack);
+  numOfSnackBars++;
+  return errorSnack;
+}
+
 // Apply injection rules to Gerrit sites if enabled
 chrome.runtime.sendMessage({ type: 'isEnabled' }, (isEnabled) => {
   if (!isEnabled) return;
@@ -60,24 +76,18 @@
     });
 
     // test redirect rules
-    let idx = 0;
     rules.filter(rule => !isInjectRule(rule)).forEach(rule => {
-      if (rule.operator === Operator.REDIRECT && !rule.disabled) {
+      if (rule.operator === Operator.REDIRECT
+          && !rule.disabled
+          // only test for js/html
+          && /\.(js|html)+$/.test(rule.destination)
+        ) {
         fetch(rule.destination).then(res => {
           if (res.status < 200 || res.status >= 300) throw new Error("Resource not found");
         }).catch(e => {
-          const errorSnack = document.createElement('div');
-          errorSnack.style.position = 'absolute';
-          errorSnack.style.top = `${idx++ * 40}px`;
-          errorSnack.style.right = '10px';
-          errorSnack.style.backgroundColor = 'black';
-          errorSnack.style.color = 'white';
-          errorSnack.style.padding = '10px';
-          errorSnack.style.zIndex = '100';
-          errorSnack.innerHTML =
-            `You may have an invalid redirect rule from ${rule.target} to ${
-            rule.destination}`;
-          document.body.appendChild(errorSnack);
+          const errorSnack = createSnackBar(
+            `You may have an invalid redirect rule from ${rule.target} to ${rule.destination}`
+          );
 
           // in case body is unresolved
           document.body.style.display = "block";
@@ -85,7 +95,7 @@
 
           setTimeout(() => {
             errorSnack.remove();
-            idx--;
+            numOfSnackBars--;
           }, 10 * 1000);
         });
       }
diff --git a/src/manifest.json b/src/manifest.json
index ba31029..96ac1d6 100644
--- a/src/manifest.json
+++ b/src/manifest.json
@@ -2,7 +2,7 @@
   "manifest_version": 2,
   "name": "Gerrit FE Dev Helper",
   "description": "This extension can help you development on gerrit sites, frontend specifically",
-  "version": "0.0.5",
+  "version": "0.0.6",
   "browser_action": {
     "default_icon": "gray-32.png",
     "default_title": "Gerrit FE Dev Helper"
diff --git a/src/popup.ts b/src/popup.ts
index 9811f90..9e968d2 100644
--- a/src/popup.ts
+++ b/src/popup.ts
@@ -280,6 +280,8 @@
     Operator.INJECT_HTML_CODE,
     Operator.INJECT_JS_PLUGIN,
     Operator.INJECT_JS_CODE,
+    Operator.ADD_REQUEST_HEADER,
+    Operator.REMOVE_RESPONSE_HEADER,
   ];
 
   handleInputOnTarget(e: Event) {
diff --git a/src/utils.ts b/src/utils.ts
index 20c5a45..c14216b 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -54,6 +54,8 @@
   INJECT_HTML_CODE = 'injectHtmlCode',
   INJECT_JS_PLUGIN = 'injectJSPlugin',
   INJECT_JS_CODE = 'injectJSCode',
+  REMOVE_RESPONSE_HEADER = 'rRespHeader',
+  ADD_REQUEST_HEADER = 'addReqHeader',
 }
 
 /**