Repository: delvedor/find-my-way
Pull request #84 (2018-06-30 13:48:34)

Add an option to disable case-sensitive routing
See https://github.com/fastify/fastify/issues/1007.

@thearegee would this work for you?

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

coveralls: 
[![Coverage Status](https://coveralls.io/builds/17772504/badge)](https://coveralls.io/builds/17772504)

Coverage decreased (-0.9%) to 96.404% when pulling **0653af5a8d1b75e595522a30aff0c786817c90ef on case-sensitive-param** into **57b657773882155f6e76ac403757c6ba577d847f on master**.

thearegee: @mcollina this looks perfect, could just do with a note maybe in the README? 
Just so people know its available
mcollina: Done.
mcollina: @delvedor updated.

Patch:
diff --git a/README.md b/README.md
index 1bfe8f5..6640503 100644
--- a/README.md
+++ b/README.md
@@ -54,7 +54,7 @@ const router = require('find-my-way')({
   ignoreTrailingSlash: true
 })
 function handler (req, res, params) {
-  res.send('foo')
+  res.end('foo')
 }
 // maps "/foo/" and "/foo" to `handler`
 router.on('GET', '/foo/', handler)
@@ -75,6 +75,19 @@ const router = require('find-my-way')({
   allowUnsafeRegex: true
 })
 ```
+
+According to [RFC3986](https://tools.ietf.org/html/rfc3986#section-6.2.2.1), find-my-way is case sensitive by default.
+You can disable this by setting the `caseSensitive` option to `false`:
+in that case all paths will be lowercased before routing, including
+parametric and regexp-matched values. You can turn off case sensitivity
+with:
+
+```js
+const router = require('find-my-way')({
+  caseSensitive: false
+})
+```
+
 <a name="on"></a>
 #### on(method, path, [opts], handler, [store])
 Register a new route.
diff --git a/index.js b/index.js
index 1a726dd..4d9f506 100644
--- a/index.js
+++ b/index.js
@@ -32,6 +32,7 @@ function Router (opts) {
     this.defaultRoute = null
   }
 
+  this.caseSensitive = opts.caseSensitive === undefined ? true : opts.caseSensitive
   this.ignoreTrailingSlash = opts.ignoreTrailingSlash || false
   this.maxParamLength = opts.maxParamLength || 100
   this.allowUnsafeRegex = opts.allowUnsafeRegex || false
@@ -96,8 +97,14 @@ Router.prototype._on = function _on (method, path, opts, handler, store) {
     if (path.charCodeAt(i) === 58) {
       var nodeType = NODE_TYPES.PARAM
       j = i + 1
+      var staticPart = path.slice(0, i)
+
+      if (this.caseSensitive === false) {
+        staticPart = staticPart.toLowerCase()
+      }
+
       // add the static part of the route to the tree
-      this._insert(method, path.slice(0, i), 0, null, null, null, null, version)
+      this._insert(method, staticPart, 0, null, null, null, null, version)
 
       // isolate the parameter name
       var isRegex = false
@@ -149,6 +156,11 @@ Router.prototype._on = function _on (method, path, opts, handler, store) {
       return this._insert(method, path.slice(0, len), 2, params, handler, store, null, version)
     }
   }
+
+  if (this.caseSensitive === false) {
+    path = path.toLowerCase()
+  }
+
   // static route
   this._insert(method, path, 0, params, handler, store, null, version)
 }
@@ -308,6 +320,9 @@ Router.prototype.lookup = function lookup (req, res) {
 }
 
 Router.prototype.find = function find (method, path, version) {
+  if (this.caseSensitive === false) {
+    path = path.toLowerCase()
+  }
   var maxParamLength = this.maxParamLength
   var currentNode = this.tree
   var wildcardNode = null


Test patch:
diff --git a/test/case-insesitive.test.js b/test/case-insesitive.test.js
new file mode 100644
index 0000000..0bc813b
--- /dev/null
+++ b/test/case-insesitive.test.js
@@ -0,0 +1,90 @@
+'use strict'
+
+const t = require('tap')
+const test = t.test
+const FindMyWay = require('../')
+
+test('case insensitive static routes of level 1', t => {
+  t.plan(1)
+
+  const findMyWay = FindMyWay({
+    caseSensitive: false,
+    defaultRoute: (req, res) => {
+      t.fail('Should not be defaultRoute')
+    }
+  })
+
+  findMyWay.on('GET', '/woo', (req, res, params) => {
+    t.pass('we should be here')
+  })
+
+  findMyWay.lookup({ method: 'GET', url: '/WOO', headers: {} }, null)
+})
+
+test('case insensitive static routes of level 3', t => {
+  t.plan(1)
+
+  const findMyWay = FindMyWay({
+    caseSensitive: false,
+    defaultRoute: (req, res) => {
+      t.fail('Should not be defaultRoute')
+    }
+  })
+
+  findMyWay.on('GET', '/foo/bar/woo', (req, res, params) => {
+    t.pass('we should be here')
+  })
+
+  findMyWay.lookup({ method: 'GET', url: '/Foo/bAR/WoO', headers: {} }, null)
+})
+
+test('parametric case insensitive', t => {
+  t.plan(1)
+
+  const findMyWay = FindMyWay({
+    caseSensitive: false,
+    defaultRoute: (req, res) => {
+      t.fail('Should not be defaultRoute')
+    }
+  })
+
+  findMyWay.on('GET', '/foo/:param', (req, res, params) => {
+    t.equal(params.param, 'bar')
+  })
+
+  findMyWay.lookup({ method: 'GET', url: '/Foo/bAR', headers: {} }, null)
+})
+
+test('parametric case insensitive with a static part', t => {
+  t.plan(1)
+
+  const findMyWay = FindMyWay({
+    caseSensitive: false,
+    defaultRoute: (req, res) => {
+      t.fail('Should not be defaultRoute')
+    }
+  })
+
+  findMyWay.on('GET', '/foo/my-:param', (req, res, params) => {
+    t.equal(params.param, 'bar')
+  })
+
+  findMyWay.lookup({ method: 'GET', url: '/Foo/MY-bAR', headers: {} }, null)
+})
+
+test('parametric case insensitive with capital letter', t => {
+  t.plan(1)
+
+  const findMyWay = FindMyWay({
+    caseSensitive: false,
+    defaultRoute: (req, res) => {
+      t.fail('Should not be defaultRoute')
+    }
+  })
+
+  findMyWay.on('GET', '/foo/:Param', (req, res, params) => {
+    t.equal(params.Param, 'bar')
+  })
+
+  findMyWay.lookup({ method: 'GET', url: '/Foo/bAR', headers: {} }, null)
+})