Add dynamic backend routing
diff --git a/conf.d/managed_endpoints.conf b/conf.d/managed_endpoints.conf
index cf917d0..ea06ac6 100644
--- a/conf.d/managed_endpoints.conf
+++ b/conf.d/managed_endpoints.conf
@@ -25,6 +25,7 @@
     listen 8080 default_server;
 
     server_tokens off;
+    ignore_invalid_headers off;
 
     #turn off the uninitialized_variable_warn ,as it writes to error_log , hence io
     uninitialized_variable_warn off;
@@ -70,7 +71,7 @@
             local routing = require "routing"
             routing.processCall()
             local cors = require "cors"
-            ngx.var.cors, ngx.var.cors_methods = cors.processCall(ngx.var["tenant"], ngx.var["gatewayPath"])   
+            ngx.var.cors, ngx.var.cors_methods = cors.processCall(ngx.var["tenant"], ngx.var["gatewayPath"])
         }
         
         proxy_pass $upstream;
diff --git a/scripts/lua/management/apis.lua b/scripts/lua/management/apis.lua
index 231461d..8f0ff99 100644
--- a/scripts/lua/management/apis.lua
+++ b/scripts/lua/management/apis.lua
@@ -231,22 +231,22 @@
 -- @param security security object
 function checkOptionalPolicies(policies, security)
   if policies then
-    for k, v in pairs(policies) do
-      local validTypes = {reqMapping = true, rateLimit = true}
+    for _, v in pairs(policies) do
+      local validTypes = {"reqMapping", "rateLimit", "backendRouting"}
       if (v.type == nil or v.value == nil) then
-        return false, { statusCode = 400, message = "Missing field in policy object. Need \"type\" and \"scope\"." }
-      elseif validTypes[v.type] == nil then
-        return false, { statusCode = 400, message = "Invalid type in policy object. Valid: \"reqMapping\", \"rateLimit\"" }
+        return false, { statusCode = 400, message = "Missing field in policy object. Need \"type\" and \"value\"." }
+      elseif utils.tableContains(validTypes, v.type) == false then
+        return false, { statusCode = 400, message = "Invalid type in policy object. Valid types: " .. cjson.encode(validTypes) }
       end
     end
   end
   if security then
-    for k, sec in ipairs(security) do
-      local validScopes = {tenant=true, api=true, resource=true}
+    for _, sec in ipairs(security) do
+      local validScopes = {"tenant", "api", "resource"}
       if (sec.type == nil or sec.scope == nil) then
         return false, { statusCode = 400, message = "Missing field in security object. Need \"type\" and \"scope\"." }
-      elseif validScopes[sec.scope] == nil then
-        return false, { statusCode = 400, message = "Invalid scope in security object. Valid: \"tenant\", \"api\", \"resource\"." }
+      elseif utils.tableContains(validScopes, sec.scope) == false == nil then
+        return false, { statusCode = 400, message = "Invalid scope in security object. Valid scopes:" .. cjson.encode(validScopes) }
       end
     end 
   end
