Merge remote-tracking branch 'da-z/patch-1' into chaining
diff --git a/.travis.yml b/.travis.yml
index b0cf782..814710d 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,4 +3,5 @@
   - 1.1
   - 1.2
   - 1.3
+  - 1.4
   - tip
diff --git a/README.md b/README.md
index 25201e1..f7ca0a3 100644
--- a/README.md
+++ b/README.md
@@ -196,8 +196,9 @@
 Or you could [just write your own](http://justinas.org/writing-http-middleware-in-go/),
 it's very easy!
 
-Alternatively, you could try [a framework building upon HttpRouter](#web-frameworks-building-upon-httprouter).
+Alternatively, you could try [a framework building upon HttpRouter](#web-frameworks--co-based-on-httprouter).
 
+### Multi-domain / Sub-domains
 Here is a quick example: Does your server serve multiple domains / hosts?
 You want to use sub-domains?
 Define a router per host!
@@ -235,7 +236,69 @@
 }
 ```
 
-## Web Frameworks building upon HttpRouter
+### Basic Authentication
+Another quick example: Basic Authentification (RFC 2617) for handles:
+
+```go
+package main
+
+import (
+    "bytes"
+    "encoding/base64"
+    "fmt"
+    "github.com/julienschmidt/httprouter"
+    "net/http"
+    "log"
+    "strings"
+)
+
+func BasicAuth(h httprouter.Handle, user, pass []byte) httprouter.Handle {
+	return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
+		const basicAuthPrefix string = "Basic "
+
+		// Get the Basic Authentication credentials
+		auth := r.Header.Get("Authorization")
+		if strings.HasPrefix(auth, basicAuthPrefix) {
+			// Check credentials
+			payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):])
+			if err == nil {
+				pair := bytes.SplitN(payload, []byte(":"), 2)
+				if len(pair) == 2 && bytes.Equal(pair[0], user) && bytes.Equal(pair[1], pass) {
+					// Delegate request to the given handle
+					h(w, r, ps)
+					return
+				}
+			}
+		}
+
+		// Request Basic Authentication otherwise
+		w.Header().Set("WWW-Authenticate", "Basic realm=Restricted")
+		http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized)
+	}
+}
+
+func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+    fmt.Fprint(w, "Not protected!\n")
+}
+
+func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
+    fmt.Fprint(w, "Protected!\n")
+}
+
+func main() {
+    user := []byte("gordon")
+    pass := []byte("secret!")
+    
+    router := httprouter.New()
+    router.GET("/", Index)
+    router.GET("/protected/", BasicAuth(Protected, user, pass))
+
+    log.Fatal(http.ListenAndServe(":8080", router))
+}
+```
+
+## Web Frameworks & Co based on HttpRouter
 If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package:
 * [Gin](https://github.com/gin-gonic/gin): Features a martini-like API with much better performance
 * [Hikaru](https://github.com/najeira/hikaru): Supports standalone and Google AppEngine
+* [Hitch](https://github.com/nbio/hitch): Hitch ties httprouter, [httpcontext](https://github.com/nbio/httpcontext), and middleware up in a bow
diff --git a/router.go b/router.go
index 3f3d163..ac3d680 100644
--- a/router.go
+++ b/router.go
@@ -123,13 +123,21 @@
 	// handle is registered for it.
 	// First superfluous path elements like ../ or // are removed.
 	// Afterwards the router does a case-insensitive lookup of the cleaned path.
-	// If a handle can be found for this route, the router makes a  redirection
+	// If a handle can be found for this route, the router makes a redirection
 	// to the corrected path with status code 301 for GET requests and 307 for
 	// all other request methods.
 	// For example /FOO and /..//Foo could be redirected to /foo.
 	// RedirectTrailingSlash is independent of this option.
 	RedirectFixedPath bool
 
+	// If enabled, the router checks if another method is allowed for the
+	// current route, if the current request can not be routed.
+	// If this is the case, the request is answered with 'Method Not Allowed'
+	// and HTTP status code 405.
+	// If no other Method is allowed, the request is delegated to the NotFound
+	// handler.
+	HandleMethodNotAllowed bool
+
 	// Configurable http.HandlerFunc which is called when no matching route is
 	// found. If it is not set, http.NotFound is used.
 	NotFound http.HandlerFunc
@@ -149,8 +157,9 @@
 // Path auto-correction, including trailing slashes, is enabled by default.
 func New() *Router {
 	return &Router{
-		RedirectTrailingSlash: true,
-		RedirectFixedPath:     true,
+		RedirectTrailingSlash:  true,
+		RedirectFixedPath:      true,
+		HandleMethodNotAllowed: true,
 	}
 }
 
@@ -159,6 +168,11 @@
 	r.Handle("GET", path, handle)
 }
 
+// HEAD is a shortcut for router.Handle("HEAD", path, handle)
+func (r *Router) HEAD(path string, handle Handle) {
+	r.Handle("HEAD", path, handle)
+}
+
 // POST is a shortcut for router.Handle("POST", path, handle)
 func (r *Router) POST(path string, handle Handle) {
 	r.Handle("POST", path, handle)
@@ -284,7 +298,7 @@
 			}
 
 			if tsr && r.RedirectTrailingSlash {
-				if path[len(path)-1] == '/' {
+				if len(path) > 1 && path[len(path)-1] == '/' {
 					req.URL.Path = path[:len(path)-1]
 				} else {
 					req.URL.Path = path + "/"
@@ -308,6 +322,25 @@
 		}
 	}
 
+	// Handle 405
+	if r.HandleMethodNotAllowed {
+		for method := range r.trees {
+			// Skip the requested method - we already tried this one
+			if method == req.Method {
+				continue
+			}
+
+			handle, _, _ := r.trees[method].getValue(req.URL.Path)
+			if handle != nil {
+				http.Error(w,
+					http.StatusText(http.StatusMethodNotAllowed),
+					http.StatusMethodNotAllowed,
+				)
+				return
+			}
+		}
+	}
+
 	// Handle 404
 	if r.NotFound != nil {
 		r.NotFound(w, req)
diff --git a/router_test.go b/router_test.go
index ca59066..6292ba8 100644
--- a/router_test.go
+++ b/router_test.go
@@ -76,7 +76,7 @@
 }
 
 func TestRouterAPI(t *testing.T) {
-	var get, post, put, patch, delete, handler, handlerFunc bool
+	var get, head, post, put, patch, delete, handler, handlerFunc bool
 
 	httpHandler := handlerStruct{&handler}
 
@@ -84,6 +84,9 @@
 	router.GET("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) {
 		get = true
 	})
+	router.HEAD("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) {
+		head = true
+	})
 	router.POST("/POST", func(w http.ResponseWriter, r *http.Request, _ Params) {
 		post = true
 	})
@@ -109,6 +112,12 @@
 		t.Error("routing GET failed")
 	}
 
+	r, _ = http.NewRequest("HEAD", "/GET", nil)
+	router.ServeHTTP(w, r)
+	if !head {
+		t.Error("routing HEAD failed")
+	}
+
 	r, _ = http.NewRequest("POST", "/POST", nil)
 	router.ServeHTTP(w, r)
 	if !post {
@@ -156,12 +165,28 @@
 	}
 }
 
+func TestRouterNotAllowed(t *testing.T) {
+	handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}
+
+	router := New()
+	router.POST("/path", handlerFunc)
+
+	// Test not allowed
+	r, _ := http.NewRequest("GET", "/path", nil)
+	w := httptest.NewRecorder()
+	router.ServeHTTP(w, r)
+	if !(w.Code == http.StatusMethodNotAllowed) {
+		t.Errorf("NotAllowed handling route %s failed: Code=%d, Header=%v", w.Code, w.Header())
+	}
+}
+
 func TestRouterNotFound(t *testing.T) {
 	handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {}
 
 	router := New()
 	router.GET("/path", handlerFunc)
 	router.GET("/dir/", handlerFunc)
+	router.GET("/", handlerFunc)
 
 	testRoutes := []struct {
 		route  string
@@ -170,6 +195,7 @@
 	}{
 		{"/path/", 301, "map[Location:[/path]]"},   // TSR -/
 		{"/dir", 301, "map[Location:[/dir/]]"},     // TSR +/
+		{"", 301, "map[Location:[/]]"},             // TSR +/
 		{"/PATH", 301, "map[Location:[/path]]"},    // Fixed Case
 		{"/DIR/", 301, "map[Location:[/dir/]]"},    // Fixed Case
 		{"/PATH/", 301, "map[Location:[/path]]"},   // Fixed Case -/