diff --git a/scripts/lua/policies/backendRouting.lua b/scripts/lua/policies/backendRouting.lua
new file mode 100644
index 0000000..5c5b4f3
--- /dev/null
+++ b/scripts/lua/policies/backendRouting.lua
@@ -0,0 +1,89 @@
+-- Copyright (c) 2016 IBM. All rights reserved.
+--
+--   Permission is hereby granted, free of charge, to any person obtaining a
+--   copy of this software and associated documentation files (the "Software"),
+--   to deal in the Software without restriction, including without limitation
+--   the rights to use, copy, modify, merge, publish, distribute, sublicense,
+--   and/or sell copies of the Software, and to permit persons to whom the
+--   Software is furnished to do so, subject to the following conditions:
+--
+--   The above copyright notice and this permission notice shall be included in
+--   all copies or substantial portions of the Software.
+--
+--   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+--   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+--   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+--   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+--   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+--   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+--   DEALINGS IN THE SOFTWARE.
+
+--- @module backendRouting
+-- Used to set the backend Url either statically or dynamically
+
+local url = require "url"
+local utils = require "lib/utils"
+local request = require "lib/request"
+local logger = require "lib/logger"
+
+local _M = {}
+
+--- Set upstream based on the backendUrl
+function _M.setRoute(backendUrl)
+  local u = url.parse(backendUrl)
+  if u.scheme == nil then
+    u = url.parse(utils.concatStrings({'http://', backendUrl}))
+  end
+  ngx.var.backendUrl = backendUrl
+  ngx.req.set_uri(getUriPath(u.path))
+  setUpstream(u)
+end
+
+--- Set dynamic route based on the based on the header that is passed in
+function _M.setDynamicRoute(obj)
+  local whitelist = obj.whitelist
+  for k in pairs(whitelist) do
+    whitelist[k] = whitelist[k]:lower()
+  end
+  local header = obj.header ~= nil and obj.header or 'X-Cf-Forwarded-Url'
+  local dynamicBackend = ngx.req.get_headers()[header];
+  if dynamicBackend ~= nil and dynamicBackend ~= '' then
+    local u = url.parse(dynamicBackend)
+    if u.scheme == nil or u.scheme == '' then
+      u = url.parse(utils.concatStrings({'http://', dynamicBackend}))
+    end
+    if utils.tableContains(whitelist, u.host) then
+      ngx.req.set_uri(getUriPath(u.path))
+      setUpstream(u)
+    else
+      request.err(403, 'Dynamic backend host not part of whitelist.')
+    end
+  else
+    logger.info('Header for dynamic routing not found. Defaulting to backendUrl.')
+  end
+end
+
+function getUriPath(backendPath)
+  local gatewayPath = ngx.unescape_uri(ngx.var.gatewayPath)
+  gatewayPath = gatewayPath:gsub('-', '%%-')
+  local _, j = ngx.var.request_uri:find(gatewayPath)
+  local incomingPath = ((j and ngx.var.request_uri:sub(j + 1)) or nil)
+  -- Check for backendUrl path
+  if backendPath == nil or backendPath == '' or backendPath == '/' then
+    incomingPath = (incomingPath and incomingPath ~= '') and incomingPath or '/'
+    incomingPath = string.sub(incomingPath, 1, 1) == '/' and incomingPath or utils.concatStrings({'/', incomingPath})
+    return incomingPath
+  else
+    return utils.concatStrings({backendPath, incomingPath})
+  end
+end
+
+function setUpstream(u)
+  local upstream = utils.concatStrings({u.scheme, '://', u.host})
+  if u.port ~= nil and u.port ~= '' then
+    upstream = utils.concatStrings({upstream, ':', u.port})
+  end
+  ngx.var.upstream = upstream
+end
+
+return _M
\ No newline at end of file
diff --git a/scripts/lua/policies/mapping.lua b/scripts/lua/policies/mapping.lua
index 97f7c71..643070f 100644
--- a/scripts/lua/policies/mapping.lua
+++ b/scripts/lua/policies/mapping.lua
@@ -28,10 +28,10 @@
 
 local _M = {}
 
-local body = nil
-local query = nil
-local headers = nil
-local path = nil
+local body
+local query
+local headers
+local path
 
 --- Implementation for the mapping policy.
 -- @param map The mapping object that contains details about request tranformations
diff --git a/scripts/lua/routing.lua b/scripts/lua/routing.lua
index c1e2720..af4da88 100644
--- a/scripts/lua/routing.lua
+++ b/scripts/lua/routing.lua
@@ -25,11 +25,11 @@
 local utils = require "lib/utils"
 local request = require "lib/request"
 local redis = require "lib/redis"
-local url = require "url"
 -- load policies
 local security = require "policies/security"
 local mapping = require "policies/mapping"
 local rateLimit = require "policies/rateLimit"
+local backendRouting = require "policies/backendRouting"
 
 local REDIS_HOST = os.getenv("REDIS_HOST")
 local REDIS_PORT = os.getenv("REDIS_PORT")
@@ -44,14 +44,13 @@
   local resourceKeys = redis.getAllResourceKeys(red, ngx.var.tenant)
   local redisKey = _M.findRedisKey(resourceKeys, ngx.var.tenant, ngx.var.gatewayPath)
   if redisKey == nil then
-    return request.err(404, 'Not found.')
+    request.err(404, 'Not found.')
   end
   local obj = cjson.decode(redis.getResource(red, redisKey, "resources"))
-  local found = false
   for verb, opFields in pairs(obj.operations) do
     if string.upper(verb) == ngx.req.get_method() then
       -- Check if auth is required
-      local key = nil
+      local key
       if (opFields.security) then
         for k, sec in ipairs(opFields.security) do  
           local result = utils.concatStrings({key, security.process(sec)})
@@ -60,36 +59,20 @@
           end
         end
       end
-      -- Parse backend url
-      local u = url.parse(opFields.backendUrl)
-      -- add http:// if no protocol is specified
-      if u.scheme == nil then
-        u = url.parse(utils.concatStrings({'http://', opFields.backendUrl}))
-      end
-      ngx.req.set_uri(getUriPath(u.path))
-      ngx.var.backendUrl = opFields.backendUrl
-      -- Set upstream
-      local upstream = utils.concatStrings({u.scheme, '://', u.host})
-      -- add port if it's in the backendURL
-      if u.port ~= nil and u.port ~= '' then
-        upstream = utils.concatStrings({upstream, ':', u.port})
-      end
-      ngx.var.upstream = upstream
       -- Set backend method
       if opFields.backendMethod ~= nil then
         setVerb(opFields.backendMethod)
       end
+      -- Set backend upstream and uri
+      backendRouting.setRoute(opFields.backendUrl)
       -- Parse policies
       if opFields.policies ~= nil then
         parsePolicies(opFields.policies, key)
       end
-      found = true
-      break
+      return
     end
   end
-  if found == false then
-    request.err(404, 'Whoops. Verb not supported.')
-  end
+  request.err(404, 'Whoops. Verb not supported.')
 end
 
 --- Find the correct redis key based on the path that's passed in
@@ -168,6 +151,8 @@
       mapping.processMap(v.value)
     elseif v.type == 'rateLimit' then
       rateLimit.limit(v.value, apiKey)
+    elseif v.type == 'backendRouting' then
+      backendRouting.setDynamicRoute(v.value)
     end
   end
 end
@@ -177,26 +162,11 @@
 function setVerb(v)
   local allowedVerbs = {'GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'HEAD', 'OPTIONS'}
   local verb = string.upper(v)
-  if(utils.tableContains(allowedVerbs, verb)) then
+  if utils.tableContains(allowedVerbs, verb) then
     ngx.req.set_method(ngx[utils.concatStrings({"HTTP_", verb})])
   else
     ngx.req.set_method(ngx.HTTP_GET)
   end
 end
 
-function getUriPath(backendPath)
-  local gatewayPath = ngx.unescape_uri(ngx.var.gatewayPath)
-  gatewayPath = gatewayPath:gsub('-', '%%-')
-  local _, j = ngx.var.uri:find(gatewayPath)
-  local incomingPath = ((j and ngx.var.uri:sub(j + 1)) or nil)
-  -- Check for backendUrl path
-  if backendPath == nil or backendPath == '' or backendPath == '/' then
-    incomingPath = (incomingPath and incomingPath ~= '') and incomingPath or '/'
-    incomingPath = string.sub(incomingPath, 1, 1) == '/' and incomingPath or utils.concatStrings({'/', incomingPath})
-    return incomingPath
-  else
-    return utils.concatStrings({backendPath, incomingPath})
-  end
-end
-
 return _M