Kaynağa Gözat

添加部分代码注释

maxiaoshan 2 yıl önce
ebeveyn
işleme
e36831796f
41 değiştirilmiş dosya ile 8 ekleme ve 7091 silme
  1. BIN
      src/github.com/dlclark/regexp2.zip
  2. 0 18
      src/github.com/gorilla/context/.travis.yml
  3. 0 27
      src/github.com/gorilla/context/LICENSE
  4. 0 7
      src/github.com/gorilla/context/README.md
  5. 0 143
      src/github.com/gorilla/context/context.go
  6. 0 161
      src/github.com/gorilla/context/context_test.go
  7. 0 82
      src/github.com/gorilla/context/doc.go
  8. 0 0
      src/github.com/gorilla/gorilla.zip
  9. 0 20
      src/github.com/gorilla/mux/.travis.yml
  10. 0 27
      src/github.com/gorilla/mux/LICENSE
  11. 0 242
      src/github.com/gorilla/mux/README.md
  12. 0 49
      src/github.com/gorilla/mux/bench_test.go
  13. 0 26
      src/github.com/gorilla/mux/context_gorilla.go
  14. 0 40
      src/github.com/gorilla/mux/context_gorilla_test.go
  15. 0 24
      src/github.com/gorilla/mux/context_native.go
  16. 0 32
      src/github.com/gorilla/mux/context_native_test.go
  17. 0 206
      src/github.com/gorilla/mux/doc.go
  18. 0 495
      src/github.com/gorilla/mux/mux.go
  19. 0 1439
      src/github.com/gorilla/mux/mux_test.go
  20. 0 710
      src/github.com/gorilla/mux/old_test.go
  21. 0 312
      src/github.com/gorilla/mux/regexp.go
  22. 0 634
      src/github.com/gorilla/mux/route.go
  23. 0 18
      src/github.com/gorilla/securecookie/.travis.yml
  24. 0 27
      src/github.com/gorilla/securecookie/LICENSE
  25. 0 78
      src/github.com/gorilla/securecookie/README.md
  26. 0 61
      src/github.com/gorilla/securecookie/doc.go
  27. 0 25
      src/github.com/gorilla/securecookie/fuzz.go
  28. 0 47
      src/github.com/gorilla/securecookie/fuzz/gencorpus.go
  29. 0 646
      src/github.com/gorilla/securecookie/securecookie.go
  30. 0 274
      src/github.com/gorilla/securecookie/securecookie_test.go
  31. 0 21
      src/github.com/gorilla/sessions/.travis.yml
  32. 0 27
      src/github.com/gorilla/sessions/LICENSE
  33. 0 79
      src/github.com/gorilla/sessions/README.md
  34. 0 199
      src/github.com/gorilla/sessions/doc.go
  35. 0 102
      src/github.com/gorilla/sessions/lex.go
  36. 0 241
      src/github.com/gorilla/sessions/sessions.go
  37. 0 201
      src/github.com/gorilla/sessions/sessions_test.go
  38. 0 270
      src/github.com/gorilla/sessions/store.go
  39. 0 73
      src/github.com/gorilla/sessions/store_test.go
  40. 1 1
      src/task/task.go
  41. 7 7
      src/task/updatetask.go

BIN
src/github.com/dlclark/regexp2.zip


+ 0 - 18
src/github.com/gorilla/context/.travis.yml

@@ -1,18 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-  allow_failures:
-    - go: tip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go vet $(go list ./... | grep -v /vendor/)
-  - go test -v -race ./...

+ 0 - 27
src/github.com/gorilla/context/LICENSE

@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-	 * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-	 * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-	 * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 7
src/github.com/gorilla/context/README.md

@@ -1,7 +0,0 @@
-context
-=======
-[![Build Status](https://travis-ci.org/gorilla/context.png?branch=master)](https://travis-ci.org/gorilla/context)
-
-gorilla/context is a general purpose registry for global request variables.
-
-Read the full documentation here: http://www.gorillatoolkit.org/pkg/context

+ 0 - 143
src/github.com/gorilla/context/context.go

@@ -1,143 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package context
-
-import (
-	"net/http"
-	"sync"
-	"time"
-)
-
-var (
-	mutex sync.RWMutex
-	data  = make(map[*http.Request]map[interface{}]interface{})
-	datat = make(map[*http.Request]int64)
-)
-
-// Set stores a value for a given key in a given request.
-func Set(r *http.Request, key, val interface{}) {
-	mutex.Lock()
-	if data[r] == nil {
-		data[r] = make(map[interface{}]interface{})
-		datat[r] = time.Now().Unix()
-	}
-	data[r][key] = val
-	mutex.Unlock()
-}
-
-// Get returns a value stored for a given key in a given request.
-func Get(r *http.Request, key interface{}) interface{} {
-	mutex.RLock()
-	if ctx := data[r]; ctx != nil {
-		value := ctx[key]
-		mutex.RUnlock()
-		return value
-	}
-	mutex.RUnlock()
-	return nil
-}
-
-// GetOk returns stored value and presence state like multi-value return of map access.
-func GetOk(r *http.Request, key interface{}) (interface{}, bool) {
-	mutex.RLock()
-	if _, ok := data[r]; ok {
-		value, ok := data[r][key]
-		mutex.RUnlock()
-		return value, ok
-	}
-	mutex.RUnlock()
-	return nil, false
-}
-
-// GetAll returns all stored values for the request as a map. Nil is returned for invalid requests.
-func GetAll(r *http.Request) map[interface{}]interface{} {
-	mutex.RLock()
-	if context, ok := data[r]; ok {
-		result := make(map[interface{}]interface{}, len(context))
-		for k, v := range context {
-			result[k] = v
-		}
-		mutex.RUnlock()
-		return result
-	}
-	mutex.RUnlock()
-	return nil
-}
-
-// GetAllOk returns all stored values for the request as a map and a boolean value that indicates if
-// the request was registered.
-func GetAllOk(r *http.Request) (map[interface{}]interface{}, bool) {
-	mutex.RLock()
-	context, ok := data[r]
-	result := make(map[interface{}]interface{}, len(context))
-	for k, v := range context {
-		result[k] = v
-	}
-	mutex.RUnlock()
-	return result, ok
-}
-
-// Delete removes a value stored for a given key in a given request.
-func Delete(r *http.Request, key interface{}) {
-	mutex.Lock()
-	if data[r] != nil {
-		delete(data[r], key)
-	}
-	mutex.Unlock()
-}
-
-// Clear removes all values stored for a given request.
-//
-// This is usually called by a handler wrapper to clean up request
-// variables at the end of a request lifetime. See ClearHandler().
-func Clear(r *http.Request) {
-	mutex.Lock()
-	clear(r)
-	mutex.Unlock()
-}
-
-// clear is Clear without the lock.
-func clear(r *http.Request) {
-	delete(data, r)
-	delete(datat, r)
-}
-
-// Purge removes request data stored for longer than maxAge, in seconds.
-// It returns the amount of requests removed.
-//
-// If maxAge <= 0, all request data is removed.
-//
-// This is only used for sanity check: in case context cleaning was not
-// properly set some request data can be kept forever, consuming an increasing
-// amount of memory. In case this is detected, Purge() must be called
-// periodically until the problem is fixed.
-func Purge(maxAge int) int {
-	mutex.Lock()
-	count := 0
-	if maxAge <= 0 {
-		count = len(data)
-		data = make(map[*http.Request]map[interface{}]interface{})
-		datat = make(map[*http.Request]int64)
-	} else {
-		min := time.Now().Unix() - int64(maxAge)
-		for r := range data {
-			if datat[r] < min {
-				clear(r)
-				count++
-			}
-		}
-	}
-	mutex.Unlock()
-	return count
-}
-
-// ClearHandler wraps an http.Handler and clears request values at the end
-// of a request lifetime.
-func ClearHandler(h http.Handler) http.Handler {
-	return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		defer Clear(r)
-		h.ServeHTTP(w, r)
-	})
-}

+ 0 - 161
src/github.com/gorilla/context/context_test.go

@@ -1,161 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package context
-
-import (
-	"net/http"
-	"testing"
-)
-
-type keyType int
-
-const (
-	key1 keyType = iota
-	key2
-)
-
-func TestContext(t *testing.T) {
-	assertEqual := func(val interface{}, exp interface{}) {
-		if val != exp {
-			t.Errorf("Expected %v, got %v.", exp, val)
-		}
-	}
-
-	r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
-	emptyR, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
-
-	// Get()
-	assertEqual(Get(r, key1), nil)
-
-	// Set()
-	Set(r, key1, "1")
-	assertEqual(Get(r, key1), "1")
-	assertEqual(len(data[r]), 1)
-
-	Set(r, key2, "2")
-	assertEqual(Get(r, key2), "2")
-	assertEqual(len(data[r]), 2)
-
-	//GetOk
-	value, ok := GetOk(r, key1)
-	assertEqual(value, "1")
-	assertEqual(ok, true)
-
-	value, ok = GetOk(r, "not exists")
-	assertEqual(value, nil)
-	assertEqual(ok, false)
-
-	Set(r, "nil value", nil)
-	value, ok = GetOk(r, "nil value")
-	assertEqual(value, nil)
-	assertEqual(ok, true)
-
-	// GetAll()
-	values := GetAll(r)
-	assertEqual(len(values), 3)
-
-	// GetAll() for empty request
-	values = GetAll(emptyR)
-	if values != nil {
-		t.Error("GetAll didn't return nil value for invalid request")
-	}
-
-	// GetAllOk()
-	values, ok = GetAllOk(r)
-	assertEqual(len(values), 3)
-	assertEqual(ok, true)
-
-	// GetAllOk() for empty request
-	values, ok = GetAllOk(emptyR)
-	assertEqual(len(values), 0)
-	assertEqual(ok, false)
-
-	// Delete()
-	Delete(r, key1)
-	assertEqual(Get(r, key1), nil)
-	assertEqual(len(data[r]), 2)
-
-	Delete(r, key2)
-	assertEqual(Get(r, key2), nil)
-	assertEqual(len(data[r]), 1)
-
-	// Clear()
-	Clear(r)
-	assertEqual(len(data), 0)
-}
-
-func parallelReader(r *http.Request, key string, iterations int, wait, done chan struct{}) {
-	<-wait
-	for i := 0; i < iterations; i++ {
-		Get(r, key)
-	}
-	done <- struct{}{}
-
-}
-
-func parallelWriter(r *http.Request, key, value string, iterations int, wait, done chan struct{}) {
-	<-wait
-	for i := 0; i < iterations; i++ {
-		Set(r, key, value)
-	}
-	done <- struct{}{}
-
-}
-
-func benchmarkMutex(b *testing.B, numReaders, numWriters, iterations int) {
-
-	b.StopTimer()
-	r, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
-	done := make(chan struct{})
-	b.StartTimer()
-
-	for i := 0; i < b.N; i++ {
-		wait := make(chan struct{})
-
-		for i := 0; i < numReaders; i++ {
-			go parallelReader(r, "test", iterations, wait, done)
-		}
-
-		for i := 0; i < numWriters; i++ {
-			go parallelWriter(r, "test", "123", iterations, wait, done)
-		}
-
-		close(wait)
-
-		for i := 0; i < numReaders+numWriters; i++ {
-			<-done
-		}
-
-	}
-
-}
-
-func BenchmarkMutexSameReadWrite1(b *testing.B) {
-	benchmarkMutex(b, 1, 1, 32)
-}
-func BenchmarkMutexSameReadWrite2(b *testing.B) {
-	benchmarkMutex(b, 2, 2, 32)
-}
-func BenchmarkMutexSameReadWrite4(b *testing.B) {
-	benchmarkMutex(b, 4, 4, 32)
-}
-func BenchmarkMutex1(b *testing.B) {
-	benchmarkMutex(b, 2, 8, 32)
-}
-func BenchmarkMutex2(b *testing.B) {
-	benchmarkMutex(b, 16, 4, 64)
-}
-func BenchmarkMutex3(b *testing.B) {
-	benchmarkMutex(b, 1, 2, 128)
-}
-func BenchmarkMutex4(b *testing.B) {
-	benchmarkMutex(b, 128, 32, 256)
-}
-func BenchmarkMutex5(b *testing.B) {
-	benchmarkMutex(b, 1024, 2048, 64)
-}
-func BenchmarkMutex6(b *testing.B) {
-	benchmarkMutex(b, 2048, 1024, 512)
-}

+ 0 - 82
src/github.com/gorilla/context/doc.go

@@ -1,82 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package context stores values shared during a request lifetime.
-
-For example, a router can set variables extracted from the URL and later
-application handlers can access those values, or it can be used to store
-sessions values to be saved at the end of a request. There are several
-others common uses.
-
-The idea was posted by Brad Fitzpatrick to the go-nuts mailing list:
-
-	http://groups.google.com/group/golang-nuts/msg/e2d679d303aa5d53
-
-Here's the basic usage: first define the keys that you will need. The key
-type is interface{} so a key can be of any type that supports equality.
-Here we define a key using a custom int type to avoid name collisions:
-
-	package foo
-
-	import (
-		"github.com/gorilla/context"
-	)
-
-	type key int
-
-	const MyKey key = 0
-
-Then set a variable. Variables are bound to an http.Request object, so you
-need a request instance to set a value:
-
-	context.Set(r, MyKey, "bar")
-
-The application can later access the variable using the same key you provided:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// val is "bar".
-		val := context.Get(r, foo.MyKey)
-
-		// returns ("bar", true)
-		val, ok := context.GetOk(r, foo.MyKey)
-		// ...
-	}
-
-And that's all about the basic usage. We discuss some other ideas below.
-
-Any type can be stored in the context. To enforce a given type, make the key
-private and wrap Get() and Set() to accept and return values of a specific
-type:
-
-	type key int
-
-	const mykey key = 0
-
-	// GetMyKey returns a value for this package from the request values.
-	func GetMyKey(r *http.Request) SomeType {
-		if rv := context.Get(r, mykey); rv != nil {
-			return rv.(SomeType)
-		}
-		return nil
-	}
-
-	// SetMyKey sets a value for this package in the request values.
-	func SetMyKey(r *http.Request, val SomeType) {
-		context.Set(r, mykey, val)
-	}
-
-Variables must be cleared at the end of a request, to remove all values
-that were stored. This can be done in an http.Handler, after a request was
-served. Just call Clear() passing the request:
-
-	context.Clear(r)
-
-...or use ClearHandler(), which conveniently wraps an http.Handler to clear
-variables at the end of a request lifetime.
-
-The Routers from the packages gorilla/mux and gorilla/pat call Clear()
-so if you are using either of them you don't need to clear the context manually.
-*/
-package context

+ 0 - 0
src/github.com/gorilla/gorilla.zip


+ 0 - 20
src/github.com/gorilla/mux/.travis.yml

@@ -1,20 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.2
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-
-install:
-  - # Skip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go tool vet .
-  - go test -v -race ./...

+ 0 - 27
src/github.com/gorilla/mux/LICENSE

@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-	 * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-	 * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-	 * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 242
src/github.com/gorilla/mux/README.md

@@ -1,242 +0,0 @@
-mux
-===
-[![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
-[![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
-
-http://www.gorillatoolkit.org/pkg/mux
-
-Package `gorilla/mux` implements a request router and dispatcher.
-
-The name mux stands for "HTTP request multiplexer". Like the standard `http.ServeMux`, `mux.Router` matches incoming requests against a list of registered routes and calls a handler for the route that matches the URL or other conditions. The main features are:
-
-* Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
-* URL hosts and paths can have variables with an optional regular expression.
-* Registered URLs can be built, or "reversed", which helps maintaining references to resources.
-* Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
-* It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
-
-Let's start registering a couple of URL paths and handlers:
-
-```go
-func main() {
-	r := mux.NewRouter()
-	r.HandleFunc("/", HomeHandler)
-	r.HandleFunc("/products", ProductsHandler)
-	r.HandleFunc("/articles", ArticlesHandler)
-	http.Handle("/", r)
-}
-```
-
-Here we register three routes mapping URL paths to handlers. This is equivalent to how `http.HandleFunc()` works: if an incoming request URL matches one of the paths, the corresponding handler is called passing (`http.ResponseWriter`, `*http.Request`) as parameters.
-
-Paths can have variables. They are defined using the format `{name}` or `{name:pattern}`. If a regular expression pattern is not defined, the matched variable will be anything until the next slash. For example:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/products/{key}", ProductHandler)
-r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
-r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-```
-
-The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
-
-```go
-vars := mux.Vars(request)
-category := vars["category"]
-```
-
-And this is all you need to know about the basic usage. More advanced options are explained below.
-
-Routes can also be restricted to a domain or subdomain. Just define a host pattern to be matched. They can also have variables:
-
-```go
-r := mux.NewRouter()
-// Only matches if domain is "www.example.com".
-r.Host("www.example.com")
-// Matches a dynamic subdomain.
-r.Host("{subdomain:[a-z]+}.domain.com")
-```
-
-There are several other matchers that can be added. To match path prefixes:
-
-```go
-r.PathPrefix("/products/")
-```
-
-...or HTTP methods:
-
-```go
-r.Methods("GET", "POST")
-```
-
-...or URL schemes:
-
-```go
-r.Schemes("https")
-```
-
-...or header values:
-
-```go
-r.Headers("X-Requested-With", "XMLHttpRequest")
-```
-
-...or query values:
-
-```go
-r.Queries("key", "value")
-```
-
-...or to use a custom matcher function:
-
-```go
-r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
-	return r.ProtoMajor == 0
-})
-```
-
-...and finally, it is possible to combine several matchers in a single route:
-
-```go
-r.HandleFunc("/products", ProductsHandler).
-  Host("www.example.com").
-  Methods("GET").
-  Schemes("http")
-```
-
-Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
-
-For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
-
-```go
-r := mux.NewRouter()
-s := r.Host("www.example.com").Subrouter()
-```
-
-Then register routes in the subrouter:
-
-```go
-s.HandleFunc("/products/", ProductsHandler)
-s.HandleFunc("/products/{key}", ProductHandler)
-s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-```
-
-The three URL paths we registered above will only be tested if the domain is `www.example.com`, because the subrouter is tested first. This is not only convenient, but also optimizes request matching. You can create subrouters combining any attribute matchers accepted by a route.
-
-Subrouters can be used to create domain or path "namespaces": you define subrouters in a central place and then parts of the app can register its paths relatively to a given subrouter.
-
-There's one more thing about subroutes. When a subrouter has a path prefix, the inner routes use it as base for their paths:
-
-```go
-r := mux.NewRouter()
-s := r.PathPrefix("/products").Subrouter()
-// "/products/"
-s.HandleFunc("/", ProductsHandler)
-// "/products/{key}/"
-s.HandleFunc("/{key}/", ProductHandler)
-// "/products/{key}/details"
-s.HandleFunc("/{key}/details", ProductDetailsHandler)
-```
-
-Now let's see how to build registered URLs.
-
-Routes can be named. All routes that define a name can have their URLs built, or "reversed". We define a name calling `Name()` on a route. For example:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-  Name("article")
-```
-
-To build a URL, get the route and call the `URL()` method, passing a sequence of key/value pairs for the route variables. For the previous route, we would do:
-
-```go
-url, err := r.Get("article").URL("category", "technology", "id", "42")
-```
-
-...and the result will be a `url.URL` with the following path:
-
-```
-"/articles/technology/42"
-```
-
-This also works for host variables:
-
-```go
-r := mux.NewRouter()
-r.Host("{subdomain}.domain.com").
-  Path("/articles/{category}/{id:[0-9]+}").
-  HandlerFunc(ArticleHandler).
-  Name("article")
-
-// url.String() will be "http://news.domain.com/articles/technology/42"
-url, err := r.Get("article").URL("subdomain", "news",
-                                 "category", "technology",
-                                 "id", "42")
-```
-
-All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
-
-Regex support also exists for matching Headers within a route. For example, we could do:
-
-```go
-r.HeadersRegexp("Content-Type", "application/(text|json)")
-```
-
-...and the route will match both requests with a Content-Type of `application/json` as well as `application/text`
-
-There's also a way to build only the URL host or path for a route: use the methods `URLHost()` or `URLPath()` instead. For the previous route, we would do:
-
-```go
-// "http://news.domain.com/"
-host, err := r.Get("article").URLHost("subdomain", "news")
-
-// "/articles/technology/42"
-path, err := r.Get("article").URLPath("category", "technology", "id", "42")
-```
-
-And if you use subrouters, host and path defined separately can be built as well:
-
-```go
-r := mux.NewRouter()
-s := r.Host("{subdomain}.domain.com").Subrouter()
-s.Path("/articles/{category}/{id:[0-9]+}").
-  HandlerFunc(ArticleHandler).
-  Name("article")
-
-// "http://news.domain.com/articles/technology/42"
-url, err := r.Get("article").URL("subdomain", "news",
-                                 "category", "technology",
-                                 "id", "42")
-```
-
-## Full Example
-
-Here's a complete, runnable example of a small `mux` based server:
-
-```go
-package main
-
-import (
-	"net/http"
-	"log"
-	"github.com/gorilla/mux"
-)
-
-func YourHandler(w http.ResponseWriter, r *http.Request) {
-	w.Write([]byte("Gorilla!\n"))
-}
-
-func main() {
-	r := mux.NewRouter()
-	// Routes consist of a path and a handler function.
-	r.HandleFunc("/", YourHandler)
-
-	// Bind to a port and pass our router in
-	log.Fatal(http.ListenAndServe(":8000", r))
-}
-```
-
-## License
-
-BSD licensed. See the LICENSE file for details.

+ 0 - 49
src/github.com/gorilla/mux/bench_test.go

@@ -1,49 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"net/http"
-	"net/http/httptest"
-	"testing"
-)
-
-func BenchmarkMux(b *testing.B) {
-	router := new(Router)
-	handler := func(w http.ResponseWriter, r *http.Request) {}
-	router.HandleFunc("/v1/{v1}", handler)
-
-	request, _ := http.NewRequest("GET", "/v1/anything", nil)
-	for i := 0; i < b.N; i++ {
-		router.ServeHTTP(nil, request)
-	}
-}
-
-func BenchmarkMuxAlternativeInRegexp(b *testing.B) {
-	router := new(Router)
-	handler := func(w http.ResponseWriter, r *http.Request) {}
-	router.HandleFunc("/v1/{v1:(a|b)}", handler)
-
-	requestA, _ := http.NewRequest("GET", "/v1/a", nil)
-	requestB, _ := http.NewRequest("GET", "/v1/b", nil)
-	for i := 0; i < b.N; i++ {
-		router.ServeHTTP(nil, requestA)
-		router.ServeHTTP(nil, requestB)
-	}
-}
-
-func BenchmarkManyPathVariables(b *testing.B) {
-	router := new(Router)
-	handler := func(w http.ResponseWriter, r *http.Request) {}
-	router.HandleFunc("/v1/{v1}/{v2}/{v3}/{v4}/{v5}", handler)
-
-	matchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4/5", nil)
-	notMatchingRequest, _ := http.NewRequest("GET", "/v1/1/2/3/4", nil)
-	recorder := httptest.NewRecorder()
-	for i := 0; i < b.N; i++ {
-		router.ServeHTTP(nil, matchingRequest)
-		router.ServeHTTP(recorder, notMatchingRequest)
-	}
-}

+ 0 - 26
src/github.com/gorilla/mux/context_gorilla.go

@@ -1,26 +0,0 @@
-// +build !go1.7
-
-package mux
-
-import (
-	"net/http"
-
-	"github.com/gorilla/context"
-)
-
-func contextGet(r *http.Request, key interface{}) interface{} {
-	return context.Get(r, key)
-}
-
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
-	if val == nil {
-		return r
-	}
-
-	context.Set(r, key, val)
-	return r
-}
-
-func contextClear(r *http.Request) {
-	context.Clear(r)
-}

+ 0 - 40
src/github.com/gorilla/mux/context_gorilla_test.go

@@ -1,40 +0,0 @@
-// +build !go1.7
-
-package mux
-
-import (
-	"net/http"
-	"testing"
-
-	"github.com/gorilla/context"
-)
-
-// Tests that the context is cleared or not cleared properly depending on
-// the configuration of the router
-func TestKeepContext(t *testing.T) {
-	func1 := func(w http.ResponseWriter, r *http.Request) {}
-
-	r := NewRouter()
-	r.HandleFunc("/", func1).Name("func1")
-
-	req, _ := http.NewRequest("GET", "http://localhost/", nil)
-	context.Set(req, "t", 1)
-
-	res := new(http.ResponseWriter)
-	r.ServeHTTP(*res, req)
-
-	if _, ok := context.GetOk(req, "t"); ok {
-		t.Error("Context should have been cleared at end of request")
-	}
-
-	r.KeepContext = true
-
-	req, _ = http.NewRequest("GET", "http://localhost/", nil)
-	context.Set(req, "t", 1)
-
-	r.ServeHTTP(*res, req)
-	if _, ok := context.GetOk(req, "t"); !ok {
-		t.Error("Context should NOT have been cleared at end of request")
-	}
-
-}

+ 0 - 24
src/github.com/gorilla/mux/context_native.go

@@ -1,24 +0,0 @@
-// +build go1.7
-
-package mux
-
-import (
-	"context"
-	"net/http"
-)
-
-func contextGet(r *http.Request, key interface{}) interface{} {
-	return r.Context().Value(key)
-}
-
-func contextSet(r *http.Request, key, val interface{}) *http.Request {
-	if val == nil {
-		return r
-	}
-
-	return r.WithContext(context.WithValue(r.Context(), key, val))
-}
-
-func contextClear(r *http.Request) {
-	return
-}

+ 0 - 32
src/github.com/gorilla/mux/context_native_test.go

@@ -1,32 +0,0 @@
-// +build go1.7
-
-package mux
-
-import (
-	"context"
-	"net/http"
-	"testing"
-	"time"
-)
-
-func TestNativeContextMiddleware(t *testing.T) {
-	withTimeout := func(h http.Handler) http.Handler {
-		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-			ctx, cancel := context.WithTimeout(r.Context(), time.Minute)
-			defer cancel()
-			h.ServeHTTP(w, r.WithContext(ctx))
-		})
-	}
-
-	r := NewRouter()
-	r.Handle("/path/{foo}", withTimeout(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		vars := Vars(r)
-		if vars["foo"] != "bar" {
-			t.Fatal("Expected foo var to be set")
-		}
-	})))
-
-	rec := NewRecorder()
-	req := newRequest("GET", "/path/bar")
-	r.ServeHTTP(rec, req)
-}

+ 0 - 206
src/github.com/gorilla/mux/doc.go

@@ -1,206 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package mux implements a request router and dispatcher.
-
-The name mux stands for "HTTP request multiplexer". Like the standard
-http.ServeMux, mux.Router matches incoming requests against a list of
-registered routes and calls a handler for the route that matches the URL
-or other conditions. The main features are:
-
-	* Requests can be matched based on URL host, path, path prefix, schemes,
-	  header and query values, HTTP methods or using custom matchers.
-	* URL hosts and paths can have variables with an optional regular
-	  expression.
-	* Registered URLs can be built, or "reversed", which helps maintaining
-	  references to resources.
-	* Routes can be used as subrouters: nested routes are only tested if the
-	  parent route matches. This is useful to define groups of routes that
-	  share common conditions like a host, a path prefix or other repeated
-	  attributes. As a bonus, this optimizes request matching.
-	* It implements the http.Handler interface so it is compatible with the
-	  standard http.ServeMux.
-
-Let's start registering a couple of URL paths and handlers:
-
-	func main() {
-		r := mux.NewRouter()
-		r.HandleFunc("/", HomeHandler)
-		r.HandleFunc("/products", ProductsHandler)
-		r.HandleFunc("/articles", ArticlesHandler)
-		http.Handle("/", r)
-	}
-
-Here we register three routes mapping URL paths to handlers. This is
-equivalent to how http.HandleFunc() works: if an incoming request URL matches
-one of the paths, the corresponding handler is called passing
-(http.ResponseWriter, *http.Request) as parameters.
-
-Paths can have variables. They are defined using the format {name} or
-{name:pattern}. If a regular expression pattern is not defined, the matched
-variable will be anything until the next slash. For example:
-
-	r := mux.NewRouter()
-	r.HandleFunc("/products/{key}", ProductHandler)
-	r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler)
-	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
-
-The names are used to create a map of route variables which can be retrieved
-calling mux.Vars():
-
-	vars := mux.Vars(request)
-	category := vars["category"]
-
-And this is all you need to know about the basic usage. More advanced options
-are explained below.
-
-Routes can also be restricted to a domain or subdomain. Just define a host
-pattern to be matched. They can also have variables:
-
-	r := mux.NewRouter()
-	// Only matches if domain is "www.example.com".
-	r.Host("www.example.com")
-	// Matches a dynamic subdomain.
-	r.Host("{subdomain:[a-z]+}.domain.com")
-
-There are several other matchers that can be added. To match path prefixes:
-
-	r.PathPrefix("/products/")
-
-...or HTTP methods:
-
-	r.Methods("GET", "POST")
-
-...or URL schemes:
-
-	r.Schemes("https")
-
-...or header values:
-
-	r.Headers("X-Requested-With", "XMLHttpRequest")
-
-...or query values:
-
-	r.Queries("key", "value")
-
-...or to use a custom matcher function:
-
-	r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool {
-		return r.ProtoMajor == 0
-	})
-
-...and finally, it is possible to combine several matchers in a single route:
-
-	r.HandleFunc("/products", ProductsHandler).
-	  Host("www.example.com").
-	  Methods("GET").
-	  Schemes("http")
-
-Setting the same matching conditions again and again can be boring, so we have
-a way to group several routes that share the same requirements.
-We call it "subrouting".
-
-For example, let's say we have several URLs that should only match when the
-host is "www.example.com". Create a route for that host and get a "subrouter"
-from it:
-
-	r := mux.NewRouter()
-	s := r.Host("www.example.com").Subrouter()
-
-Then register routes in the subrouter:
-
-	s.HandleFunc("/products/", ProductsHandler)
-	s.HandleFunc("/products/{key}", ProductHandler)
-	s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
-
-The three URL paths we registered above will only be tested if the domain is
-"www.example.com", because the subrouter is tested first. This is not
-only convenient, but also optimizes request matching. You can create
-subrouters combining any attribute matchers accepted by a route.
-
-Subrouters can be used to create domain or path "namespaces": you define
-subrouters in a central place and then parts of the app can register its
-paths relatively to a given subrouter.
-
-There's one more thing about subroutes. When a subrouter has a path prefix,
-the inner routes use it as base for their paths:
-
-	r := mux.NewRouter()
-	s := r.PathPrefix("/products").Subrouter()
-	// "/products/"
-	s.HandleFunc("/", ProductsHandler)
-	// "/products/{key}/"
-	s.HandleFunc("/{key}/", ProductHandler)
-	// "/products/{key}/details"
-	s.HandleFunc("/{key}/details", ProductDetailsHandler)
-
-Now let's see how to build registered URLs.
-
-Routes can be named. All routes that define a name can have their URLs built,
-or "reversed". We define a name calling Name() on a route. For example:
-
-	r := mux.NewRouter()
-	r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-	  Name("article")
-
-To build a URL, get the route and call the URL() method, passing a sequence of
-key/value pairs for the route variables. For the previous route, we would do:
-
-	url, err := r.Get("article").URL("category", "technology", "id", "42")
-
-...and the result will be a url.URL with the following path:
-
-	"/articles/technology/42"
-
-This also works for host variables:
-
-	r := mux.NewRouter()
-	r.Host("{subdomain}.domain.com").
-	  Path("/articles/{category}/{id:[0-9]+}").
-	  HandlerFunc(ArticleHandler).
-	  Name("article")
-
-	// url.String() will be "http://news.domain.com/articles/technology/42"
-	url, err := r.Get("article").URL("subdomain", "news",
-	                                 "category", "technology",
-	                                 "id", "42")
-
-All variables defined in the route are required, and their values must
-conform to the corresponding patterns. These requirements guarantee that a
-generated URL will always match a registered route -- the only exception is
-for explicitly defined "build-only" routes which never match.
-
-Regex support also exists for matching Headers within a route. For example, we could do:
-
-	r.HeadersRegexp("Content-Type", "application/(text|json)")
-
-...and the route will match both requests with a Content-Type of `application/json` as well as
-`application/text`
-
-There's also a way to build only the URL host or path for a route:
-use the methods URLHost() or URLPath() instead. For the previous route,
-we would do:
-
-	// "http://news.domain.com/"
-	host, err := r.Get("article").URLHost("subdomain", "news")
-
-	// "/articles/technology/42"
-	path, err := r.Get("article").URLPath("category", "technology", "id", "42")
-
-And if you use subrouters, host and path defined separately can be built
-as well:
-
-	r := mux.NewRouter()
-	s := r.Host("{subdomain}.domain.com").Subrouter()
-	s.Path("/articles/{category}/{id:[0-9]+}").
-	  HandlerFunc(ArticleHandler).
-	  Name("article")
-
-	// "http://news.domain.com/articles/technology/42"
-	url, err := r.Get("article").URL("subdomain", "news",
-	                                 "category", "technology",
-	                                 "id", "42")
-*/
-package mux

+ 0 - 495
src/github.com/gorilla/mux/mux.go

@@ -1,495 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"errors"
-	"fmt"
-	"net/http"
-	"path"
-	"regexp"
-)
-
-// NewRouter returns a new router instance.
-func NewRouter() *Router {
-	return &Router{namedRoutes: make(map[string]*Route), KeepContext: false}
-}
-
-// Router registers routes to be matched and dispatches a handler.
-//
-// It implements the http.Handler interface, so it can be registered to serve
-// requests:
-//
-//     var router = mux.NewRouter()
-//
-//     func main() {
-//         http.Handle("/", router)
-//     }
-//
-// Or, for Google App Engine, register it in a init() function:
-//
-//     func init() {
-//         http.Handle("/", router)
-//     }
-//
-// This will send all incoming requests to the router.
-type Router struct {
-	// Configurable Handler to be used when no route matches.
-	NotFoundHandler http.Handler
-	// Parent route, if this is a subrouter.
-	parent parentRoute
-	// Routes to be matched, in order.
-	routes []*Route
-	// Routes by name for URL building.
-	namedRoutes map[string]*Route
-	// See Router.StrictSlash(). This defines the flag for new routes.
-	strictSlash bool
-	// See Router.SkipClean(). This defines the flag for new routes.
-	skipClean bool
-	// If true, do not clear the request context after handling the request.
-	// This has no effect when go1.7+ is used, since the context is stored
-	// on the request itself.
-	KeepContext bool
-}
-
-// Match matches registered routes against the request.
-func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
-	for _, route := range r.routes {
-		if route.Match(req, match) {
-			return true
-		}
-	}
-
-	// Closest match for a router (includes sub-routers)
-	if r.NotFoundHandler != nil {
-		match.Handler = r.NotFoundHandler
-		return true
-	}
-	return false
-}
-
-// ServeHTTP dispatches the handler registered in the matched route.
-//
-// When there is a match, the route variables can be retrieved calling
-// mux.Vars(request).
-func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
-	if !r.skipClean {
-		// Clean path to canonical form and redirect.
-		if p := cleanPath(req.URL.Path); p != req.URL.Path {
-
-			// Added 3 lines (Philip Schlump) - It was dropping the query string and #whatever from query.
-			// This matches with fix in go 1.2 r.c. 4 for same problem.  Go Issue:
-			// http://code.google.com/p/go/issues/detail?id=5252
-			url := *req.URL
-			url.Path = p
-			p = url.String()
-
-			w.Header().Set("Location", p)
-			w.WriteHeader(http.StatusMovedPermanently)
-			return
-		}
-	}
-	var match RouteMatch
-	var handler http.Handler
-	if r.Match(req, &match) {
-		handler = match.Handler
-		req = setVars(req, match.Vars)
-		req = setCurrentRoute(req, match.Route)
-	}
-	if handler == nil {
-		handler = http.NotFoundHandler()
-	}
-	if !r.KeepContext {
-		defer contextClear(req)
-	}
-	handler.ServeHTTP(w, req)
-}
-
-// Get returns a route registered with the given name.
-func (r *Router) Get(name string) *Route {
-	return r.getNamedRoutes()[name]
-}
-
-// GetRoute returns a route registered with the given name. This method
-// was renamed to Get() and remains here for backwards compatibility.
-func (r *Router) GetRoute(name string) *Route {
-	return r.getNamedRoutes()[name]
-}
-
-// StrictSlash defines the trailing slash behavior for new routes. The initial
-// value is false.
-//
-// When true, if the route path is "/path/", accessing "/path" will redirect
-// to the former and vice versa. In other words, your application will always
-// see the path as specified in the route.
-//
-// When false, if the route path is "/path", accessing "/path/" will not match
-// this route and vice versa.
-//
-// Special case: when a route sets a path prefix using the PathPrefix() method,
-// strict slash is ignored for that route because the redirect behavior can't
-// be determined from a prefix alone. However, any subrouters created from that
-// route inherit the original StrictSlash setting.
-func (r *Router) StrictSlash(value bool) *Router {
-	r.strictSlash = value
-	return r
-}
-
-// SkipClean defines the path cleaning behaviour for new routes. The initial
-// value is false. Users should be careful about which routes are not cleaned
-//
-// When true, if the route path is "/path//to", it will remain with the double
-// slash. This is helpful if you have a route like: /fetch/http://xkcd.com/534/
-//
-// When false, the path will be cleaned, so /fetch/http://xkcd.com/534/ will
-// become /fetch/http/xkcd.com/534
-func (r *Router) SkipClean(value bool) *Router {
-	r.skipClean = value
-	return r
-}
-
-// ----------------------------------------------------------------------------
-// parentRoute
-// ----------------------------------------------------------------------------
-
-// getNamedRoutes returns the map where named routes are registered.
-func (r *Router) getNamedRoutes() map[string]*Route {
-	if r.namedRoutes == nil {
-		if r.parent != nil {
-			r.namedRoutes = r.parent.getNamedRoutes()
-		} else {
-			r.namedRoutes = make(map[string]*Route)
-		}
-	}
-	return r.namedRoutes
-}
-
-// getRegexpGroup returns regexp definitions from the parent route, if any.
-func (r *Router) getRegexpGroup() *routeRegexpGroup {
-	if r.parent != nil {
-		return r.parent.getRegexpGroup()
-	}
-	return nil
-}
-
-func (r *Router) buildVars(m map[string]string) map[string]string {
-	if r.parent != nil {
-		m = r.parent.buildVars(m)
-	}
-	return m
-}
-
-// ----------------------------------------------------------------------------
-// Route factories
-// ----------------------------------------------------------------------------
-
-// NewRoute registers an empty route.
-func (r *Router) NewRoute() *Route {
-	route := &Route{parent: r, strictSlash: r.strictSlash, skipClean: r.skipClean}
-	r.routes = append(r.routes, route)
-	return route
-}
-
-// Handle registers a new route with a matcher for the URL path.
-// See Route.Path() and Route.Handler().
-func (r *Router) Handle(path string, handler http.Handler) *Route {
-	return r.NewRoute().Path(path).Handler(handler)
-}
-
-// HandleFunc registers a new route with a matcher for the URL path.
-// See Route.Path() and Route.HandlerFunc().
-func (r *Router) HandleFunc(path string, f func(http.ResponseWriter,
-	*http.Request)) *Route {
-	return r.NewRoute().Path(path).HandlerFunc(f)
-}
-
-// Headers registers a new route with a matcher for request header values.
-// See Route.Headers().
-func (r *Router) Headers(pairs ...string) *Route {
-	return r.NewRoute().Headers(pairs...)
-}
-
-// Host registers a new route with a matcher for the URL host.
-// See Route.Host().
-func (r *Router) Host(tpl string) *Route {
-	return r.NewRoute().Host(tpl)
-}
-
-// MatcherFunc registers a new route with a custom matcher function.
-// See Route.MatcherFunc().
-func (r *Router) MatcherFunc(f MatcherFunc) *Route {
-	return r.NewRoute().MatcherFunc(f)
-}
-
-// Methods registers a new route with a matcher for HTTP methods.
-// See Route.Methods().
-func (r *Router) Methods(methods ...string) *Route {
-	return r.NewRoute().Methods(methods...)
-}
-
-// Path registers a new route with a matcher for the URL path.
-// See Route.Path().
-func (r *Router) Path(tpl string) *Route {
-	return r.NewRoute().Path(tpl)
-}
-
-// PathPrefix registers a new route with a matcher for the URL path prefix.
-// See Route.PathPrefix().
-func (r *Router) PathPrefix(tpl string) *Route {
-	return r.NewRoute().PathPrefix(tpl)
-}
-
-// Queries registers a new route with a matcher for URL query values.
-// See Route.Queries().
-func (r *Router) Queries(pairs ...string) *Route {
-	return r.NewRoute().Queries(pairs...)
-}
-
-// Schemes registers a new route with a matcher for URL schemes.
-// See Route.Schemes().
-func (r *Router) Schemes(schemes ...string) *Route {
-	return r.NewRoute().Schemes(schemes...)
-}
-
-// BuildVarsFunc registers a new route with a custom function for modifying
-// route variables before building a URL.
-func (r *Router) BuildVarsFunc(f BuildVarsFunc) *Route {
-	return r.NewRoute().BuildVarsFunc(f)
-}
-
-// Walk walks the router and all its sub-routers, calling walkFn for each route
-// in the tree. The routes are walked in the order they were added. Sub-routers
-// are explored depth-first.
-func (r *Router) Walk(walkFn WalkFunc) error {
-	return r.walk(walkFn, []*Route{})
-}
-
-// SkipRouter is used as a return value from WalkFuncs to indicate that the
-// router that walk is about to descend down to should be skipped.
-var SkipRouter = errors.New("skip this router")
-
-// WalkFunc is the type of the function called for each route visited by Walk.
-// At every invocation, it is given the current route, and the current router,
-// and a list of ancestor routes that lead to the current route.
-type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
-
-func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
-	for _, t := range r.routes {
-		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
-			continue
-		}
-
-		err := walkFn(t, r, ancestors)
-		if err == SkipRouter {
-			continue
-		}
-		for _, sr := range t.matchers {
-			if h, ok := sr.(*Router); ok {
-				err := h.walk(walkFn, ancestors)
-				if err != nil {
-					return err
-				}
-			}
-		}
-		if h, ok := t.handler.(*Router); ok {
-			ancestors = append(ancestors, t)
-			err := h.walk(walkFn, ancestors)
-			if err != nil {
-				return err
-			}
-			ancestors = ancestors[:len(ancestors)-1]
-		}
-	}
-	return nil
-}
-
-// ----------------------------------------------------------------------------
-// Context
-// ----------------------------------------------------------------------------
-
-// RouteMatch stores information about a matched route.
-type RouteMatch struct {
-	Route   *Route
-	Handler http.Handler
-	Vars    map[string]string
-}
-
-type contextKey int
-
-const (
-	varsKey contextKey = iota
-	routeKey
-)
-
-// Vars returns the route variables for the current request, if any.
-func Vars(r *http.Request) map[string]string {
-	if rv := contextGet(r, varsKey); rv != nil {
-		return rv.(map[string]string)
-	}
-	return nil
-}
-
-// CurrentRoute returns the matched route for the current request, if any.
-// This only works when called inside the handler of the matched route
-// because the matched route is stored in the request context which is cleared
-// after the handler returns, unless the KeepContext option is set on the
-// Router.
-func CurrentRoute(r *http.Request) *Route {
-	if rv := contextGet(r, routeKey); rv != nil {
-		return rv.(*Route)
-	}
-	return nil
-}
-
-func setVars(r *http.Request, val interface{}) *http.Request {
-	return contextSet(r, varsKey, val)
-}
-
-func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
-	return contextSet(r, routeKey, val)
-}
-
-// ----------------------------------------------------------------------------
-// Helpers
-// ----------------------------------------------------------------------------
-
-// cleanPath returns the canonical path for p, eliminating . and .. elements.
-// Borrowed from the net/http package.
-func cleanPath(p string) string {
-	if p == "" {
-		return "/"
-	}
-	if p[0] != '/' {
-		p = "/" + p
-	}
-	np := path.Clean(p)
-	// path.Clean removes trailing slash except for root;
-	// put the trailing slash back if necessary.
-	if p[len(p)-1] == '/' && np != "/" {
-		np += "/"
-	}
-
-	return np
-}
-
-// uniqueVars returns an error if two slices contain duplicated strings.
-func uniqueVars(s1, s2 []string) error {
-	for _, v1 := range s1 {
-		for _, v2 := range s2 {
-			if v1 == v2 {
-				return fmt.Errorf("mux: duplicated route variable %q", v2)
-			}
-		}
-	}
-	return nil
-}
-
-// checkPairs returns the count of strings passed in, and an error if
-// the count is not an even number.
-func checkPairs(pairs ...string) (int, error) {
-	length := len(pairs)
-	if length%2 != 0 {
-		return length, fmt.Errorf(
-			"mux: number of parameters must be multiple of 2, got %v", pairs)
-	}
-	return length, nil
-}
-
-// mapFromPairsToString converts variadic string parameters to a
-// string to string map.
-func mapFromPairsToString(pairs ...string) (map[string]string, error) {
-	length, err := checkPairs(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	m := make(map[string]string, length/2)
-	for i := 0; i < length; i += 2 {
-		m[pairs[i]] = pairs[i+1]
-	}
-	return m, nil
-}
-
-// mapFromPairsToRegex converts variadic string paramers to a
-// string to regex map.
-func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
-	length, err := checkPairs(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	m := make(map[string]*regexp.Regexp, length/2)
-	for i := 0; i < length; i += 2 {
-		regex, err := regexp.Compile(pairs[i+1])
-		if err != nil {
-			return nil, err
-		}
-		m[pairs[i]] = regex
-	}
-	return m, nil
-}
-
-// matchInArray returns true if the given string value is in the array.
-func matchInArray(arr []string, value string) bool {
-	for _, v := range arr {
-		if v == value {
-			return true
-		}
-	}
-	return false
-}
-
-// matchMapWithString returns true if the given key/value pairs exist in a given map.
-func matchMapWithString(toCheck map[string]string, toMatch map[string][]string, canonicalKey bool) bool {
-	for k, v := range toCheck {
-		// Check if key exists.
-		if canonicalKey {
-			k = http.CanonicalHeaderKey(k)
-		}
-		if values := toMatch[k]; values == nil {
-			return false
-		} else if v != "" {
-			// If value was defined as an empty string we only check that the
-			// key exists. Otherwise we also check for equality.
-			valueExists := false
-			for _, value := range values {
-				if v == value {
-					valueExists = true
-					break
-				}
-			}
-			if !valueExists {
-				return false
-			}
-		}
-	}
-	return true
-}
-
-// matchMapWithRegex returns true if the given key/value pairs exist in a given map compiled against
-// the given regex
-func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]string, canonicalKey bool) bool {
-	for k, v := range toCheck {
-		// Check if key exists.
-		if canonicalKey {
-			k = http.CanonicalHeaderKey(k)
-		}
-		if values := toMatch[k]; values == nil {
-			return false
-		} else if v != nil {
-			// If value was defined as an empty string we only check that the
-			// key exists. Otherwise we also check for equality.
-			valueExists := false
-			for _, value := range values {
-				if v.MatchString(value) {
-					valueExists = true
-					break
-				}
-			}
-			if !valueExists {
-				return false
-			}
-		}
-	}
-	return true
-}

+ 0 - 1439
src/github.com/gorilla/mux/mux_test.go

@@ -1,1439 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"fmt"
-	"net/http"
-	"strings"
-	"testing"
-)
-
-func (r *Route) GoString() string {
-	matchers := make([]string, len(r.matchers))
-	for i, m := range r.matchers {
-		matchers[i] = fmt.Sprintf("%#v", m)
-	}
-	return fmt.Sprintf("&Route{matchers:[]matcher{%s}}", strings.Join(matchers, ", "))
-}
-
-func (r *routeRegexp) GoString() string {
-	return fmt.Sprintf("&routeRegexp{template: %q, matchHost: %t, matchQuery: %t, strictSlash: %t, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.matchHost, r.matchQuery, r.strictSlash, r.regexp.String(), r.reverse, r.varsN, r.varsR)
-}
-
-type routeTest struct {
-	title          string            // title of the test
-	route          *Route            // the route being tested
-	request        *http.Request     // a request to test the route
-	vars           map[string]string // the expected vars of the match
-	host           string            // the expected host of the match
-	path           string            // the expected path of the match
-	path_template  string            // the expected path template to match
-	host_template  string            // the expected host template to match
-	shouldMatch    bool              // whether the request is expected to match the route at all
-	shouldRedirect bool              // whether the request should result in a redirect
-}
-
-func TestHost(t *testing.T) {
-	// newRequestHost a new request with a method, url, and host header
-	newRequestHost := func(method, url, host string) *http.Request {
-		req, err := http.NewRequest(method, url, nil)
-		if err != nil {
-			panic(err)
-		}
-		req.Host = host
-		return req
-	}
-
-	tests := []routeTest{
-		{
-			title:       "Host route match",
-			route:       new(Route).Host("aaa.bbb.ccc"),
-			request:     newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Host route, wrong host in request URL",
-			route:       new(Route).Host("aaa.bbb.ccc"),
-			request:     newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Host route with port, match",
-			route:       new(Route).Host("aaa.bbb.ccc:1234"),
-			request:     newRequest("GET", "http://aaa.bbb.ccc:1234/111/222/333"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc:1234",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Host route with port, wrong port in request URL",
-			route:       new(Route).Host("aaa.bbb.ccc:1234"),
-			request:     newRequest("GET", "http://aaa.bbb.ccc:9999/111/222/333"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc:1234",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Host route, match with host in request header",
-			route:       new(Route).Host("aaa.bbb.ccc"),
-			request:     newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Host route, wrong host in request header",
-			route:       new(Route).Host("aaa.bbb.ccc"),
-			request:     newRequestHost("GET", "/111/222/333", "aaa.222.ccc"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc",
-			path:        "",
-			shouldMatch: false,
-		},
-		// BUG {new(Route).Host("aaa.bbb.ccc:1234"), newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:1234"), map[string]string{}, "aaa.bbb.ccc:1234", "", true},
-		{
-			title:       "Host route with port, wrong host in request header",
-			route:       new(Route).Host("aaa.bbb.ccc:1234"),
-			request:     newRequestHost("GET", "/111/222/333", "aaa.bbb.ccc:9999"),
-			vars:        map[string]string{},
-			host:        "aaa.bbb.ccc:1234",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:         "Host route with pattern, match",
-			route:         new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "bbb"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `aaa.{v1:[a-z]{3}}.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host route with pattern, additional capturing group, match",
-			route:         new(Route).Host("aaa.{v1:[a-z]{2}(b|c)}.ccc"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "bbb"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `aaa.{v1:[a-z]{2}(b|c)}.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host route with pattern, wrong host in request URL",
-			route:         new(Route).Host("aaa.{v1:[a-z]{3}}.ccc"),
-			request:       newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "bbb"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `aaa.{v1:[a-z]{3}}.ccc`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Host route with multiple patterns, match",
-			route:         new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host route with multiple patterns, wrong host in request URL",
-			route:         new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}"),
-			request:       newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Host route with hyphenated name and pattern, match",
-			route:         new(Route).Host("aaa.{v-1:[a-z]{3}}.ccc"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v-1": "bbb"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `aaa.{v-1:[a-z]{3}}.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host route with hyphenated name and pattern, additional capturing group, match",
-			route:         new(Route).Host("aaa.{v-1:[a-z]{2}(b|c)}.ccc"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v-1": "bbb"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `aaa.{v-1:[a-z]{2}(b|c)}.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host route with multiple hyphenated names and patterns, match",
-			route:         new(Route).Host("{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v-1": "aaa", "v-2": "bbb", "v-3": "ccc"},
-			host:          "aaa.bbb.ccc",
-			path:          "",
-			host_template: `{v-1:[a-z]{3}}.{v-2:[a-z]{3}}.{v-3:[a-z]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with single pattern with pipe, match",
-			route:         new(Route).Path("/{category:a|b/c}"),
-			request:       newRequest("GET", "http://localhost/a"),
-			vars:          map[string]string{"category": "a"},
-			host:          "",
-			path:          "/a",
-			path_template: `/{category:a|b/c}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with single pattern with pipe, match",
-			route:         new(Route).Path("/{category:a|b/c}"),
-			request:       newRequest("GET", "http://localhost/b/c"),
-			vars:          map[string]string{"category": "b/c"},
-			host:          "",
-			path:          "/b/c",
-			path_template: `/{category:a|b/c}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple patterns with pipe, match",
-			route:         new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"),
-			request:       newRequest("GET", "http://localhost/a/product_name/1"),
-			vars:          map[string]string{"category": "a", "product": "product_name", "id": "1"},
-			host:          "",
-			path:          "/a/product_name/1",
-			path_template: `/{category:a|b/c}/{product}/{id:[0-9]+}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple patterns with pipe, match",
-			route:         new(Route).Path("/{category:a|b/c}/{product}/{id:[0-9]+}"),
-			request:       newRequest("GET", "http://localhost/b/c/product_name/1"),
-			vars:          map[string]string{"category": "b/c", "product": "product_name", "id": "1"},
-			host:          "",
-			path:          "/b/c/product_name/1",
-			path_template: `/{category:a|b/c}/{product}/{id:[0-9]+}`,
-			shouldMatch:   true,
-		},
-	}
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestPath(t *testing.T) {
-	tests := []routeTest{
-		{
-			title:       "Path route, match",
-			route:       new(Route).Path("/111/222/333"),
-			request:     newRequest("GET", "http://localhost/111/222/333"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/111/222/333",
-			shouldMatch: true,
-		},
-		{
-			title:       "Path route, match with trailing slash in request and path",
-			route:       new(Route).Path("/111/"),
-			request:     newRequest("GET", "http://localhost/111/"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/111/",
-			shouldMatch: true,
-		},
-		{
-			title:         "Path route, do not match with trailing slash in path",
-			route:         new(Route).Path("/111/"),
-			request:       newRequest("GET", "http://localhost/111"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "/111",
-			path_template: `/111/`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Path route, do not match with trailing slash in request",
-			route:         new(Route).Path("/111"),
-			request:       newRequest("GET", "http://localhost/111/"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "/111/",
-			path_template: `/111`,
-			shouldMatch:   false,
-		},
-		{
-			title:       "Path route, wrong path in request in request URL",
-			route:       new(Route).Path("/111/222/333"),
-			request:     newRequest("GET", "http://localhost/1/2/3"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/111/222/333",
-			shouldMatch: false,
-		},
-		{
-			title:         "Path route with pattern, match",
-			route:         new(Route).Path("/111/{v1:[0-9]{3}}/333"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v1": "222"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/111/{v1:[0-9]{3}}/333`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with pattern, URL in request does not match",
-			route:         new(Route).Path("/111/{v1:[0-9]{3}}/333"),
-			request:       newRequest("GET", "http://localhost/111/aaa/333"),
-			vars:          map[string]string{"v1": "222"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/111/{v1:[0-9]{3}}/333`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Path route with multiple patterns, match",
-			route:         new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v1": "111", "v2": "222", "v3": "333"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple patterns, URL in request does not match",
-			route:         new(Route).Path("/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/aaa/333"),
-			vars:          map[string]string{"v1": "111", "v2": "222", "v3": "333"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}/{v3:[0-9]{3}}`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Path route with multiple patterns with pipe, match",
-			route:         new(Route).Path("/{category:a|(b/c)}/{product}/{id:[0-9]+}"),
-			request:       newRequest("GET", "http://localhost/a/product_name/1"),
-			vars:          map[string]string{"category": "a", "product": "product_name", "id": "1"},
-			host:          "",
-			path:          "/a/product_name/1",
-			path_template: `/{category:a|(b/c)}/{product}/{id:[0-9]+}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with hyphenated name and pattern, match",
-			route:         new(Route).Path("/111/{v-1:[0-9]{3}}/333"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v-1": "222"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/111/{v-1:[0-9]{3}}/333`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple hyphenated names and patterns, match",
-			route:         new(Route).Path("/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v-1": "111", "v-2": "222", "v-3": "333"},
-			host:          "",
-			path:          "/111/222/333",
-			path_template: `/{v-1:[0-9]{3}}/{v-2:[0-9]{3}}/{v-3:[0-9]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple hyphenated names and patterns with pipe, match",
-			route:         new(Route).Path("/{product-category:a|(b/c)}/{product-name}/{product-id:[0-9]+}"),
-			request:       newRequest("GET", "http://localhost/a/product_name/1"),
-			vars:          map[string]string{"product-category": "a", "product-name": "product_name", "product-id": "1"},
-			host:          "",
-			path:          "/a/product_name/1",
-			path_template: `/{product-category:a|(b/c)}/{product-name}/{product-id:[0-9]+}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Path route with multiple hyphenated names and patterns with pipe and case insensitive, match",
-			route:         new(Route).Path("/{type:(?i:daily|mini|variety)}-{date:\\d{4,4}-\\d{2,2}-\\d{2,2}}"),
-			request:       newRequest("GET", "http://localhost/daily-2016-01-01"),
-			vars:          map[string]string{"type": "daily", "date": "2016-01-01"},
-			host:          "",
-			path:          "/daily-2016-01-01",
-			path_template: `/{type:(?i:daily|mini|variety)}-{date:\d{4,4}-\d{2,2}-\d{2,2}}`,
-			shouldMatch:   true,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestPathPrefix(t *testing.T) {
-	tests := []routeTest{
-		{
-			title:       "PathPrefix route, match",
-			route:       new(Route).PathPrefix("/111"),
-			request:     newRequest("GET", "http://localhost/111/222/333"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/111",
-			shouldMatch: true,
-		},
-		{
-			title:       "PathPrefix route, match substring",
-			route:       new(Route).PathPrefix("/1"),
-			request:     newRequest("GET", "http://localhost/111/222/333"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/1",
-			shouldMatch: true,
-		},
-		{
-			title:       "PathPrefix route, URL prefix in request does not match",
-			route:       new(Route).PathPrefix("/111"),
-			request:     newRequest("GET", "http://localhost/1/2/3"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "/111",
-			shouldMatch: false,
-		},
-		{
-			title:         "PathPrefix route with pattern, match",
-			route:         new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v1": "222"},
-			host:          "",
-			path:          "/111/222",
-			path_template: `/111/{v1:[0-9]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "PathPrefix route with pattern, URL prefix in request does not match",
-			route:         new(Route).PathPrefix("/111/{v1:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/aaa/333"),
-			vars:          map[string]string{"v1": "222"},
-			host:          "",
-			path:          "/111/222",
-			path_template: `/111/{v1:[0-9]{3}}`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "PathPrefix route with multiple patterns, match",
-			route:         new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/222/333"),
-			vars:          map[string]string{"v1": "111", "v2": "222"},
-			host:          "",
-			path:          "/111/222",
-			path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "PathPrefix route with multiple patterns, URL prefix in request does not match",
-			route:         new(Route).PathPrefix("/{v1:[0-9]{3}}/{v2:[0-9]{3}}"),
-			request:       newRequest("GET", "http://localhost/111/aaa/333"),
-			vars:          map[string]string{"v1": "111", "v2": "222"},
-			host:          "",
-			path:          "/111/222",
-			path_template: `/{v1:[0-9]{3}}/{v2:[0-9]{3}}`,
-			shouldMatch:   false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestHostPath(t *testing.T) {
-	tests := []routeTest{
-		{
-			title:         "Host and Path route, match",
-			route:         new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "",
-			path_template: `/111/222/333`,
-			host_template: `aaa.bbb.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host and Path route, wrong host in request URL",
-			route:         new(Route).Host("aaa.bbb.ccc").Path("/111/222/333"),
-			request:       newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "",
-			path_template: `/111/222/333`,
-			host_template: `aaa.bbb.ccc`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Host and Path route with pattern, match",
-			route:         new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "bbb", "v2": "222"},
-			host:          "aaa.bbb.ccc",
-			path:          "/111/222/333",
-			path_template: `/111/{v2:[0-9]{3}}/333`,
-			host_template: `aaa.{v1:[a-z]{3}}.ccc`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host and Path route with pattern, URL in request does not match",
-			route:         new(Route).Host("aaa.{v1:[a-z]{3}}.ccc").Path("/111/{v2:[0-9]{3}}/333"),
-			request:       newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "bbb", "v2": "222"},
-			host:          "aaa.bbb.ccc",
-			path:          "/111/222/333",
-			path_template: `/111/{v2:[0-9]{3}}/333`,
-			host_template: `aaa.{v1:[a-z]{3}}.ccc`,
-			shouldMatch:   false,
-		},
-		{
-			title:         "Host and Path route with multiple patterns, match",
-			route:         new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
-			request:       newRequest("GET", "http://aaa.bbb.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
-			host:          "aaa.bbb.ccc",
-			path:          "/111/222/333",
-			path_template: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`,
-			host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Host and Path route with multiple patterns, URL in request does not match",
-			route:         new(Route).Host("{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}").Path("/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}"),
-			request:       newRequest("GET", "http://aaa.222.ccc/111/222/333"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb", "v3": "ccc", "v4": "111", "v5": "222", "v6": "333"},
-			host:          "aaa.bbb.ccc",
-			path:          "/111/222/333",
-			path_template: `/{v4:[0-9]{3}}/{v5:[0-9]{3}}/{v6:[0-9]{3}}`,
-			host_template: `{v1:[a-z]{3}}.{v2:[a-z]{3}}.{v3:[a-z]{3}}`,
-			shouldMatch:   false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestHeaders(t *testing.T) {
-	// newRequestHeaders creates a new request with a method, url, and headers
-	newRequestHeaders := func(method, url string, headers map[string]string) *http.Request {
-		req, err := http.NewRequest(method, url, nil)
-		if err != nil {
-			panic(err)
-		}
-		for k, v := range headers {
-			req.Header.Add(k, v)
-		}
-		return req
-	}
-
-	tests := []routeTest{
-		{
-			title:       "Headers route, match",
-			route:       new(Route).Headers("foo", "bar", "baz", "ding"),
-			request:     newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "ding"}),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Headers route, bad header values",
-			route:       new(Route).Headers("foo", "bar", "baz", "ding"),
-			request:     newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar", "baz": "dong"}),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Headers route, regex header values to match",
-			route:       new(Route).Headers("foo", "ba[zr]"),
-			request:     newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "bar"}),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Headers route, regex header values to match",
-			route:       new(Route).HeadersRegexp("foo", "ba[zr]"),
-			request:     newRequestHeaders("GET", "http://localhost", map[string]string{"foo": "baz"}),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-
-}
-
-func TestMethods(t *testing.T) {
-	tests := []routeTest{
-		{
-			title:       "Methods route, match GET",
-			route:       new(Route).Methods("GET", "POST"),
-			request:     newRequest("GET", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Methods route, match POST",
-			route:       new(Route).Methods("GET", "POST"),
-			request:     newRequest("POST", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Methods route, bad method",
-			route:       new(Route).Methods("GET", "POST"),
-			request:     newRequest("PUT", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestQueries(t *testing.T) {
-	tests := []routeTest{
-		{
-			title:       "Queries route, match",
-			route:       new(Route).Queries("foo", "bar", "baz", "ding"),
-			request:     newRequest("GET", "http://localhost?foo=bar&baz=ding"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:         "Queries route, match with a query string",
-			route:         new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
-			request:       newRequest("GET", "http://www.example.com/api?foo=bar&baz=ding"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "",
-			path_template: `/api`,
-			host_template: `www.example.com`,
-			shouldMatch:   true,
-		},
-		{
-			title:         "Queries route, match with a query string out of order",
-			route:         new(Route).Host("www.example.com").Path("/api").Queries("foo", "bar", "baz", "ding"),
-			request:       newRequest("GET", "http://www.example.com/api?baz=ding&foo=bar"),
-			vars:          map[string]string{},
-			host:          "",
-			path:          "",
-			path_template: `/api`,
-			host_template: `www.example.com`,
-			shouldMatch:   true,
-		},
-		{
-			title:       "Queries route, bad query",
-			route:       new(Route).Queries("foo", "bar", "baz", "ding"),
-			request:     newRequest("GET", "http://localhost?foo=bar&baz=dong"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with pattern, match",
-			route:       new(Route).Queries("foo", "{v1}"),
-			request:     newRequest("GET", "http://localhost?foo=bar"),
-			vars:        map[string]string{"v1": "bar"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with multiple patterns, match",
-			route:       new(Route).Queries("foo", "{v1}", "baz", "{v2}"),
-			request:     newRequest("GET", "http://localhost?foo=bar&baz=ding"),
-			vars:        map[string]string{"v1": "bar", "v2": "ding"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with regexp pattern, match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]+}"),
-			request:     newRequest("GET", "http://localhost?foo=10"),
-			vars:        map[string]string{"v1": "10"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with regexp pattern, regexp does not match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]+}"),
-			request:     newRequest("GET", "http://localhost?foo=a"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with regexp pattern with quantifier, match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]{1}}"),
-			request:     newRequest("GET", "http://localhost?foo=1"),
-			vars:        map[string]string{"v1": "1"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with regexp pattern with quantifier, additional variable in query string, match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]{1}}"),
-			request:     newRequest("GET", "http://localhost?bar=2&foo=1"),
-			vars:        map[string]string{"v1": "1"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with regexp pattern with quantifier, regexp does not match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]{1}}"),
-			request:     newRequest("GET", "http://localhost?foo=12"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with regexp pattern with quantifier, additional capturing group",
-			route:       new(Route).Queries("foo", "{v1:[0-9]{1}(a|b)}"),
-			request:     newRequest("GET", "http://localhost?foo=1a"),
-			vars:        map[string]string{"v1": "1a"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with regexp pattern with quantifier, additional variable in query string, regexp does not match",
-			route:       new(Route).Queries("foo", "{v1:[0-9]{1}}"),
-			request:     newRequest("GET", "http://localhost?foo=12"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with hyphenated name, match",
-			route:       new(Route).Queries("foo", "{v-1}"),
-			request:     newRequest("GET", "http://localhost?foo=bar"),
-			vars:        map[string]string{"v-1": "bar"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with multiple hyphenated names, match",
-			route:       new(Route).Queries("foo", "{v-1}", "baz", "{v-2}"),
-			request:     newRequest("GET", "http://localhost?foo=bar&baz=ding"),
-			vars:        map[string]string{"v-1": "bar", "v-2": "ding"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with hyphenate name and pattern, match",
-			route:       new(Route).Queries("foo", "{v-1:[0-9]+}"),
-			request:     newRequest("GET", "http://localhost?foo=10"),
-			vars:        map[string]string{"v-1": "10"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with hyphenated name and pattern with quantifier, additional capturing group",
-			route:       new(Route).Queries("foo", "{v-1:[0-9]{1}(a|b)}"),
-			request:     newRequest("GET", "http://localhost?foo=1a"),
-			vars:        map[string]string{"v-1": "1a"},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with empty value, should match",
-			route:       new(Route).Queries("foo", ""),
-			request:     newRequest("GET", "http://localhost?foo=bar"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with empty value and no parameter in request, should not match",
-			route:       new(Route).Queries("foo", ""),
-			request:     newRequest("GET", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with empty value and empty parameter in request, should match",
-			route:       new(Route).Queries("foo", ""),
-			request:     newRequest("GET", "http://localhost?foo="),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route with overlapping value, should not match",
-			route:       new(Route).Queries("foo", "bar"),
-			request:     newRequest("GET", "http://localhost?foo=barfoo"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with no parameter in request, should not match",
-			route:       new(Route).Queries("foo", "{bar}"),
-			request:     newRequest("GET", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-		{
-			title:       "Queries route with empty parameter in request, should match",
-			route:       new(Route).Queries("foo", "{bar}"),
-			request:     newRequest("GET", "http://localhost?foo="),
-			vars:        map[string]string{"foo": ""},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Queries route, bad submatch",
-			route:       new(Route).Queries("foo", "bar", "baz", "ding"),
-			request:     newRequest("GET", "http://localhost?fffoo=bar&baz=dingggg"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestSchemes(t *testing.T) {
-	tests := []routeTest{
-		// Schemes
-		{
-			title:       "Schemes route, match https",
-			route:       new(Route).Schemes("https", "ftp"),
-			request:     newRequest("GET", "https://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Schemes route, match ftp",
-			route:       new(Route).Schemes("https", "ftp"),
-			request:     newRequest("GET", "ftp://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "Schemes route, bad scheme",
-			route:       new(Route).Schemes("https", "ftp"),
-			request:     newRequest("GET", "http://localhost"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-	}
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestMatcherFunc(t *testing.T) {
-	m := func(r *http.Request, m *RouteMatch) bool {
-		if r.URL.Host == "aaa.bbb.ccc" {
-			return true
-		}
-		return false
-	}
-
-	tests := []routeTest{
-		{
-			title:       "MatchFunc route, match",
-			route:       new(Route).MatcherFunc(m),
-			request:     newRequest("GET", "http://aaa.bbb.ccc"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: true,
-		},
-		{
-			title:       "MatchFunc route, non-match",
-			route:       new(Route).MatcherFunc(m),
-			request:     newRequest("GET", "http://aaa.222.ccc"),
-			vars:        map[string]string{},
-			host:        "",
-			path:        "",
-			shouldMatch: false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestBuildVarsFunc(t *testing.T) {
-	tests := []routeTest{
-		{
-			title: "BuildVarsFunc set on route",
-			route: new(Route).Path(`/111/{v1:\d}{v2:.*}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
-				vars["v1"] = "3"
-				vars["v2"] = "a"
-				return vars
-			}),
-			request:       newRequest("GET", "http://localhost/111/2"),
-			path:          "/111/3a",
-			path_template: `/111/{v1:\d}{v2:.*}`,
-			shouldMatch:   true,
-		},
-		{
-			title: "BuildVarsFunc set on route and parent route",
-			route: new(Route).PathPrefix(`/{v1:\d}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
-				vars["v1"] = "2"
-				return vars
-			}).Subrouter().Path(`/{v2:\w}`).BuildVarsFunc(func(vars map[string]string) map[string]string {
-				vars["v2"] = "b"
-				return vars
-			}),
-			request:       newRequest("GET", "http://localhost/1/a"),
-			path:          "/2/b",
-			path_template: `/{v1:\d}/{v2:\w}`,
-			shouldMatch:   true,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestSubRouter(t *testing.T) {
-	subrouter1 := new(Route).Host("{v1:[a-z]+}.google.com").Subrouter()
-	subrouter2 := new(Route).PathPrefix("/foo/{v1}").Subrouter()
-
-	tests := []routeTest{
-		{
-			route:         subrouter1.Path("/{v2:[a-z]+}"),
-			request:       newRequest("GET", "http://aaa.google.com/bbb"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb"},
-			host:          "aaa.google.com",
-			path:          "/bbb",
-			path_template: `/{v2:[a-z]+}`,
-			host_template: `{v1:[a-z]+}.google.com`,
-			shouldMatch:   true,
-		},
-		{
-			route:         subrouter1.Path("/{v2:[a-z]+}"),
-			request:       newRequest("GET", "http://111.google.com/111"),
-			vars:          map[string]string{"v1": "aaa", "v2": "bbb"},
-			host:          "aaa.google.com",
-			path:          "/bbb",
-			path_template: `/{v2:[a-z]+}`,
-			host_template: `{v1:[a-z]+}.google.com`,
-			shouldMatch:   false,
-		},
-		{
-			route:         subrouter2.Path("/baz/{v2}"),
-			request:       newRequest("GET", "http://localhost/foo/bar/baz/ding"),
-			vars:          map[string]string{"v1": "bar", "v2": "ding"},
-			host:          "",
-			path:          "/foo/bar/baz/ding",
-			path_template: `/foo/{v1}/baz/{v2}`,
-			shouldMatch:   true,
-		},
-		{
-			route:         subrouter2.Path("/baz/{v2}"),
-			request:       newRequest("GET", "http://localhost/foo/bar"),
-			vars:          map[string]string{"v1": "bar", "v2": "ding"},
-			host:          "",
-			path:          "/foo/bar/baz/ding",
-			path_template: `/foo/{v1}/baz/{v2}`,
-			shouldMatch:   false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestNamedRoutes(t *testing.T) {
-	r1 := NewRouter()
-	r1.NewRoute().Name("a")
-	r1.NewRoute().Name("b")
-	r1.NewRoute().Name("c")
-
-	r2 := r1.NewRoute().Subrouter()
-	r2.NewRoute().Name("d")
-	r2.NewRoute().Name("e")
-	r2.NewRoute().Name("f")
-
-	r3 := r2.NewRoute().Subrouter()
-	r3.NewRoute().Name("g")
-	r3.NewRoute().Name("h")
-	r3.NewRoute().Name("i")
-
-	if r1.namedRoutes == nil || len(r1.namedRoutes) != 9 {
-		t.Errorf("Expected 9 named routes, got %v", r1.namedRoutes)
-	} else if r1.Get("i") == nil {
-		t.Errorf("Subroute name not registered")
-	}
-}
-
-func TestStrictSlash(t *testing.T) {
-	r := NewRouter()
-	r.StrictSlash(true)
-
-	tests := []routeTest{
-		{
-			title:          "Redirect path without slash",
-			route:          r.NewRoute().Path("/111/"),
-			request:        newRequest("GET", "http://localhost/111"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/111/",
-			shouldMatch:    true,
-			shouldRedirect: true,
-		},
-		{
-			title:          "Do not redirect path with slash",
-			route:          r.NewRoute().Path("/111/"),
-			request:        newRequest("GET", "http://localhost/111/"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/111/",
-			shouldMatch:    true,
-			shouldRedirect: false,
-		},
-		{
-			title:          "Redirect path with slash",
-			route:          r.NewRoute().Path("/111"),
-			request:        newRequest("GET", "http://localhost/111/"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/111",
-			shouldMatch:    true,
-			shouldRedirect: true,
-		},
-		{
-			title:          "Do not redirect path without slash",
-			route:          r.NewRoute().Path("/111"),
-			request:        newRequest("GET", "http://localhost/111"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/111",
-			shouldMatch:    true,
-			shouldRedirect: false,
-		},
-		{
-			title:          "Propagate StrictSlash to subrouters",
-			route:          r.NewRoute().PathPrefix("/static/").Subrouter().Path("/images/"),
-			request:        newRequest("GET", "http://localhost/static/images"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/static/images/",
-			shouldMatch:    true,
-			shouldRedirect: true,
-		},
-		{
-			title:          "Ignore StrictSlash for path prefix",
-			route:          r.NewRoute().PathPrefix("/static/"),
-			request:        newRequest("GET", "http://localhost/static/logo.png"),
-			vars:           map[string]string{},
-			host:           "",
-			path:           "/static/",
-			shouldMatch:    true,
-			shouldRedirect: false,
-		},
-	}
-
-	for _, test := range tests {
-		testRoute(t, test)
-		testTemplate(t, test)
-	}
-}
-
-func TestWalkSingleDepth(t *testing.T) {
-	r0 := NewRouter()
-	r1 := NewRouter()
-	r2 := NewRouter()
-
-	r0.Path("/g")
-	r0.Path("/o")
-	r0.Path("/d").Handler(r1)
-	r0.Path("/r").Handler(r2)
-	r0.Path("/a")
-
-	r1.Path("/z")
-	r1.Path("/i")
-	r1.Path("/l")
-	r1.Path("/l")
-
-	r2.Path("/i")
-	r2.Path("/l")
-	r2.Path("/l")
-
-	paths := []string{"g", "o", "r", "i", "l", "l", "a"}
-	depths := []int{0, 0, 0, 1, 1, 1, 0}
-	i := 0
-	err := r0.Walk(func(route *Route, router *Router, ancestors []*Route) error {
-		matcher := route.matchers[0].(*routeRegexp)
-		if matcher.template == "/d" {
-			return SkipRouter
-		}
-		if len(ancestors) != depths[i] {
-			t.Errorf(`Expected depth of %d at i = %d; got "%d"`, depths[i], i, len(ancestors))
-		}
-		if matcher.template != "/"+paths[i] {
-			t.Errorf(`Expected "/%s" at i = %d; got "%s"`, paths[i], i, matcher.template)
-		}
-		i++
-		return nil
-	})
-	if err != nil {
-		panic(err)
-	}
-	if i != len(paths) {
-		t.Errorf("Expected %d routes, found %d", len(paths), i)
-	}
-}
-
-func TestWalkNested(t *testing.T) {
-	router := NewRouter()
-
-	g := router.Path("/g").Subrouter()
-	o := g.PathPrefix("/o").Subrouter()
-	r := o.PathPrefix("/r").Subrouter()
-	i := r.PathPrefix("/i").Subrouter()
-	l1 := i.PathPrefix("/l").Subrouter()
-	l2 := l1.PathPrefix("/l").Subrouter()
-	l2.Path("/a")
-
-	paths := []string{"/g", "/g/o", "/g/o/r", "/g/o/r/i", "/g/o/r/i/l", "/g/o/r/i/l/l", "/g/o/r/i/l/l/a"}
-	idx := 0
-	err := router.Walk(func(route *Route, router *Router, ancestors []*Route) error {
-		path := paths[idx]
-		tpl := route.regexp.path.template
-		if tpl != path {
-			t.Errorf(`Expected %s got %s`, path, tpl)
-		}
-		idx++
-		return nil
-	})
-	if err != nil {
-		panic(err)
-	}
-	if idx != len(paths) {
-		t.Errorf("Expected %d routes, found %d", len(paths), idx)
-	}
-}
-
-func TestSubrouterErrorHandling(t *testing.T) {
-	superRouterCalled := false
-	subRouterCalled := false
-
-	router := NewRouter()
-	router.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		superRouterCalled = true
-	})
-	subRouter := router.PathPrefix("/bign8").Subrouter()
-	subRouter.NotFoundHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
-		subRouterCalled = true
-	})
-
-	req, _ := http.NewRequest("GET", "http://localhost/bign8/was/here", nil)
-	router.ServeHTTP(NewRecorder(), req)
-
-	if superRouterCalled {
-		t.Error("Super router 404 handler called when sub-router 404 handler is available.")
-	}
-	if !subRouterCalled {
-		t.Error("Sub-router 404 handler was not called.")
-	}
-}
-
-// ----------------------------------------------------------------------------
-// Helpers
-// ----------------------------------------------------------------------------
-
-func getRouteTemplate(route *Route) string {
-	host, err := route.GetHostTemplate()
-	if err != nil {
-		host = "none"
-	}
-	path, err := route.GetPathTemplate()
-	if err != nil {
-		path = "none"
-	}
-	return fmt.Sprintf("Host: %v, Path: %v", host, path)
-}
-
-func testRoute(t *testing.T, test routeTest) {
-	request := test.request
-	route := test.route
-	vars := test.vars
-	shouldMatch := test.shouldMatch
-	host := test.host
-	path := test.path
-	url := test.host + test.path
-	shouldRedirect := test.shouldRedirect
-
-	var match RouteMatch
-	ok := route.Match(request, &match)
-	if ok != shouldMatch {
-		msg := "Should match"
-		if !shouldMatch {
-			msg = "Should not match"
-		}
-		t.Errorf("(%v) %v:\nRoute: %#v\nRequest: %#v\nVars: %v\n", test.title, msg, route, request, vars)
-		return
-	}
-	if shouldMatch {
-		if test.vars != nil && !stringMapEqual(test.vars, match.Vars) {
-			t.Errorf("(%v) Vars not equal: expected %v, got %v", test.title, vars, match.Vars)
-			return
-		}
-		if host != "" {
-			u, _ := test.route.URLHost(mapToPairs(match.Vars)...)
-			if host != u.Host {
-				t.Errorf("(%v) URLHost not equal: expected %v, got %v -- %v", test.title, host, u.Host, getRouteTemplate(route))
-				return
-			}
-		}
-		if path != "" {
-			u, _ := route.URLPath(mapToPairs(match.Vars)...)
-			if path != u.Path {
-				t.Errorf("(%v) URLPath not equal: expected %v, got %v -- %v", test.title, path, u.Path, getRouteTemplate(route))
-				return
-			}
-		}
-		if url != "" {
-			u, _ := route.URL(mapToPairs(match.Vars)...)
-			if url != u.Host+u.Path {
-				t.Errorf("(%v) URL not equal: expected %v, got %v -- %v", test.title, url, u.Host+u.Path, getRouteTemplate(route))
-				return
-			}
-		}
-		if shouldRedirect && match.Handler == nil {
-			t.Errorf("(%v) Did not redirect", test.title)
-			return
-		}
-		if !shouldRedirect && match.Handler != nil {
-			t.Errorf("(%v) Unexpected redirect", test.title)
-			return
-		}
-	}
-}
-
-func testTemplate(t *testing.T, test routeTest) {
-	route := test.route
-	path_template := test.path_template
-	if len(path_template) == 0 {
-		path_template = test.path
-	}
-	host_template := test.host_template
-	if len(host_template) == 0 {
-		host_template = test.host
-	}
-
-	path_tmpl, path_err := route.GetPathTemplate()
-	if path_err == nil && path_tmpl != path_template {
-		t.Errorf("(%v) GetPathTemplate not equal: expected %v, got %v", test.title, path_template, path_tmpl)
-	}
-
-	host_tmpl, host_err := route.GetHostTemplate()
-	if host_err == nil && host_tmpl != host_template {
-		t.Errorf("(%v) GetHostTemplate not equal: expected %v, got %v", test.title, host_template, host_tmpl)
-	}
-}
-
-type TestA301ResponseWriter struct {
-	hh     http.Header
-	status int
-}
-
-func (ho TestA301ResponseWriter) Header() http.Header {
-	return http.Header(ho.hh)
-}
-
-func (ho TestA301ResponseWriter) Write(b []byte) (int, error) {
-	return 0, nil
-}
-
-func (ho TestA301ResponseWriter) WriteHeader(code int) {
-	ho.status = code
-}
-
-func Test301Redirect(t *testing.T) {
-	m := make(http.Header)
-
-	func1 := func(w http.ResponseWriter, r *http.Request) {}
-	func2 := func(w http.ResponseWriter, r *http.Request) {}
-
-	r := NewRouter()
-	r.HandleFunc("/api/", func2).Name("func2")
-	r.HandleFunc("/", func1).Name("func1")
-
-	req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil)
-
-	res := TestA301ResponseWriter{
-		hh:     m,
-		status: 0,
-	}
-	r.ServeHTTP(&res, req)
-
-	if "http://localhost/api/?abc=def" != res.hh["Location"][0] {
-		t.Errorf("Should have complete URL with query string")
-	}
-}
-
-func TestSkipClean(t *testing.T) {
-	func1 := func(w http.ResponseWriter, r *http.Request) {}
-	func2 := func(w http.ResponseWriter, r *http.Request) {}
-
-	r := NewRouter()
-	r.SkipClean(true)
-	r.HandleFunc("/api/", func2).Name("func2")
-	r.HandleFunc("/", func1).Name("func1")
-
-	req, _ := http.NewRequest("GET", "http://localhost//api/?abc=def", nil)
-	res := NewRecorder()
-	r.ServeHTTP(res, req)
-
-	if len(res.HeaderMap["Location"]) != 0 {
-		t.Errorf("Shouldn't redirect since skip clean is disabled")
-	}
-}
-
-// https://plus.google.com/101022900381697718949/posts/eWy6DjFJ6uW
-func TestSubrouterHeader(t *testing.T) {
-	expected := "func1 response"
-	func1 := func(w http.ResponseWriter, r *http.Request) {
-		fmt.Fprint(w, expected)
-	}
-	func2 := func(http.ResponseWriter, *http.Request) {}
-
-	r := NewRouter()
-	s := r.Headers("SomeSpecialHeader", "").Subrouter()
-	s.HandleFunc("/", func1).Name("func1")
-	r.HandleFunc("/", func2).Name("func2")
-
-	req, _ := http.NewRequest("GET", "http://localhost/", nil)
-	req.Header.Add("SomeSpecialHeader", "foo")
-	match := new(RouteMatch)
-	matched := r.Match(req, match)
-	if !matched {
-		t.Errorf("Should match request")
-	}
-	if match.Route.GetName() != "func1" {
-		t.Errorf("Expecting func1 handler, got %s", match.Route.GetName())
-	}
-	resp := NewRecorder()
-	match.Handler.ServeHTTP(resp, req)
-	if resp.Body.String() != expected {
-		t.Errorf("Expecting %q", expected)
-	}
-}
-
-// mapToPairs converts a string map to a slice of string pairs
-func mapToPairs(m map[string]string) []string {
-	var i int
-	p := make([]string, len(m)*2)
-	for k, v := range m {
-		p[i] = k
-		p[i+1] = v
-		i += 2
-	}
-	return p
-}
-
-// stringMapEqual checks the equality of two string maps
-func stringMapEqual(m1, m2 map[string]string) bool {
-	nil1 := m1 == nil
-	nil2 := m2 == nil
-	if nil1 != nil2 || len(m1) != len(m2) {
-		return false
-	}
-	for k, v := range m1 {
-		if v != m2[k] {
-			return false
-		}
-	}
-	return true
-}
-
-// newRequest is a helper function to create a new request with a method and url
-func newRequest(method, url string) *http.Request {
-	req, err := http.NewRequest(method, url, nil)
-	if err != nil {
-		panic(err)
-	}
-	return req
-}

+ 0 - 710
src/github.com/gorilla/mux/old_test.go

@@ -1,710 +0,0 @@
-// Old tests ported to Go1. This is a mess. Want to drop it one day.
-
-// Copyright 2011 Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"bytes"
-	"net/http"
-	"testing"
-)
-
-// ----------------------------------------------------------------------------
-// ResponseRecorder
-// ----------------------------------------------------------------------------
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// ResponseRecorder is an implementation of http.ResponseWriter that
-// records its mutations for later inspection in tests.
-type ResponseRecorder struct {
-	Code      int           // the HTTP response code from WriteHeader
-	HeaderMap http.Header   // the HTTP response headers
-	Body      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
-	Flushed   bool
-}
-
-// NewRecorder returns an initialized ResponseRecorder.
-func NewRecorder() *ResponseRecorder {
-	return &ResponseRecorder{
-		HeaderMap: make(http.Header),
-		Body:      new(bytes.Buffer),
-	}
-}
-
-// Header returns the response headers.
-func (rw *ResponseRecorder) Header() http.Header {
-	return rw.HeaderMap
-}
-
-// Write always succeeds and writes to rw.Body, if not nil.
-func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
-	if rw.Body != nil {
-		rw.Body.Write(buf)
-	}
-	if rw.Code == 0 {
-		rw.Code = http.StatusOK
-	}
-	return len(buf), nil
-}
-
-// WriteHeader sets rw.Code.
-func (rw *ResponseRecorder) WriteHeader(code int) {
-	rw.Code = code
-}
-
-// Flush sets rw.Flushed to true.
-func (rw *ResponseRecorder) Flush() {
-	rw.Flushed = true
-}
-
-// ----------------------------------------------------------------------------
-
-func TestRouteMatchers(t *testing.T) {
-	var scheme, host, path, query, method string
-	var headers map[string]string
-	var resultVars map[bool]map[string]string
-
-	router := NewRouter()
-	router.NewRoute().Host("{var1}.google.com").
-		Path("/{var2:[a-z]+}/{var3:[0-9]+}").
-		Queries("foo", "bar").
-		Methods("GET").
-		Schemes("https").
-		Headers("x-requested-with", "XMLHttpRequest")
-	router.NewRoute().Host("www.{var4}.com").
-		PathPrefix("/foo/{var5:[a-z]+}/{var6:[0-9]+}").
-		Queries("baz", "ding").
-		Methods("POST").
-		Schemes("http").
-		Headers("Content-Type", "application/json")
-
-	reset := func() {
-		// Everything match.
-		scheme = "https"
-		host = "www.google.com"
-		path = "/product/42"
-		query = "?foo=bar"
-		method = "GET"
-		headers = map[string]string{"X-Requested-With": "XMLHttpRequest"}
-		resultVars = map[bool]map[string]string{
-			true:  {"var1": "www", "var2": "product", "var3": "42"},
-			false: {},
-		}
-	}
-
-	reset2 := func() {
-		// Everything match.
-		scheme = "http"
-		host = "www.google.com"
-		path = "/foo/product/42/path/that/is/ignored"
-		query = "?baz=ding"
-		method = "POST"
-		headers = map[string]string{"Content-Type": "application/json"}
-		resultVars = map[bool]map[string]string{
-			true:  {"var4": "google", "var5": "product", "var6": "42"},
-			false: {},
-		}
-	}
-
-	match := func(shouldMatch bool) {
-		url := scheme + "://" + host + path + query
-		request, _ := http.NewRequest(method, url, nil)
-		for key, value := range headers {
-			request.Header.Add(key, value)
-		}
-
-		var routeMatch RouteMatch
-		matched := router.Match(request, &routeMatch)
-		if matched != shouldMatch {
-			// Need better messages. :)
-			if matched {
-				t.Errorf("Should match.")
-			} else {
-				t.Errorf("Should not match.")
-			}
-		}
-
-		if matched {
-			currentRoute := routeMatch.Route
-			if currentRoute == nil {
-				t.Errorf("Expected a current route.")
-			}
-			vars := routeMatch.Vars
-			expectedVars := resultVars[shouldMatch]
-			if len(vars) != len(expectedVars) {
-				t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
-			}
-			for name, value := range vars {
-				if expectedVars[name] != value {
-					t.Errorf("Expected vars: %v Got: %v.", expectedVars, vars)
-				}
-			}
-		}
-	}
-
-	// 1st route --------------------------------------------------------------
-
-	// Everything match.
-	reset()
-	match(true)
-
-	// Scheme doesn't match.
-	reset()
-	scheme = "http"
-	match(false)
-
-	// Host doesn't match.
-	reset()
-	host = "www.mygoogle.com"
-	match(false)
-
-	// Path doesn't match.
-	reset()
-	path = "/product/notdigits"
-	match(false)
-
-	// Query doesn't match.
-	reset()
-	query = "?foo=baz"
-	match(false)
-
-	// Method doesn't match.
-	reset()
-	method = "POST"
-	match(false)
-
-	// Header doesn't match.
-	reset()
-	headers = map[string]string{}
-	match(false)
-
-	// Everything match, again.
-	reset()
-	match(true)
-
-	// 2nd route --------------------------------------------------------------
-
-	// Everything match.
-	reset2()
-	match(true)
-
-	// Scheme doesn't match.
-	reset2()
-	scheme = "https"
-	match(false)
-
-	// Host doesn't match.
-	reset2()
-	host = "sub.google.com"
-	match(false)
-
-	// Path doesn't match.
-	reset2()
-	path = "/bar/product/42"
-	match(false)
-
-	// Query doesn't match.
-	reset2()
-	query = "?foo=baz"
-	match(false)
-
-	// Method doesn't match.
-	reset2()
-	method = "GET"
-	match(false)
-
-	// Header doesn't match.
-	reset2()
-	headers = map[string]string{}
-	match(false)
-
-	// Everything match, again.
-	reset2()
-	match(true)
-}
-
-type headerMatcherTest struct {
-	matcher headerMatcher
-	headers map[string]string
-	result  bool
-}
-
-var headerMatcherTests = []headerMatcherTest{
-	{
-		matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
-		headers: map[string]string{"X-Requested-With": "XMLHttpRequest"},
-		result:  true,
-	},
-	{
-		matcher: headerMatcher(map[string]string{"x-requested-with": ""}),
-		headers: map[string]string{"X-Requested-With": "anything"},
-		result:  true,
-	},
-	{
-		matcher: headerMatcher(map[string]string{"x-requested-with": "XMLHttpRequest"}),
-		headers: map[string]string{},
-		result:  false,
-	},
-}
-
-type hostMatcherTest struct {
-	matcher *Route
-	url     string
-	vars    map[string]string
-	result  bool
-}
-
-var hostMatcherTests = []hostMatcherTest{
-	{
-		matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
-		url:     "http://abc.def.ghi/",
-		vars:    map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
-		result:  true,
-	},
-	{
-		matcher: NewRouter().NewRoute().Host("{foo:[a-z][a-z][a-z]}.{bar:[a-z][a-z][a-z]}.{baz:[a-z][a-z][a-z]}"),
-		url:     "http://a.b.c/",
-		vars:    map[string]string{"foo": "abc", "bar": "def", "baz": "ghi"},
-		result:  false,
-	},
-}
-
-type methodMatcherTest struct {
-	matcher methodMatcher
-	method  string
-	result  bool
-}
-
-var methodMatcherTests = []methodMatcherTest{
-	{
-		matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
-		method:  "GET",
-		result:  true,
-	},
-	{
-		matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
-		method:  "POST",
-		result:  true,
-	},
-	{
-		matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
-		method:  "PUT",
-		result:  true,
-	},
-	{
-		matcher: methodMatcher([]string{"GET", "POST", "PUT"}),
-		method:  "DELETE",
-		result:  false,
-	},
-}
-
-type pathMatcherTest struct {
-	matcher *Route
-	url     string
-	vars    map[string]string
-	result  bool
-}
-
-var pathMatcherTests = []pathMatcherTest{
-	{
-		matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
-		url:     "http://localhost:8080/123/456/789",
-		vars:    map[string]string{"foo": "123", "bar": "456", "baz": "789"},
-		result:  true,
-	},
-	{
-		matcher: NewRouter().NewRoute().Path("/{foo:[0-9][0-9][0-9]}/{bar:[0-9][0-9][0-9]}/{baz:[0-9][0-9][0-9]}"),
-		url:     "http://localhost:8080/1/2/3",
-		vars:    map[string]string{"foo": "123", "bar": "456", "baz": "789"},
-		result:  false,
-	},
-}
-
-type schemeMatcherTest struct {
-	matcher schemeMatcher
-	url     string
-	result  bool
-}
-
-var schemeMatcherTests = []schemeMatcherTest{
-	{
-		matcher: schemeMatcher([]string{"http", "https"}),
-		url:     "http://localhost:8080/",
-		result:  true,
-	},
-	{
-		matcher: schemeMatcher([]string{"http", "https"}),
-		url:     "https://localhost:8080/",
-		result:  true,
-	},
-	{
-		matcher: schemeMatcher([]string{"https"}),
-		url:     "http://localhost:8080/",
-		result:  false,
-	},
-	{
-		matcher: schemeMatcher([]string{"http"}),
-		url:     "https://localhost:8080/",
-		result:  false,
-	},
-}
-
-type urlBuildingTest struct {
-	route *Route
-	vars  []string
-	url   string
-}
-
-var urlBuildingTests = []urlBuildingTest{
-	{
-		route: new(Route).Host("foo.domain.com"),
-		vars:  []string{},
-		url:   "http://foo.domain.com",
-	},
-	{
-		route: new(Route).Host("{subdomain}.domain.com"),
-		vars:  []string{"subdomain", "bar"},
-		url:   "http://bar.domain.com",
-	},
-	{
-		route: new(Route).Host("foo.domain.com").Path("/articles"),
-		vars:  []string{},
-		url:   "http://foo.domain.com/articles",
-	},
-	{
-		route: new(Route).Path("/articles"),
-		vars:  []string{},
-		url:   "/articles",
-	},
-	{
-		route: new(Route).Path("/articles/{category}/{id:[0-9]+}"),
-		vars:  []string{"category", "technology", "id", "42"},
-		url:   "/articles/technology/42",
-	},
-	{
-		route: new(Route).Host("{subdomain}.domain.com").Path("/articles/{category}/{id:[0-9]+}"),
-		vars:  []string{"subdomain", "foo", "category", "technology", "id", "42"},
-		url:   "http://foo.domain.com/articles/technology/42",
-	},
-}
-
-func TestHeaderMatcher(t *testing.T) {
-	for _, v := range headerMatcherTests {
-		request, _ := http.NewRequest("GET", "http://localhost:8080/", nil)
-		for key, value := range v.headers {
-			request.Header.Add(key, value)
-		}
-		var routeMatch RouteMatch
-		result := v.matcher.Match(request, &routeMatch)
-		if result != v.result {
-			if v.result {
-				t.Errorf("%#v: should match %v.", v.matcher, request.Header)
-			} else {
-				t.Errorf("%#v: should not match %v.", v.matcher, request.Header)
-			}
-		}
-	}
-}
-
-func TestHostMatcher(t *testing.T) {
-	for _, v := range hostMatcherTests {
-		request, _ := http.NewRequest("GET", v.url, nil)
-		var routeMatch RouteMatch
-		result := v.matcher.Match(request, &routeMatch)
-		vars := routeMatch.Vars
-		if result != v.result {
-			if v.result {
-				t.Errorf("%#v: should match %v.", v.matcher, v.url)
-			} else {
-				t.Errorf("%#v: should not match %v.", v.matcher, v.url)
-			}
-		}
-		if result {
-			if len(vars) != len(v.vars) {
-				t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
-			}
-			for name, value := range vars {
-				if v.vars[name] != value {
-					t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
-				}
-			}
-		} else {
-			if len(vars) != 0 {
-				t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
-			}
-		}
-	}
-}
-
-func TestMethodMatcher(t *testing.T) {
-	for _, v := range methodMatcherTests {
-		request, _ := http.NewRequest(v.method, "http://localhost:8080/", nil)
-		var routeMatch RouteMatch
-		result := v.matcher.Match(request, &routeMatch)
-		if result != v.result {
-			if v.result {
-				t.Errorf("%#v: should match %v.", v.matcher, v.method)
-			} else {
-				t.Errorf("%#v: should not match %v.", v.matcher, v.method)
-			}
-		}
-	}
-}
-
-func TestPathMatcher(t *testing.T) {
-	for _, v := range pathMatcherTests {
-		request, _ := http.NewRequest("GET", v.url, nil)
-		var routeMatch RouteMatch
-		result := v.matcher.Match(request, &routeMatch)
-		vars := routeMatch.Vars
-		if result != v.result {
-			if v.result {
-				t.Errorf("%#v: should match %v.", v.matcher, v.url)
-			} else {
-				t.Errorf("%#v: should not match %v.", v.matcher, v.url)
-			}
-		}
-		if result {
-			if len(vars) != len(v.vars) {
-				t.Errorf("%#v: vars length should be %v, got %v.", v.matcher, len(v.vars), len(vars))
-			}
-			for name, value := range vars {
-				if v.vars[name] != value {
-					t.Errorf("%#v: expected value %v for key %v, got %v.", v.matcher, v.vars[name], name, value)
-				}
-			}
-		} else {
-			if len(vars) != 0 {
-				t.Errorf("%#v: vars length should be 0, got %v.", v.matcher, len(vars))
-			}
-		}
-	}
-}
-
-func TestSchemeMatcher(t *testing.T) {
-	for _, v := range schemeMatcherTests {
-		request, _ := http.NewRequest("GET", v.url, nil)
-		var routeMatch RouteMatch
-		result := v.matcher.Match(request, &routeMatch)
-		if result != v.result {
-			if v.result {
-				t.Errorf("%#v: should match %v.", v.matcher, v.url)
-			} else {
-				t.Errorf("%#v: should not match %v.", v.matcher, v.url)
-			}
-		}
-	}
-}
-
-func TestUrlBuilding(t *testing.T) {
-
-	for _, v := range urlBuildingTests {
-		u, _ := v.route.URL(v.vars...)
-		url := u.String()
-		if url != v.url {
-			t.Errorf("expected %v, got %v", v.url, url)
-			/*
-				reversePath := ""
-				reverseHost := ""
-				if v.route.pathTemplate != nil {
-						reversePath = v.route.pathTemplate.Reverse
-				}
-				if v.route.hostTemplate != nil {
-						reverseHost = v.route.hostTemplate.Reverse
-				}
-
-				t.Errorf("%#v:\nexpected: %q\ngot: %q\nreverse path: %q\nreverse host: %q", v.route, v.url, url, reversePath, reverseHost)
-			*/
-		}
-	}
-
-	ArticleHandler := func(w http.ResponseWriter, r *http.Request) {
-	}
-
-	router := NewRouter()
-	router.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).Name("article")
-
-	url, _ := router.Get("article").URL("category", "technology", "id", "42")
-	expected := "/articles/technology/42"
-	if url.String() != expected {
-		t.Errorf("Expected %v, got %v", expected, url.String())
-	}
-}
-
-func TestMatchedRouteName(t *testing.T) {
-	routeName := "stock"
-	router := NewRouter()
-	route := router.NewRoute().Path("/products/").Name(routeName)
-
-	url := "http://www.example.com/products/"
-	request, _ := http.NewRequest("GET", url, nil)
-	var rv RouteMatch
-	ok := router.Match(request, &rv)
-
-	if !ok || rv.Route != route {
-		t.Errorf("Expected same route, got %+v.", rv.Route)
-	}
-
-	retName := rv.Route.GetName()
-	if retName != routeName {
-		t.Errorf("Expected %q, got %q.", routeName, retName)
-	}
-}
-
-func TestSubRouting(t *testing.T) {
-	// Example from docs.
-	router := NewRouter()
-	subrouter := router.NewRoute().Host("www.example.com").Subrouter()
-	route := subrouter.NewRoute().Path("/products/").Name("products")
-
-	url := "http://www.example.com/products/"
-	request, _ := http.NewRequest("GET", url, nil)
-	var rv RouteMatch
-	ok := router.Match(request, &rv)
-
-	if !ok || rv.Route != route {
-		t.Errorf("Expected same route, got %+v.", rv.Route)
-	}
-
-	u, _ := router.Get("products").URL()
-	builtURL := u.String()
-	// Yay, subroute aware of the domain when building!
-	if builtURL != url {
-		t.Errorf("Expected %q, got %q.", url, builtURL)
-	}
-}
-
-func TestVariableNames(t *testing.T) {
-	route := new(Route).Host("{arg1}.domain.com").Path("/{arg1}/{arg2:[0-9]+}")
-	if route.err == nil {
-		t.Errorf("Expected error for duplicated variable names")
-	}
-}
-
-func TestRedirectSlash(t *testing.T) {
-	var route *Route
-	var routeMatch RouteMatch
-	r := NewRouter()
-
-	r.StrictSlash(false)
-	route = r.NewRoute()
-	if route.strictSlash != false {
-		t.Errorf("Expected false redirectSlash.")
-	}
-
-	r.StrictSlash(true)
-	route = r.NewRoute()
-	if route.strictSlash != true {
-		t.Errorf("Expected true redirectSlash.")
-	}
-
-	route = new(Route)
-	route.strictSlash = true
-	route.Path("/{arg1}/{arg2:[0-9]+}/")
-	request, _ := http.NewRequest("GET", "http://localhost/foo/123", nil)
-	routeMatch = RouteMatch{}
-	_ = route.Match(request, &routeMatch)
-	vars := routeMatch.Vars
-	if vars["arg1"] != "foo" {
-		t.Errorf("Expected foo.")
-	}
-	if vars["arg2"] != "123" {
-		t.Errorf("Expected 123.")
-	}
-	rsp := NewRecorder()
-	routeMatch.Handler.ServeHTTP(rsp, request)
-	if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123/" {
-		t.Errorf("Expected redirect header.")
-	}
-
-	route = new(Route)
-	route.strictSlash = true
-	route.Path("/{arg1}/{arg2:[0-9]+}")
-	request, _ = http.NewRequest("GET", "http://localhost/foo/123/", nil)
-	routeMatch = RouteMatch{}
-	_ = route.Match(request, &routeMatch)
-	vars = routeMatch.Vars
-	if vars["arg1"] != "foo" {
-		t.Errorf("Expected foo.")
-	}
-	if vars["arg2"] != "123" {
-		t.Errorf("Expected 123.")
-	}
-	rsp = NewRecorder()
-	routeMatch.Handler.ServeHTTP(rsp, request)
-	if rsp.HeaderMap.Get("Location") != "http://localhost/foo/123" {
-		t.Errorf("Expected redirect header.")
-	}
-}
-
-// Test for the new regexp library, still not available in stable Go.
-func TestNewRegexp(t *testing.T) {
-	var p *routeRegexp
-	var matches []string
-
-	tests := map[string]map[string][]string{
-		"/{foo:a{2}}": {
-			"/a":    nil,
-			"/aa":   {"aa"},
-			"/aaa":  nil,
-			"/aaaa": nil,
-		},
-		"/{foo:a{2,}}": {
-			"/a":    nil,
-			"/aa":   {"aa"},
-			"/aaa":  {"aaa"},
-			"/aaaa": {"aaaa"},
-		},
-		"/{foo:a{2,3}}": {
-			"/a":    nil,
-			"/aa":   {"aa"},
-			"/aaa":  {"aaa"},
-			"/aaaa": nil,
-		},
-		"/{foo:[a-z]{3}}/{bar:[a-z]{2}}": {
-			"/a":       nil,
-			"/ab":      nil,
-			"/abc":     nil,
-			"/abcd":    nil,
-			"/abc/ab":  {"abc", "ab"},
-			"/abc/abc": nil,
-			"/abcd/ab": nil,
-		},
-		`/{foo:\w{3,}}/{bar:\d{2,}}`: {
-			"/a":        nil,
-			"/ab":       nil,
-			"/abc":      nil,
-			"/abc/1":    nil,
-			"/abc/12":   {"abc", "12"},
-			"/abcd/12":  {"abcd", "12"},
-			"/abcd/123": {"abcd", "123"},
-		},
-	}
-
-	for pattern, paths := range tests {
-		p, _ = newRouteRegexp(pattern, false, false, false, false)
-		for path, result := range paths {
-			matches = p.regexp.FindStringSubmatch(path)
-			if result == nil {
-				if matches != nil {
-					t.Errorf("%v should not match %v.", pattern, path)
-				}
-			} else {
-				if len(matches) != len(result)+1 {
-					t.Errorf("Expected %v matches, got %v.", len(result)+1, len(matches))
-				} else {
-					for k, v := range result {
-						if matches[k+1] != v {
-							t.Errorf("Expected %v, got %v.", v, matches[k+1])
-						}
-					}
-				}
-			}
-		}
-	}
-}

+ 0 - 312
src/github.com/gorilla/mux/regexp.go

@@ -1,312 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"bytes"
-	"fmt"
-	"net/http"
-	"net/url"
-	"regexp"
-	"strconv"
-	"strings"
-)
-
-// newRouteRegexp parses a route template and returns a routeRegexp,
-// used to match a host, a path or a query string.
-//
-// It will extract named variables, assemble a regexp to be matched, create
-// a "reverse" template to build URLs and compile regexps to validate variable
-// values used in URL building.
-//
-// Previously we accepted only Python-like identifiers for variable
-// names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that
-// name and pattern can't be empty, and names can't contain a colon.
-func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash bool) (*routeRegexp, error) {
-	// Check if it is well-formed.
-	idxs, errBraces := braceIndices(tpl)
-	if errBraces != nil {
-		return nil, errBraces
-	}
-	// Backup the original.
-	template := tpl
-	// Now let's parse it.
-	defaultPattern := "[^/]+"
-	if matchQuery {
-		defaultPattern = "[^?&]*"
-	} else if matchHost {
-		defaultPattern = "[^.]+"
-		matchPrefix = false
-	}
-	// Only match strict slash if not matching
-	if matchPrefix || matchHost || matchQuery {
-		strictSlash = false
-	}
-	// Set a flag for strictSlash.
-	endSlash := false
-	if strictSlash && strings.HasSuffix(tpl, "/") {
-		tpl = tpl[:len(tpl)-1]
-		endSlash = true
-	}
-	varsN := make([]string, len(idxs)/2)
-	varsR := make([]*regexp.Regexp, len(idxs)/2)
-	pattern := bytes.NewBufferString("")
-	pattern.WriteByte('^')
-	reverse := bytes.NewBufferString("")
-	var end int
-	var err error
-	for i := 0; i < len(idxs); i += 2 {
-		// Set all values we are interested in.
-		raw := tpl[end:idxs[i]]
-		end = idxs[i+1]
-		parts := strings.SplitN(tpl[idxs[i]+1:end-1], ":", 2)
-		name := parts[0]
-		patt := defaultPattern
-		if len(parts) == 2 {
-			patt = parts[1]
-		}
-		// Name or pattern can't be empty.
-		if name == "" || patt == "" {
-			return nil, fmt.Errorf("mux: missing name or pattern in %q",
-				tpl[idxs[i]:end])
-		}
-		// Build the regexp pattern.
-		fmt.Fprintf(pattern, "%s(?P<%s>%s)", regexp.QuoteMeta(raw), varGroupName(i/2), patt)
-
-		// Build the reverse template.
-		fmt.Fprintf(reverse, "%s%%s", raw)
-
-		// Append variable name and compiled pattern.
-		varsN[i/2] = name
-		varsR[i/2], err = regexp.Compile(fmt.Sprintf("^%s$", patt))
-		if err != nil {
-			return nil, err
-		}
-	}
-	// Add the remaining.
-	raw := tpl[end:]
-	pattern.WriteString(regexp.QuoteMeta(raw))
-	if strictSlash {
-		pattern.WriteString("[/]?")
-	}
-	if matchQuery {
-		// Add the default pattern if the query value is empty
-		if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" {
-			pattern.WriteString(defaultPattern)
-		}
-	}
-	if !matchPrefix {
-		pattern.WriteByte('$')
-	}
-	reverse.WriteString(raw)
-	if endSlash {
-		reverse.WriteByte('/')
-	}
-	// Compile full regexp.
-	reg, errCompile := regexp.Compile(pattern.String())
-	if errCompile != nil {
-		return nil, errCompile
-	}
-	// Done!
-	return &routeRegexp{
-		template:    template,
-		matchHost:   matchHost,
-		matchQuery:  matchQuery,
-		strictSlash: strictSlash,
-		regexp:      reg,
-		reverse:     reverse.String(),
-		varsN:       varsN,
-		varsR:       varsR,
-	}, nil
-}
-
-// routeRegexp stores a regexp to match a host or path and information to
-// collect and validate route variables.
-type routeRegexp struct {
-	// The unmodified template.
-	template string
-	// True for host match, false for path or query string match.
-	matchHost bool
-	// True for query string match, false for path and host match.
-	matchQuery bool
-	// The strictSlash value defined on the route, but disabled if PathPrefix was used.
-	strictSlash bool
-	// Expanded regexp.
-	regexp *regexp.Regexp
-	// Reverse template.
-	reverse string
-	// Variable names.
-	varsN []string
-	// Variable regexps (validators).
-	varsR []*regexp.Regexp
-}
-
-// Match matches the regexp against the URL host or path.
-func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
-	if !r.matchHost {
-		if r.matchQuery {
-			return r.matchQueryString(req)
-		}
-
-		return r.regexp.MatchString(req.URL.Path)
-	}
-
-	return r.regexp.MatchString(getHost(req))
-}
-
-// url builds a URL part using the given values.
-func (r *routeRegexp) url(values map[string]string) (string, error) {
-	urlValues := make([]interface{}, len(r.varsN))
-	for k, v := range r.varsN {
-		value, ok := values[v]
-		if !ok {
-			return "", fmt.Errorf("mux: missing route variable %q", v)
-		}
-		urlValues[k] = value
-	}
-	rv := fmt.Sprintf(r.reverse, urlValues...)
-	if !r.regexp.MatchString(rv) {
-		// The URL is checked against the full regexp, instead of checking
-		// individual variables. This is faster but to provide a good error
-		// message, we check individual regexps if the URL doesn't match.
-		for k, v := range r.varsN {
-			if !r.varsR[k].MatchString(values[v]) {
-				return "", fmt.Errorf(
-					"mux: variable %q doesn't match, expected %q", values[v],
-					r.varsR[k].String())
-			}
-		}
-	}
-	return rv, nil
-}
-
-// getURLQuery returns a single query parameter from a request URL.
-// For a URL with foo=bar&baz=ding, we return only the relevant key
-// value pair for the routeRegexp.
-func (r *routeRegexp) getURLQuery(req *http.Request) string {
-	if !r.matchQuery {
-		return ""
-	}
-	templateKey := strings.SplitN(r.template, "=", 2)[0]
-	for key, vals := range req.URL.Query() {
-		if key == templateKey && len(vals) > 0 {
-			return key + "=" + vals[0]
-		}
-	}
-	return ""
-}
-
-func (r *routeRegexp) matchQueryString(req *http.Request) bool {
-	return r.regexp.MatchString(r.getURLQuery(req))
-}
-
-// braceIndices returns the first level curly brace indices from a string.
-// It returns an error in case of unbalanced braces.
-func braceIndices(s string) ([]int, error) {
-	var level, idx int
-	var idxs []int
-	for i := 0; i < len(s); i++ {
-		switch s[i] {
-		case '{':
-			if level++; level == 1 {
-				idx = i
-			}
-		case '}':
-			if level--; level == 0 {
-				idxs = append(idxs, idx, i+1)
-			} else if level < 0 {
-				return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
-			}
-		}
-	}
-	if level != 0 {
-		return nil, fmt.Errorf("mux: unbalanced braces in %q", s)
-	}
-	return idxs, nil
-}
-
-// varGroupName builds a capturing group name for the indexed variable.
-func varGroupName(idx int) string {
-	return "v" + strconv.Itoa(idx)
-}
-
-// ----------------------------------------------------------------------------
-// routeRegexpGroup
-// ----------------------------------------------------------------------------
-
-// routeRegexpGroup groups the route matchers that carry variables.
-type routeRegexpGroup struct {
-	host    *routeRegexp
-	path    *routeRegexp
-	queries []*routeRegexp
-}
-
-// setMatch extracts the variables from the URL once a route matches.
-func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) {
-	// Store host variables.
-	if v.host != nil {
-		host := getHost(req)
-		matches := v.host.regexp.FindStringSubmatchIndex(host)
-		if len(matches) > 0 {
-			extractVars(host, matches, v.host.varsN, m.Vars)
-		}
-	}
-	// Store path variables.
-	if v.path != nil {
-		matches := v.path.regexp.FindStringSubmatchIndex(req.URL.Path)
-		if len(matches) > 0 {
-			extractVars(req.URL.Path, matches, v.path.varsN, m.Vars)
-			// Check if we should redirect.
-			if v.path.strictSlash {
-				p1 := strings.HasSuffix(req.URL.Path, "/")
-				p2 := strings.HasSuffix(v.path.template, "/")
-				if p1 != p2 {
-					u, _ := url.Parse(req.URL.String())
-					if p1 {
-						u.Path = u.Path[:len(u.Path)-1]
-					} else {
-						u.Path += "/"
-					}
-					m.Handler = http.RedirectHandler(u.String(), 301)
-				}
-			}
-		}
-	}
-	// Store query string variables.
-	for _, q := range v.queries {
-		queryURL := q.getURLQuery(req)
-		matches := q.regexp.FindStringSubmatchIndex(queryURL)
-		if len(matches) > 0 {
-			extractVars(queryURL, matches, q.varsN, m.Vars)
-		}
-	}
-}
-
-// getHost tries its best to return the request host.
-func getHost(r *http.Request) string {
-	if r.URL.IsAbs() {
-		return r.URL.Host
-	}
-	host := r.Host
-	// Slice off any port information.
-	if i := strings.Index(host, ":"); i != -1 {
-		host = host[:i]
-	}
-	return host
-
-}
-
-func extractVars(input string, matches []int, names []string, output map[string]string) {
-	matchesCount := 0
-	prevEnd := -1
-	for i := 2; i < len(matches) && matchesCount < len(names); i += 2 {
-		if prevEnd < matches[i+1] {
-			value := input[matches[i]:matches[i+1]]
-			output[names[matchesCount]] = value
-			prevEnd = matches[i+1]
-			matchesCount++
-		}
-	}
-}

+ 0 - 634
src/github.com/gorilla/mux/route.go

@@ -1,634 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package mux
-
-import (
-	"errors"
-	"fmt"
-	"net/http"
-	"net/url"
-	"regexp"
-	"strings"
-)
-
-// Route stores information to match a request and build URLs.
-type Route struct {
-	// Parent where the route was registered (a Router).
-	parent parentRoute
-	// Request handler for the route.
-	handler http.Handler
-	// List of matchers.
-	matchers []matcher
-	// Manager for the variables from host and path.
-	regexp *routeRegexpGroup
-	// If true, when the path pattern is "/path/", accessing "/path" will
-	// redirect to the former and vice versa.
-	strictSlash bool
-	// If true, when the path pattern is "/path//to", accessing "/path//to"
-	// will not redirect
-	skipClean bool
-	// If true, this route never matches: it is only used to build URLs.
-	buildOnly bool
-	// The name used to build URLs.
-	name string
-	// Error resulted from building a route.
-	err error
-
-	buildVarsFunc BuildVarsFunc
-}
-
-func (r *Route) SkipClean() bool {
-	return r.skipClean
-}
-
-// Match matches the route against the request.
-func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
-	if r.buildOnly || r.err != nil {
-		return false
-	}
-	// Match everything.
-	for _, m := range r.matchers {
-		if matched := m.Match(req, match); !matched {
-			return false
-		}
-	}
-	// Yay, we have a match. Let's collect some info about it.
-	if match.Route == nil {
-		match.Route = r
-	}
-	if match.Handler == nil {
-		match.Handler = r.handler
-	}
-	if match.Vars == nil {
-		match.Vars = make(map[string]string)
-	}
-	// Set variables.
-	if r.regexp != nil {
-		r.regexp.setMatch(req, match, r)
-	}
-	return true
-}
-
-// ----------------------------------------------------------------------------
-// Route attributes
-// ----------------------------------------------------------------------------
-
-// GetError returns an error resulted from building the route, if any.
-func (r *Route) GetError() error {
-	return r.err
-}
-
-// BuildOnly sets the route to never match: it is only used to build URLs.
-func (r *Route) BuildOnly() *Route {
-	r.buildOnly = true
-	return r
-}
-
-// Handler --------------------------------------------------------------------
-
-// Handler sets a handler for the route.
-func (r *Route) Handler(handler http.Handler) *Route {
-	if r.err == nil {
-		r.handler = handler
-	}
-	return r
-}
-
-// HandlerFunc sets a handler function for the route.
-func (r *Route) HandlerFunc(f func(http.ResponseWriter, *http.Request)) *Route {
-	return r.Handler(http.HandlerFunc(f))
-}
-
-// GetHandler returns the handler for the route, if any.
-func (r *Route) GetHandler() http.Handler {
-	return r.handler
-}
-
-// Name -----------------------------------------------------------------------
-
-// Name sets the name for the route, used to build URLs.
-// If the name was registered already it will be overwritten.
-func (r *Route) Name(name string) *Route {
-	if r.name != "" {
-		r.err = fmt.Errorf("mux: route already has name %q, can't set %q",
-			r.name, name)
-	}
-	if r.err == nil {
-		r.name = name
-		r.getNamedRoutes()[name] = r
-	}
-	return r
-}
-
-// GetName returns the name for the route, if any.
-func (r *Route) GetName() string {
-	return r.name
-}
-
-// ----------------------------------------------------------------------------
-// Matchers
-// ----------------------------------------------------------------------------
-
-// matcher types try to match a request.
-type matcher interface {
-	Match(*http.Request, *RouteMatch) bool
-}
-
-// addMatcher adds a matcher to the route.
-func (r *Route) addMatcher(m matcher) *Route {
-	if r.err == nil {
-		r.matchers = append(r.matchers, m)
-	}
-	return r
-}
-
-// addRegexpMatcher adds a host or path matcher and builder to a route.
-func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error {
-	if r.err != nil {
-		return r.err
-	}
-	r.regexp = r.getRegexpGroup()
-	if !matchHost && !matchQuery {
-		if len(tpl) == 0 || tpl[0] != '/' {
-			return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
-		}
-		if r.regexp.path != nil {
-			tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl
-		}
-	}
-	rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash)
-	if err != nil {
-		return err
-	}
-	for _, q := range r.regexp.queries {
-		if err = uniqueVars(rr.varsN, q.varsN); err != nil {
-			return err
-		}
-	}
-	if matchHost {
-		if r.regexp.path != nil {
-			if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil {
-				return err
-			}
-		}
-		r.regexp.host = rr
-	} else {
-		if r.regexp.host != nil {
-			if err = uniqueVars(rr.varsN, r.regexp.host.varsN); err != nil {
-				return err
-			}
-		}
-		if matchQuery {
-			r.regexp.queries = append(r.regexp.queries, rr)
-		} else {
-			r.regexp.path = rr
-		}
-	}
-	r.addMatcher(rr)
-	return nil
-}
-
-// Headers --------------------------------------------------------------------
-
-// headerMatcher matches the request against header values.
-type headerMatcher map[string]string
-
-func (m headerMatcher) Match(r *http.Request, match *RouteMatch) bool {
-	return matchMapWithString(m, r.Header, true)
-}
-
-// Headers adds a matcher for request header values.
-// It accepts a sequence of key/value pairs to be matched. For example:
-//
-//     r := mux.NewRouter()
-//     r.Headers("Content-Type", "application/json",
-//               "X-Requested-With", "XMLHttpRequest")
-//
-// The above route will only match if both request header values match.
-// If the value is an empty string, it will match any value if the key is set.
-func (r *Route) Headers(pairs ...string) *Route {
-	if r.err == nil {
-		var headers map[string]string
-		headers, r.err = mapFromPairsToString(pairs...)
-		return r.addMatcher(headerMatcher(headers))
-	}
-	return r
-}
-
-// headerRegexMatcher matches the request against the route given a regex for the header
-type headerRegexMatcher map[string]*regexp.Regexp
-
-func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool {
-	return matchMapWithRegex(m, r.Header, true)
-}
-
-// HeadersRegexp accepts a sequence of key/value pairs, where the value has regex
-// support. For example:
-//
-//     r := mux.NewRouter()
-//     r.HeadersRegexp("Content-Type", "application/(text|json)",
-//               "X-Requested-With", "XMLHttpRequest")
-//
-// The above route will only match if both the request header matches both regular expressions.
-// It the value is an empty string, it will match any value if the key is set.
-func (r *Route) HeadersRegexp(pairs ...string) *Route {
-	if r.err == nil {
-		var headers map[string]*regexp.Regexp
-		headers, r.err = mapFromPairsToRegex(pairs...)
-		return r.addMatcher(headerRegexMatcher(headers))
-	}
-	return r
-}
-
-// Host -----------------------------------------------------------------------
-
-// Host adds a matcher for the URL host.
-// It accepts a template with zero or more URL variables enclosed by {}.
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next dot.
-//
-// - {name:pattern} matches the given regexp pattern.
-//
-// For example:
-//
-//     r := mux.NewRouter()
-//     r.Host("www.example.com")
-//     r.Host("{subdomain}.domain.com")
-//     r.Host("{subdomain:[a-z]+}.domain.com")
-//
-// Variable names must be unique in a given route. They can be retrieved
-// calling mux.Vars(request).
-func (r *Route) Host(tpl string) *Route {
-	r.err = r.addRegexpMatcher(tpl, true, false, false)
-	return r
-}
-
-// MatcherFunc ----------------------------------------------------------------
-
-// MatcherFunc is the function signature used by custom matchers.
-type MatcherFunc func(*http.Request, *RouteMatch) bool
-
-// Match returns the match for a given request.
-func (m MatcherFunc) Match(r *http.Request, match *RouteMatch) bool {
-	return m(r, match)
-}
-
-// MatcherFunc adds a custom function to be used as request matcher.
-func (r *Route) MatcherFunc(f MatcherFunc) *Route {
-	return r.addMatcher(f)
-}
-
-// Methods --------------------------------------------------------------------
-
-// methodMatcher matches the request against HTTP methods.
-type methodMatcher []string
-
-func (m methodMatcher) Match(r *http.Request, match *RouteMatch) bool {
-	return matchInArray(m, r.Method)
-}
-
-// Methods adds a matcher for HTTP methods.
-// It accepts a sequence of one or more methods to be matched, e.g.:
-// "GET", "POST", "PUT".
-func (r *Route) Methods(methods ...string) *Route {
-	for k, v := range methods {
-		methods[k] = strings.ToUpper(v)
-	}
-	return r.addMatcher(methodMatcher(methods))
-}
-
-// Path -----------------------------------------------------------------------
-
-// Path adds a matcher for the URL path.
-// It accepts a template with zero or more URL variables enclosed by {}. The
-// template must start with a "/".
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next slash.
-//
-// - {name:pattern} matches the given regexp pattern.
-//
-// For example:
-//
-//     r := mux.NewRouter()
-//     r.Path("/products/").Handler(ProductsHandler)
-//     r.Path("/products/{key}").Handler(ProductsHandler)
-//     r.Path("/articles/{category}/{id:[0-9]+}").
-//       Handler(ArticleHandler)
-//
-// Variable names must be unique in a given route. They can be retrieved
-// calling mux.Vars(request).
-func (r *Route) Path(tpl string) *Route {
-	r.err = r.addRegexpMatcher(tpl, false, false, false)
-	return r
-}
-
-// PathPrefix -----------------------------------------------------------------
-
-// PathPrefix adds a matcher for the URL path prefix. This matches if the given
-// template is a prefix of the full URL path. See Route.Path() for details on
-// the tpl argument.
-//
-// Note that it does not treat slashes specially ("/foobar/" will be matched by
-// the prefix "/foo") so you may want to use a trailing slash here.
-//
-// Also note that the setting of Router.StrictSlash() has no effect on routes
-// with a PathPrefix matcher.
-func (r *Route) PathPrefix(tpl string) *Route {
-	r.err = r.addRegexpMatcher(tpl, false, true, false)
-	return r
-}
-
-// Query ----------------------------------------------------------------------
-
-// Queries adds a matcher for URL query values.
-// It accepts a sequence of key/value pairs. Values may define variables.
-// For example:
-//
-//     r := mux.NewRouter()
-//     r.Queries("foo", "bar", "id", "{id:[0-9]+}")
-//
-// The above route will only match if the URL contains the defined queries
-// values, e.g.: ?foo=bar&id=42.
-//
-// It the value is an empty string, it will match any value if the key is set.
-//
-// Variables can define an optional regexp pattern to be matched:
-//
-// - {name} matches anything until the next slash.
-//
-// - {name:pattern} matches the given regexp pattern.
-func (r *Route) Queries(pairs ...string) *Route {
-	length := len(pairs)
-	if length%2 != 0 {
-		r.err = fmt.Errorf(
-			"mux: number of parameters must be multiple of 2, got %v", pairs)
-		return nil
-	}
-	for i := 0; i < length; i += 2 {
-		if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil {
-			return r
-		}
-	}
-
-	return r
-}
-
-// Schemes --------------------------------------------------------------------
-
-// schemeMatcher matches the request against URL schemes.
-type schemeMatcher []string
-
-func (m schemeMatcher) Match(r *http.Request, match *RouteMatch) bool {
-	return matchInArray(m, r.URL.Scheme)
-}
-
-// Schemes adds a matcher for URL schemes.
-// It accepts a sequence of schemes to be matched, e.g.: "http", "https".
-func (r *Route) Schemes(schemes ...string) *Route {
-	for k, v := range schemes {
-		schemes[k] = strings.ToLower(v)
-	}
-	return r.addMatcher(schemeMatcher(schemes))
-}
-
-// BuildVarsFunc --------------------------------------------------------------
-
-// BuildVarsFunc is the function signature used by custom build variable
-// functions (which can modify route variables before a route's URL is built).
-type BuildVarsFunc func(map[string]string) map[string]string
-
-// BuildVarsFunc adds a custom function to be used to modify build variables
-// before a route's URL is built.
-func (r *Route) BuildVarsFunc(f BuildVarsFunc) *Route {
-	r.buildVarsFunc = f
-	return r
-}
-
-// Subrouter ------------------------------------------------------------------
-
-// Subrouter creates a subrouter for the route.
-//
-// It will test the inner routes only if the parent route matched. For example:
-//
-//     r := mux.NewRouter()
-//     s := r.Host("www.example.com").Subrouter()
-//     s.HandleFunc("/products/", ProductsHandler)
-//     s.HandleFunc("/products/{key}", ProductHandler)
-//     s.HandleFunc("/articles/{category}/{id:[0-9]+}"), ArticleHandler)
-//
-// Here, the routes registered in the subrouter won't be tested if the host
-// doesn't match.
-func (r *Route) Subrouter() *Router {
-	router := &Router{parent: r, strictSlash: r.strictSlash}
-	r.addMatcher(router)
-	return router
-}
-
-// ----------------------------------------------------------------------------
-// URL building
-// ----------------------------------------------------------------------------
-
-// URL builds a URL for the route.
-//
-// It accepts a sequence of key/value pairs for the route variables. For
-// example, given this route:
-//
-//     r := mux.NewRouter()
-//     r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-//       Name("article")
-//
-// ...a URL for it can be built using:
-//
-//     url, err := r.Get("article").URL("category", "technology", "id", "42")
-//
-// ...which will return an url.URL with the following path:
-//
-//     "/articles/technology/42"
-//
-// This also works for host variables:
-//
-//     r := mux.NewRouter()
-//     r.Host("{subdomain}.domain.com").
-//       HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler).
-//       Name("article")
-//
-//     // url.String() will be "http://news.domain.com/articles/technology/42"
-//     url, err := r.Get("article").URL("subdomain", "news",
-//                                      "category", "technology",
-//                                      "id", "42")
-//
-// All variables defined in the route are required, and their values must
-// conform to the corresponding patterns.
-func (r *Route) URL(pairs ...string) (*url.URL, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	if r.regexp == nil {
-		return nil, errors.New("mux: route doesn't have a host or path")
-	}
-	values, err := r.prepareVars(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	var scheme, host, path string
-	if r.regexp.host != nil {
-		// Set a default scheme.
-		scheme = "http"
-		if host, err = r.regexp.host.url(values); err != nil {
-			return nil, err
-		}
-	}
-	if r.regexp.path != nil {
-		if path, err = r.regexp.path.url(values); err != nil {
-			return nil, err
-		}
-	}
-	return &url.URL{
-		Scheme: scheme,
-		Host:   host,
-		Path:   path,
-	}, nil
-}
-
-// URLHost builds the host part of the URL for a route. See Route.URL().
-//
-// The route must have a host defined.
-func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	if r.regexp == nil || r.regexp.host == nil {
-		return nil, errors.New("mux: route doesn't have a host")
-	}
-	values, err := r.prepareVars(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	host, err := r.regexp.host.url(values)
-	if err != nil {
-		return nil, err
-	}
-	return &url.URL{
-		Scheme: "http",
-		Host:   host,
-	}, nil
-}
-
-// URLPath builds the path part of the URL for a route. See Route.URL().
-//
-// The route must have a path defined.
-func (r *Route) URLPath(pairs ...string) (*url.URL, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	if r.regexp == nil || r.regexp.path == nil {
-		return nil, errors.New("mux: route doesn't have a path")
-	}
-	values, err := r.prepareVars(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	path, err := r.regexp.path.url(values)
-	if err != nil {
-		return nil, err
-	}
-	return &url.URL{
-		Path: path,
-	}, nil
-}
-
-// GetPathTemplate returns the template used to build the
-// route match.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a path.
-func (r *Route) GetPathTemplate() (string, error) {
-	if r.err != nil {
-		return "", r.err
-	}
-	if r.regexp == nil || r.regexp.path == nil {
-		return "", errors.New("mux: route doesn't have a path")
-	}
-	return r.regexp.path.template, nil
-}
-
-// GetHostTemplate returns the template used to build the
-// route match.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a host.
-func (r *Route) GetHostTemplate() (string, error) {
-	if r.err != nil {
-		return "", r.err
-	}
-	if r.regexp == nil || r.regexp.host == nil {
-		return "", errors.New("mux: route doesn't have a host")
-	}
-	return r.regexp.host.template, nil
-}
-
-// prepareVars converts the route variable pairs into a map. If the route has a
-// BuildVarsFunc, it is invoked.
-func (r *Route) prepareVars(pairs ...string) (map[string]string, error) {
-	m, err := mapFromPairsToString(pairs...)
-	if err != nil {
-		return nil, err
-	}
-	return r.buildVars(m), nil
-}
-
-func (r *Route) buildVars(m map[string]string) map[string]string {
-	if r.parent != nil {
-		m = r.parent.buildVars(m)
-	}
-	if r.buildVarsFunc != nil {
-		m = r.buildVarsFunc(m)
-	}
-	return m
-}
-
-// ----------------------------------------------------------------------------
-// parentRoute
-// ----------------------------------------------------------------------------
-
-// parentRoute allows routes to know about parent host and path definitions.
-type parentRoute interface {
-	getNamedRoutes() map[string]*Route
-	getRegexpGroup() *routeRegexpGroup
-	buildVars(map[string]string) map[string]string
-}
-
-// getNamedRoutes returns the map where named routes are registered.
-func (r *Route) getNamedRoutes() map[string]*Route {
-	if r.parent == nil {
-		// During tests router is not always set.
-		r.parent = NewRouter()
-	}
-	return r.parent.getNamedRoutes()
-}
-
-// getRegexpGroup returns regexp definitions from this route.
-func (r *Route) getRegexpGroup() *routeRegexpGroup {
-	if r.regexp == nil {
-		if r.parent == nil {
-			// During tests router is not always set.
-			r.parent = NewRouter()
-		}
-		regexp := r.parent.getRegexpGroup()
-		if regexp == nil {
-			r.regexp = new(routeRegexpGroup)
-		} else {
-			// Copy.
-			r.regexp = &routeRegexpGroup{
-				host:    regexp.host,
-				path:    regexp.path,
-				queries: regexp.queries,
-			}
-		}
-	}
-	return r.regexp
-}

+ 0 - 18
src/github.com/gorilla/securecookie/.travis.yml

@@ -1,18 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-  allow_failures:
-    - go: tip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go vet $(go list ./... | grep -v /vendor/)
-  - go test -v -race ./...

+ 0 - 27
src/github.com/gorilla/securecookie/LICENSE

@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-	 * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-	 * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-	 * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 78
src/github.com/gorilla/securecookie/README.md

@@ -1,78 +0,0 @@
-securecookie
-============
-[![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie)
-
-securecookie encodes and decodes authenticated and optionally encrypted 
-cookie values.
-
-Secure cookies can't be forged, because their values are validated using HMAC.
-When encrypted, the content is also inaccessible to malicious eyes. It is still
-recommended that sensitive data not be stored in cookies, and that HTTPS be used
-to prevent cookie [replay attacks](https://en.wikipedia.org/wiki/Replay_attack).
-
-## Examples
-
-To use it, first create a new SecureCookie instance:
-
-```go
-// Hash keys should be at least 32 bytes long
-var hashKey = []byte("very-secret")
-// Block keys should be 16 bytes (AES-128) or 32 bytes (AES-256) long.
-// Shorter keys may weaken the encryption used.
-var blockKey = []byte("a-lot-secret")
-var s = securecookie.New(hashKey, blockKey)
-```
-
-The hashKey is required, used to authenticate the cookie value using HMAC.
-It is recommended to use a key with 32 or 64 bytes.
-
-The blockKey is optional, used to encrypt the cookie value -- set it to nil
-to not use encryption. If set, the length must correspond to the block size
-of the encryption algorithm. For AES, used by default, valid lengths are
-16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
-
-Strong keys can be created using the convenience function GenerateRandomKey().
-
-Once a SecureCookie instance is set, use it to encode a cookie value:
-
-```go
-func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
-	value := map[string]string{
-		"foo": "bar",
-	}
-	if encoded, err := s.Encode("cookie-name", value); err == nil {
-		cookie := &http.Cookie{
-			Name:  "cookie-name",
-			Value: encoded,
-			Path:  "/",
-			Secure: true,
-			HttpOnly: true,
-		}
-		http.SetCookie(w, cookie)
-	}
-}
-```
-
-Later, use the same SecureCookie instance to decode and validate a cookie
-value:
-
-```go
-func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
-	if cookie, err := r.Cookie("cookie-name"); err == nil {
-		value := make(map[string]string)
-		if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
-			fmt.Fprintf(w, "The value of foo is %q", value["foo"])
-		}
-	}
-}
-```
-
-We stored a map[string]string, but secure cookies can hold any value that
-can be encoded using `encoding/gob`. To store custom types, they must be
-registered first using gob.Register(). For basic types this is not needed;
-it works out of the box. An optional JSON encoder that uses `encoding/json` is
-available for types compatible with JSON.
-
-## License
-
-BSD licensed. See the LICENSE file for details.

+ 0 - 61
src/github.com/gorilla/securecookie/doc.go

@@ -1,61 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package securecookie encodes and decodes authenticated and optionally
-encrypted cookie values.
-
-Secure cookies can't be forged, because their values are validated using HMAC.
-When encrypted, the content is also inaccessible to malicious eyes.
-
-To use it, first create a new SecureCookie instance:
-
-	var hashKey = []byte("very-secret")
-	var blockKey = []byte("a-lot-secret")
-	var s = securecookie.New(hashKey, blockKey)
-
-The hashKey is required, used to authenticate the cookie value using HMAC.
-It is recommended to use a key with 32 or 64 bytes.
-
-The blockKey is optional, used to encrypt the cookie value -- set it to nil
-to not use encryption. If set, the length must correspond to the block size
-of the encryption algorithm. For AES, used by default, valid lengths are
-16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
-
-Strong keys can be created using the convenience function GenerateRandomKey().
-
-Once a SecureCookie instance is set, use it to encode a cookie value:
-
-	func SetCookieHandler(w http.ResponseWriter, r *http.Request) {
-		value := map[string]string{
-			"foo": "bar",
-		}
-		if encoded, err := s.Encode("cookie-name", value); err == nil {
-			cookie := &http.Cookie{
-				Name:  "cookie-name",
-				Value: encoded,
-				Path:  "/",
-			}
-			http.SetCookie(w, cookie)
-		}
-	}
-
-Later, use the same SecureCookie instance to decode and validate a cookie
-value:
-
-	func ReadCookieHandler(w http.ResponseWriter, r *http.Request) {
-		if cookie, err := r.Cookie("cookie-name"); err == nil {
-			value := make(map[string]string)
-			if err = s2.Decode("cookie-name", cookie.Value, &value); err == nil {
-				fmt.Fprintf(w, "The value of foo is %q", value["foo"])
-			}
-		}
-	}
-
-We stored a map[string]string, but secure cookies can hold any value that
-can be encoded using encoding/gob. To store custom types, they must be
-registered first using gob.Register(). For basic types this is not needed;
-it works out of the box.
-*/
-package securecookie

+ 0 - 25
src/github.com/gorilla/securecookie/fuzz.go

@@ -1,25 +0,0 @@
-// +build gofuzz
-
-package securecookie
-
-var hashKey = []byte("very-secret12345")
-var blockKey = []byte("a-lot-secret1234")
-var s = New(hashKey, blockKey)
-
-type Cookie struct {
-	B bool
-	I int
-	S string
-}
-
-func Fuzz(data []byte) int {
-	datas := string(data)
-	var c Cookie
-	if err := s.Decode("fuzz", datas, &c); err != nil {
-		return 0
-	}
-	if _, err := s.Encode("fuzz", c); err != nil {
-		panic(err)
-	}
-	return 1
-}

+ 0 - 47
src/github.com/gorilla/securecookie/fuzz/gencorpus.go

@@ -1,47 +0,0 @@
-package main
-
-import (
-	"fmt"
-	"io"
-	"math/rand"
-	"os"
-	"reflect"
-	"testing/quick"
-
-	"github.com/gorilla/securecookie"
-)
-
-var hashKey = []byte("very-secret12345")
-var blockKey = []byte("a-lot-secret1234")
-var s = securecookie.New(hashKey, blockKey)
-
-type Cookie struct {
-	B bool
-	I int
-	S string
-}
-
-func main() {
-	var c Cookie
-	t := reflect.TypeOf(c)
-	rnd := rand.New(rand.NewSource(0))
-	for i := 0; i < 100; i++ {
-		v, ok := quick.Value(t, rnd)
-		if !ok {
-			panic("couldn't generate value")
-		}
-		encoded, err := s.Encode("fuzz", v.Interface())
-		if err != nil {
-			panic(err)
-		}
-		f, err := os.Create(fmt.Sprintf("corpus/%d.sc", i))
-		if err != nil {
-			panic(err)
-		}
-		_, err = io.WriteString(f, encoded)
-		if err != nil {
-			panic(err)
-		}
-		f.Close()
-	}
-}

+ 0 - 646
src/github.com/gorilla/securecookie/securecookie.go

@@ -1,646 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package securecookie
-
-import (
-	"bytes"
-	"crypto/aes"
-	"crypto/cipher"
-	"crypto/hmac"
-	"crypto/rand"
-	"crypto/sha256"
-	"crypto/subtle"
-	"encoding/base64"
-	"encoding/gob"
-	"encoding/json"
-	"fmt"
-	"hash"
-	"io"
-	"strconv"
-	"strings"
-	"time"
-)
-
-// Error is the interface of all errors returned by functions in this library.
-type Error interface {
-	error
-
-	// IsUsage returns true for errors indicating the client code probably
-	// uses this library incorrectly.  For example, the client may have
-	// failed to provide a valid hash key, or may have failed to configure
-	// the Serializer adequately for encoding value.
-	IsUsage() bool
-
-	// IsDecode returns true for errors indicating that a cookie could not
-	// be decoded and validated.  Since cookies are usually untrusted
-	// user-provided input, errors of this type should be expected.
-	// Usually, the proper action is simply to reject the request.
-	IsDecode() bool
-
-	// IsInternal returns true for unexpected errors occurring in the
-	// securecookie implementation.
-	IsInternal() bool
-
-	// Cause, if it returns a non-nil value, indicates that this error was
-	// propagated from some underlying library.  If this method returns nil,
-	// this error was raised directly by this library.
-	//
-	// Cause is provided principally for debugging/logging purposes; it is
-	// rare that application logic should perform meaningfully different
-	// logic based on Cause.  See, for example, the caveats described on
-	// (MultiError).Cause().
-	Cause() error
-}
-
-// errorType is a bitmask giving the error type(s) of an cookieError value.
-type errorType int
-
-const (
-	usageError = errorType(1 << iota)
-	decodeError
-	internalError
-)
-
-type cookieError struct {
-	typ   errorType
-	msg   string
-	cause error
-}
-
-func (e cookieError) IsUsage() bool    { return (e.typ & usageError) != 0 }
-func (e cookieError) IsDecode() bool   { return (e.typ & decodeError) != 0 }
-func (e cookieError) IsInternal() bool { return (e.typ & internalError) != 0 }
-
-func (e cookieError) Cause() error { return e.cause }
-
-func (e cookieError) Error() string {
-	parts := []string{"securecookie: "}
-	if e.msg == "" {
-		parts = append(parts, "error")
-	} else {
-		parts = append(parts, e.msg)
-	}
-	if c := e.Cause(); c != nil {
-		parts = append(parts, " - caused by: ", c.Error())
-	}
-	return strings.Join(parts, "")
-}
-
-var (
-	errGeneratingIV = cookieError{typ: internalError, msg: "failed to generate random iv"}
-
-	errNoCodecs            = cookieError{typ: usageError, msg: "no codecs provided"}
-	errHashKeyNotSet       = cookieError{typ: usageError, msg: "hash key is not set"}
-	errBlockKeyNotSet      = cookieError{typ: usageError, msg: "block key is not set"}
-	errEncodedValueTooLong = cookieError{typ: usageError, msg: "the value is too long"}
-
-	errValueToDecodeTooLong = cookieError{typ: decodeError, msg: "the value is too long"}
-	errTimestampInvalid     = cookieError{typ: decodeError, msg: "invalid timestamp"}
-	errTimestampTooNew      = cookieError{typ: decodeError, msg: "timestamp is too new"}
-	errTimestampExpired     = cookieError{typ: decodeError, msg: "expired timestamp"}
-	errDecryptionFailed     = cookieError{typ: decodeError, msg: "the value could not be decrypted"}
-	errValueNotByte         = cookieError{typ: decodeError, msg: "value not a []byte."}
-
-	// ErrMacInvalid indicates that cookie decoding failed because the HMAC
-	// could not be extracted and verified.  Direct use of this error
-	// variable is deprecated; it is public only for legacy compatibility,
-	// and may be privatized in the future, as it is rarely useful to
-	// distinguish between this error and other Error implementations.
-	ErrMacInvalid = cookieError{typ: decodeError, msg: "the value is not valid"}
-)
-
-// Codec defines an interface to encode and decode cookie values.
-type Codec interface {
-	Encode(name string, value interface{}) (string, error)
-	Decode(name, value string, dst interface{}) error
-}
-
-// New returns a new SecureCookie.
-//
-// hashKey is required, used to authenticate values using HMAC. Create it using
-// GenerateRandomKey(). It is recommended to use a key with 32 or 64 bytes.
-//
-// blockKey is optional, used to encrypt values. Create it using
-// GenerateRandomKey(). The key length must correspond to the block size
-// of the encryption algorithm. For AES, used by default, valid lengths are
-// 16, 24, or 32 bytes to select AES-128, AES-192, or AES-256.
-// The default encoder used for cookie serialization is encoding/gob.
-//
-// Note that keys created using GenerateRandomKey() are not automatically
-// persisted. New keys will be created when the application is restarted, and
-// previously issued cookies will not be able to be decoded.
-func New(hashKey, blockKey []byte) *SecureCookie {
-	s := &SecureCookie{
-		hashKey:   hashKey,
-		blockKey:  blockKey,
-		hashFunc:  sha256.New,
-		maxAge:    86400 * 30,
-		maxLength: 4096,
-		sz:        GobEncoder{},
-	}
-	if hashKey == nil {
-		s.err = errHashKeyNotSet
-	}
-	if blockKey != nil {
-		s.BlockFunc(aes.NewCipher)
-	}
-	return s
-}
-
-// SecureCookie encodes and decodes authenticated and optionally encrypted
-// cookie values.
-type SecureCookie struct {
-	hashKey   []byte
-	hashFunc  func() hash.Hash
-	blockKey  []byte
-	block     cipher.Block
-	maxLength int
-	maxAge    int64
-	minAge    int64
-	err       error
-	sz        Serializer
-	// For testing purposes, the function that returns the current timestamp.
-	// If not set, it will use time.Now().UTC().Unix().
-	timeFunc func() int64
-}
-
-// Serializer provides an interface for providing custom serializers for cookie
-// values.
-type Serializer interface {
-	Serialize(src interface{}) ([]byte, error)
-	Deserialize(src []byte, dst interface{}) error
-}
-
-// GobEncoder encodes cookie values using encoding/gob. This is the simplest
-// encoder and can handle complex types via gob.Register.
-type GobEncoder struct{}
-
-// JSONEncoder encodes cookie values using encoding/json. Users who wish to
-// encode complex types need to satisfy the json.Marshaller and
-// json.Unmarshaller interfaces.
-type JSONEncoder struct{}
-
-// NopEncoder does not encode cookie values, and instead simply accepts a []byte
-// (as an interface{}) and returns a []byte. This is particularly useful when
-// you encoding an object upstream and do not wish to re-encode it.
-type NopEncoder struct{}
-
-// MaxLength restricts the maximum length, in bytes, for the cookie value.
-//
-// Default is 4096, which is the maximum value accepted by Internet Explorer.
-func (s *SecureCookie) MaxLength(value int) *SecureCookie {
-	s.maxLength = value
-	return s
-}
-
-// MaxAge restricts the maximum age, in seconds, for the cookie value.
-//
-// Default is 86400 * 30. Set it to 0 for no restriction.
-func (s *SecureCookie) MaxAge(value int) *SecureCookie {
-	s.maxAge = int64(value)
-	return s
-}
-
-// MinAge restricts the minimum age, in seconds, for the cookie value.
-//
-// Default is 0 (no restriction).
-func (s *SecureCookie) MinAge(value int) *SecureCookie {
-	s.minAge = int64(value)
-	return s
-}
-
-// HashFunc sets the hash function used to create HMAC.
-//
-// Default is crypto/sha256.New.
-func (s *SecureCookie) HashFunc(f func() hash.Hash) *SecureCookie {
-	s.hashFunc = f
-	return s
-}
-
-// BlockFunc sets the encryption function used to create a cipher.Block.
-//
-// Default is crypto/aes.New.
-func (s *SecureCookie) BlockFunc(f func([]byte) (cipher.Block, error)) *SecureCookie {
-	if s.blockKey == nil {
-		s.err = errBlockKeyNotSet
-	} else if block, err := f(s.blockKey); err == nil {
-		s.block = block
-	} else {
-		s.err = cookieError{cause: err, typ: usageError}
-	}
-	return s
-}
-
-// Encoding sets the encoding/serialization method for cookies.
-//
-// Default is encoding/gob.  To encode special structures using encoding/gob,
-// they must be registered first using gob.Register().
-func (s *SecureCookie) SetSerializer(sz Serializer) *SecureCookie {
-	s.sz = sz
-
-	return s
-}
-
-// Encode encodes a cookie value.
-//
-// It serializes, optionally encrypts, signs with a message authentication code,
-// and finally encodes the value.
-//
-// The name argument is the cookie name. It is stored with the encoded value.
-// The value argument is the value to be encoded. It can be any value that can
-// be encoded using the currently selected serializer; see SetSerializer().
-//
-// It is the client's responsibility to ensure that value, when encoded using
-// the current serialization/encryption settings on s and then base64-encoded,
-// is shorter than the maximum permissible length.
-func (s *SecureCookie) Encode(name string, value interface{}) (string, error) {
-	if s.err != nil {
-		return "", s.err
-	}
-	if s.hashKey == nil {
-		s.err = errHashKeyNotSet
-		return "", s.err
-	}
-	var err error
-	var b []byte
-	// 1. Serialize.
-	if b, err = s.sz.Serialize(value); err != nil {
-		return "", cookieError{cause: err, typ: usageError}
-	}
-	// 2. Encrypt (optional).
-	if s.block != nil {
-		if b, err = encrypt(s.block, b); err != nil {
-			return "", cookieError{cause: err, typ: usageError}
-		}
-	}
-	b = encode(b)
-	// 3. Create MAC for "name|date|value". Extra pipe to be used later.
-	b = []byte(fmt.Sprintf("%s|%d|%s|", name, s.timestamp(), b))
-	mac := createMac(hmac.New(s.hashFunc, s.hashKey), b[:len(b)-1])
-	// Append mac, remove name.
-	b = append(b, mac...)[len(name)+1:]
-	// 4. Encode to base64.
-	b = encode(b)
-	// 5. Check length.
-	if s.maxLength != 0 && len(b) > s.maxLength {
-		return "", errEncodedValueTooLong
-	}
-	// Done.
-	return string(b), nil
-}
-
-// Decode decodes a cookie value.
-//
-// It decodes, verifies a message authentication code, optionally decrypts and
-// finally deserializes the value.
-//
-// The name argument is the cookie name. It must be the same name used when
-// it was stored. The value argument is the encoded cookie value. The dst
-// argument is where the cookie will be decoded. It must be a pointer.
-func (s *SecureCookie) Decode(name, value string, dst interface{}) error {
-	if s.err != nil {
-		return s.err
-	}
-	if s.hashKey == nil {
-		s.err = errHashKeyNotSet
-		return s.err
-	}
-	// 1. Check length.
-	if s.maxLength != 0 && len(value) > s.maxLength {
-		return errValueToDecodeTooLong
-	}
-	// 2. Decode from base64.
-	b, err := decode([]byte(value))
-	if err != nil {
-		return err
-	}
-	// 3. Verify MAC. Value is "date|value|mac".
-	parts := bytes.SplitN(b, []byte("|"), 3)
-	if len(parts) != 3 {
-		return ErrMacInvalid
-	}
-	h := hmac.New(s.hashFunc, s.hashKey)
-	b = append([]byte(name+"|"), b[:len(b)-len(parts[2])-1]...)
-	if err = verifyMac(h, b, parts[2]); err != nil {
-		return err
-	}
-	// 4. Verify date ranges.
-	var t1 int64
-	if t1, err = strconv.ParseInt(string(parts[0]), 10, 64); err != nil {
-		return errTimestampInvalid
-	}
-	t2 := s.timestamp()
-	if s.minAge != 0 && t1 > t2-s.minAge {
-		return errTimestampTooNew
-	}
-	if s.maxAge != 0 && t1 < t2-s.maxAge {
-		return errTimestampExpired
-	}
-	// 5. Decrypt (optional).
-	b, err = decode(parts[1])
-	if err != nil {
-		return err
-	}
-	if s.block != nil {
-		if b, err = decrypt(s.block, b); err != nil {
-			return err
-		}
-	}
-	// 6. Deserialize.
-	if err = s.sz.Deserialize(b, dst); err != nil {
-		return cookieError{cause: err, typ: decodeError}
-	}
-	// Done.
-	return nil
-}
-
-// timestamp returns the current timestamp, in seconds.
-//
-// For testing purposes, the function that generates the timestamp can be
-// overridden. If not set, it will return time.Now().UTC().Unix().
-func (s *SecureCookie) timestamp() int64 {
-	if s.timeFunc == nil {
-		return time.Now().UTC().Unix()
-	}
-	return s.timeFunc()
-}
-
-// Authentication -------------------------------------------------------------
-
-// createMac creates a message authentication code (MAC).
-func createMac(h hash.Hash, value []byte) []byte {
-	h.Write(value)
-	return h.Sum(nil)
-}
-
-// verifyMac verifies that a message authentication code (MAC) is valid.
-func verifyMac(h hash.Hash, value []byte, mac []byte) error {
-	mac2 := createMac(h, value)
-	// Check that both MACs are of equal length, as subtle.ConstantTimeCompare
-	// does not do this prior to Go 1.4.
-	if len(mac) == len(mac2) && subtle.ConstantTimeCompare(mac, mac2) == 1 {
-		return nil
-	}
-	return ErrMacInvalid
-}
-
-// Encryption -----------------------------------------------------------------
-
-// encrypt encrypts a value using the given block in counter mode.
-//
-// A random initialization vector (http://goo.gl/zF67k) with the length of the
-// block size is prepended to the resulting ciphertext.
-func encrypt(block cipher.Block, value []byte) ([]byte, error) {
-	iv := GenerateRandomKey(block.BlockSize())
-	if iv == nil {
-		return nil, errGeneratingIV
-	}
-	// Encrypt it.
-	stream := cipher.NewCTR(block, iv)
-	stream.XORKeyStream(value, value)
-	// Return iv + ciphertext.
-	return append(iv, value...), nil
-}
-
-// decrypt decrypts a value using the given block in counter mode.
-//
-// The value to be decrypted must be prepended by a initialization vector
-// (http://goo.gl/zF67k) with the length of the block size.
-func decrypt(block cipher.Block, value []byte) ([]byte, error) {
-	size := block.BlockSize()
-	if len(value) > size {
-		// Extract iv.
-		iv := value[:size]
-		// Extract ciphertext.
-		value = value[size:]
-		// Decrypt it.
-		stream := cipher.NewCTR(block, iv)
-		stream.XORKeyStream(value, value)
-		return value, nil
-	}
-	return nil, errDecryptionFailed
-}
-
-// Serialization --------------------------------------------------------------
-
-// Serialize encodes a value using gob.
-func (e GobEncoder) Serialize(src interface{}) ([]byte, error) {
-	buf := new(bytes.Buffer)
-	enc := gob.NewEncoder(buf)
-	if err := enc.Encode(src); err != nil {
-		return nil, cookieError{cause: err, typ: usageError}
-	}
-	return buf.Bytes(), nil
-}
-
-// Deserialize decodes a value using gob.
-func (e GobEncoder) Deserialize(src []byte, dst interface{}) error {
-	dec := gob.NewDecoder(bytes.NewBuffer(src))
-	if err := dec.Decode(dst); err != nil {
-		return cookieError{cause: err, typ: decodeError}
-	}
-	return nil
-}
-
-// Serialize encodes a value using encoding/json.
-func (e JSONEncoder) Serialize(src interface{}) ([]byte, error) {
-	buf := new(bytes.Buffer)
-	enc := json.NewEncoder(buf)
-	if err := enc.Encode(src); err != nil {
-		return nil, cookieError{cause: err, typ: usageError}
-	}
-	return buf.Bytes(), nil
-}
-
-// Deserialize decodes a value using encoding/json.
-func (e JSONEncoder) Deserialize(src []byte, dst interface{}) error {
-	dec := json.NewDecoder(bytes.NewReader(src))
-	if err := dec.Decode(dst); err != nil {
-		return cookieError{cause: err, typ: decodeError}
-	}
-	return nil
-}
-
-// Serialize passes a []byte through as-is.
-func (e NopEncoder) Serialize(src interface{}) ([]byte, error) {
-	if b, ok := src.([]byte); ok {
-		return b, nil
-	}
-
-	return nil, errValueNotByte
-}
-
-// Deserialize passes a []byte through as-is.
-func (e NopEncoder) Deserialize(src []byte, dst interface{}) error {
-	if _, ok := dst.([]byte); ok {
-		dst = src
-		return nil
-	}
-
-	return errValueNotByte
-}
-
-// Encoding -------------------------------------------------------------------
-
-// encode encodes a value using base64.
-func encode(value []byte) []byte {
-	encoded := make([]byte, base64.URLEncoding.EncodedLen(len(value)))
-	base64.URLEncoding.Encode(encoded, value)
-	return encoded
-}
-
-// decode decodes a cookie using base64.
-func decode(value []byte) ([]byte, error) {
-	decoded := make([]byte, base64.URLEncoding.DecodedLen(len(value)))
-	b, err := base64.URLEncoding.Decode(decoded, value)
-	if err != nil {
-		return nil, cookieError{cause: err, typ: decodeError, msg: "base64 decode failed"}
-	}
-	return decoded[:b], nil
-}
-
-// Helpers --------------------------------------------------------------------
-
-// GenerateRandomKey creates a random key with the given length in bytes.
-// On failure, returns nil.
-//
-// Callers should explicitly check for the possibility of a nil return, treat
-// it as a failure of the system random number generator, and not continue.
-func GenerateRandomKey(length int) []byte {
-	k := make([]byte, length)
-	if _, err := io.ReadFull(rand.Reader, k); err != nil {
-		return nil
-	}
-	return k
-}
-
-// CodecsFromPairs returns a slice of SecureCookie instances.
-//
-// It is a convenience function to create a list of codecs for key rotation. Note
-// that the generated Codecs will have the default options applied: callers
-// should iterate over each Codec and type-assert the underlying *SecureCookie to
-// change these.
-//
-// Example:
-//
-//      codecs := securecookie.CodecsFromPairs(
-//           []byte("new-hash-key"),
-//           []byte("new-block-key"),
-//           []byte("old-hash-key"),
-//           []byte("old-block-key"),
-//       )
-//
-//      // Modify each instance.
-//      for _, s := range codecs {
-//             if cookie, ok := s.(*securecookie.SecureCookie); ok {
-//                 cookie.MaxAge(86400 * 7)
-//                 cookie.SetSerializer(securecookie.JSONEncoder{})
-//                 cookie.HashFunc(sha512.New512_256)
-//             }
-//         }
-//
-func CodecsFromPairs(keyPairs ...[]byte) []Codec {
-	codecs := make([]Codec, len(keyPairs)/2+len(keyPairs)%2)
-	for i := 0; i < len(keyPairs); i += 2 {
-		var blockKey []byte
-		if i+1 < len(keyPairs) {
-			blockKey = keyPairs[i+1]
-		}
-		codecs[i/2] = New(keyPairs[i], blockKey)
-	}
-	return codecs
-}
-
-// EncodeMulti encodes a cookie value using a group of codecs.
-//
-// The codecs are tried in order. Multiple codecs are accepted to allow
-// key rotation.
-//
-// On error, may return a MultiError.
-func EncodeMulti(name string, value interface{}, codecs ...Codec) (string, error) {
-	if len(codecs) == 0 {
-		return "", errNoCodecs
-	}
-
-	var errors MultiError
-	for _, codec := range codecs {
-		encoded, err := codec.Encode(name, value)
-		if err == nil {
-			return encoded, nil
-		}
-		errors = append(errors, err)
-	}
-	return "", errors
-}
-
-// DecodeMulti decodes a cookie value using a group of codecs.
-//
-// The codecs are tried in order. Multiple codecs are accepted to allow
-// key rotation.
-//
-// On error, may return a MultiError.
-func DecodeMulti(name string, value string, dst interface{}, codecs ...Codec) error {
-	if len(codecs) == 0 {
-		return errNoCodecs
-	}
-
-	var errors MultiError
-	for _, codec := range codecs {
-		err := codec.Decode(name, value, dst)
-		if err == nil {
-			return nil
-		}
-		errors = append(errors, err)
-	}
-	return errors
-}
-
-// MultiError groups multiple errors.
-type MultiError []error
-
-func (m MultiError) IsUsage() bool    { return m.any(func(e Error) bool { return e.IsUsage() }) }
-func (m MultiError) IsDecode() bool   { return m.any(func(e Error) bool { return e.IsDecode() }) }
-func (m MultiError) IsInternal() bool { return m.any(func(e Error) bool { return e.IsInternal() }) }
-
-// Cause returns nil for MultiError; there is no unique underlying cause in the
-// general case.
-//
-// Note: we could conceivably return a non-nil Cause only when there is exactly
-// one child error with a Cause.  However, it would be brittle for client code
-// to rely on the arity of causes inside a MultiError, so we have opted not to
-// provide this functionality.  Clients which really wish to access the Causes
-// of the underlying errors are free to iterate through the errors themselves.
-func (m MultiError) Cause() error { return nil }
-
-func (m MultiError) Error() string {
-	s, n := "", 0
-	for _, e := range m {
-		if e != nil {
-			if n == 0 {
-				s = e.Error()
-			}
-			n++
-		}
-	}
-	switch n {
-	case 0:
-		return "(0 errors)"
-	case 1:
-		return s
-	case 2:
-		return s + " (and 1 other error)"
-	}
-	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
-}
-
-// any returns true if any element of m is an Error for which pred returns true.
-func (m MultiError) any(pred func(Error) bool) bool {
-	for _, e := range m {
-		if ourErr, ok := e.(Error); ok && pred(ourErr) {
-			return true
-		}
-	}
-	return false
-}

+ 0 - 274
src/github.com/gorilla/securecookie/securecookie_test.go

@@ -1,274 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package securecookie
-
-import (
-	"crypto/aes"
-	"crypto/hmac"
-	"crypto/sha256"
-	"encoding/base64"
-	"fmt"
-	"reflect"
-	"strings"
-	"testing"
-)
-
-// Asserts that cookieError and MultiError are Error implementations.
-var _ Error = cookieError{}
-var _ Error = MultiError{}
-
-var testCookies = []interface{}{
-	map[string]string{"foo": "bar"},
-	map[string]string{"baz": "ding"},
-}
-
-var testStrings = []string{"foo", "bar", "baz"}
-
-func TestSecureCookie(t *testing.T) {
-	// TODO test too old / too new timestamps
-	s1 := New([]byte("12345"), []byte("1234567890123456"))
-	s2 := New([]byte("54321"), []byte("6543210987654321"))
-	value := map[string]interface{}{
-		"foo": "bar",
-		"baz": 128,
-	}
-
-	for i := 0; i < 50; i++ {
-		// Running this multiple times to check if any special character
-		// breaks encoding/decoding.
-		encoded, err1 := s1.Encode("sid", value)
-		if err1 != nil {
-			t.Error(err1)
-			continue
-		}
-		dst := make(map[string]interface{})
-		err2 := s1.Decode("sid", encoded, &dst)
-		if err2 != nil {
-			t.Fatalf("%v: %v", err2, encoded)
-		}
-		if !reflect.DeepEqual(dst, value) {
-			t.Fatalf("Expected %v, got %v.", value, dst)
-		}
-		dst2 := make(map[string]interface{})
-		err3 := s2.Decode("sid", encoded, &dst2)
-		if err3 == nil {
-			t.Fatalf("Expected failure decoding.")
-		}
-		err4, ok := err3.(Error)
-		if !ok {
-			t.Fatalf("Expected error to implement Error, got: %#v", err3)
-		}
-		if !err4.IsDecode() {
-			t.Fatalf("Expected DecodeError, got: %#v", err4)
-		}
-
-		// Test other error type flags.
-		if err4.IsUsage() {
-			t.Fatalf("Expected IsUsage() == false, got: %#v", err4)
-		}
-		if err4.IsInternal() {
-			t.Fatalf("Expected IsInternal() == false, got: %#v", err4)
-		}
-	}
-}
-
-func TestSecureCookieNilKey(t *testing.T) {
-	s1 := New(nil, nil)
-	value := map[string]interface{}{
-		"foo": "bar",
-		"baz": 128,
-	}
-	_, err := s1.Encode("sid", value)
-	if err != errHashKeyNotSet {
-		t.Fatal("Wrong error returned:", err)
-	}
-}
-
-func TestDecodeInvalid(t *testing.T) {
-	// List of invalid cookies, which must not be accepted, base64-decoded
-	// (they will be encoded before passing to Decode).
-	invalidCookies := []string{
-		"",
-		" ",
-		"\n",
-		"||",
-		"|||",
-		"cookie",
-	}
-	s := New([]byte("12345"), nil)
-	var dst string
-	for i, v := range invalidCookies {
-		for _, enc := range []*base64.Encoding{
-			base64.StdEncoding,
-			base64.URLEncoding,
-		} {
-			err := s.Decode("name", enc.EncodeToString([]byte(v)), &dst)
-			if err == nil {
-				t.Fatalf("%d: expected failure decoding", i)
-			}
-			err2, ok := err.(Error)
-			if !ok || !err2.IsDecode() {
-				t.Fatalf("%d: Expected IsDecode(), got: %#v", i, err)
-			}
-		}
-	}
-}
-
-func TestAuthentication(t *testing.T) {
-	hash := hmac.New(sha256.New, []byte("secret-key"))
-	for _, value := range testStrings {
-		hash.Reset()
-		signed := createMac(hash, []byte(value))
-		hash.Reset()
-		err := verifyMac(hash, []byte(value), signed)
-		if err != nil {
-			t.Error(err)
-		}
-	}
-}
-
-func TestEncryption(t *testing.T) {
-	block, err := aes.NewCipher([]byte("1234567890123456"))
-	if err != nil {
-		t.Fatalf("Block could not be created")
-	}
-	var encrypted, decrypted []byte
-	for _, value := range testStrings {
-		if encrypted, err = encrypt(block, []byte(value)); err != nil {
-			t.Error(err)
-		} else {
-			if decrypted, err = decrypt(block, encrypted); err != nil {
-				t.Error(err)
-			}
-			if string(decrypted) != value {
-				t.Errorf("Expected %v, got %v.", value, string(decrypted))
-			}
-		}
-	}
-}
-
-func TestGobSerialization(t *testing.T) {
-	var (
-		sz           GobEncoder
-		serialized   []byte
-		deserialized map[string]string
-		err          error
-	)
-	for _, value := range testCookies {
-		if serialized, err = sz.Serialize(value); err != nil {
-			t.Error(err)
-		} else {
-			deserialized = make(map[string]string)
-			if err = sz.Deserialize(serialized, &deserialized); err != nil {
-				t.Error(err)
-			}
-			if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) {
-				t.Errorf("Expected %v, got %v.", value, deserialized)
-			}
-		}
-	}
-}
-
-func TestJSONSerialization(t *testing.T) {
-	var (
-		sz           JSONEncoder
-		serialized   []byte
-		deserialized map[string]string
-		err          error
-	)
-	for _, value := range testCookies {
-		if serialized, err = sz.Serialize(value); err != nil {
-			t.Error(err)
-		} else {
-			deserialized = make(map[string]string)
-			if err = sz.Deserialize(serialized, &deserialized); err != nil {
-				t.Error(err)
-			}
-			if fmt.Sprintf("%v", deserialized) != fmt.Sprintf("%v", value) {
-				t.Errorf("Expected %v, got %v.", value, deserialized)
-			}
-		}
-	}
-}
-
-func TestEncoding(t *testing.T) {
-	for _, value := range testStrings {
-		encoded := encode([]byte(value))
-		decoded, err := decode(encoded)
-		if err != nil {
-			t.Error(err)
-		} else if string(decoded) != value {
-			t.Errorf("Expected %v, got %s.", value, string(decoded))
-		}
-	}
-}
-
-func TestMultiError(t *testing.T) {
-	s1, s2 := New(nil, nil), New(nil, nil)
-	_, err := EncodeMulti("sid", "value", s1, s2)
-	if len(err.(MultiError)) != 2 {
-		t.Errorf("Expected 2 errors, got %s.", err)
-	} else {
-		if strings.Index(err.Error(), "hash key is not set") == -1 {
-			t.Errorf("Expected missing hash key error, got %s.", err.Error())
-		}
-		ourErr, ok := err.(Error)
-		if !ok || !ourErr.IsUsage() {
-			t.Fatalf("Expected error to be a usage error; got %#v", err)
-		}
-		if ourErr.IsDecode() {
-			t.Errorf("Expected error NOT to be a decode error; got %#v", ourErr)
-		}
-		if ourErr.IsInternal() {
-			t.Errorf("Expected error NOT to be an internal error; got %#v", ourErr)
-		}
-	}
-}
-
-func TestMultiNoCodecs(t *testing.T) {
-	_, err := EncodeMulti("foo", "bar")
-	if err != errNoCodecs {
-		t.Errorf("EncodeMulti: bad value for error, got: %v", err)
-	}
-
-	var dst []byte
-	err = DecodeMulti("foo", "bar", &dst)
-	if err != errNoCodecs {
-		t.Errorf("DecodeMulti: bad value for error, got: %v", err)
-	}
-}
-
-func TestMissingKey(t *testing.T) {
-	s1 := New(nil, nil)
-
-	var dst []byte
-	err := s1.Decode("sid", "value", &dst)
-	if err != errHashKeyNotSet {
-		t.Fatalf("Expected %#v, got %#v", errHashKeyNotSet, err)
-	}
-	if err2, ok := err.(Error); !ok || !err2.IsUsage() {
-		t.Errorf("Expected missing hash key to be IsUsage(); was %#v", err)
-	}
-}
-
-// ----------------------------------------------------------------------------
-
-type FooBar struct {
-	Foo int
-	Bar string
-}
-
-func TestCustomType(t *testing.T) {
-	s1 := New([]byte("12345"), []byte("1234567890123456"))
-	// Type is not registered in gob. (!!!)
-	src := &FooBar{42, "bar"}
-	encoded, _ := s1.Encode("sid", src)
-
-	dst := &FooBar{}
-	_ = s1.Decode("sid", encoded, dst)
-	if dst.Foo != 42 || dst.Bar != "bar" {
-		t.Fatalf("Expected %#v, got %#v", src, dst)
-	}
-}

+ 0 - 21
src/github.com/gorilla/sessions/.travis.yml

@@ -1,21 +0,0 @@
-language: go
-sudo: false
-
-matrix:
-  include:
-    - go: 1.3
-    - go: 1.4
-    - go: 1.5
-    - go: 1.6
-    - go: tip
-  allow_failures:
-    - go: tip
-
-install:
-  - # skip
-
-script:
-  - go get -t -v ./...
-  - diff -u <(echo -n) <(gofmt -d .)
-  - go vet $(go list ./... | grep -v /vendor/)
-  - go test -v -race ./...

+ 0 - 27
src/github.com/gorilla/sessions/LICENSE

@@ -1,27 +0,0 @@
-Copyright (c) 2012 Rodrigo Moraes. All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-	 * Redistributions of source code must retain the above copyright
-notice, this list of conditions and the following disclaimer.
-	 * Redistributions in binary form must reproduce the above
-copyright notice, this list of conditions and the following disclaimer
-in the documentation and/or other materials provided with the
-distribution.
-	 * Neither the name of Google Inc. nor the names of its
-contributors may be used to endorse or promote products derived from
-this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

+ 0 - 79
src/github.com/gorilla/sessions/README.md

@@ -1,79 +0,0 @@
-sessions
-========
-[![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.png?branch=master)](https://travis-ci.org/gorilla/sessions)
-
-gorilla/sessions provides cookie and filesystem sessions and infrastructure for
-custom session backends.
-
-The key features are:
-
-* Simple API: use it as an easy way to set signed (and optionally
-  encrypted) cookies.
-* Built-in backends to store sessions in cookies or the filesystem.
-* Flash messages: session values that last until read.
-* Convenient way to switch session persistency (aka "remember me") and set
-  other attributes.
-* Mechanism to rotate authentication and encryption keys.
-* Multiple sessions per request, even using different backends.
-* Interfaces and infrastructure for custom session backends: sessions from
-  different stores can be retrieved and batch-saved using a common API.
-
-Let's start with an example that shows the sessions API in a nutshell:
-
-```go
-	import (
-		"net/http"
-		"github.com/gorilla/sessions"
-	)
-
-	var store = sessions.NewCookieStore([]byte("something-very-secret"))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session. We're ignoring the error resulted from decoding an
-		// existing session: Get() always returns a session, even if empty.
-		session, _ := store.Get(r, "session-name")
-		// Set some session values.
-		session.Values["foo"] = "bar"
-		session.Values[42] = 43
-		// Save it before we write to the response/return from the handler.
-		session.Save(r, w)
-	}
-```
-
-First we initialize a session store calling `NewCookieStore()` and passing a
-secret key used to authenticate the session. Inside the handler, we call
-`store.Get()` to retrieve an existing session or a new one. Then we set some
-session values in session.Values, which is a `map[interface{}]interface{}`.
-And finally we call `session.Save()` to save the session in the response.
-
-Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
-with
-[`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler)
-as or else you will leak memory! An easy way to do this is to wrap the top-level
-mux when calling http.ListenAndServe:
-
-More examples are available [on the Gorilla
-website](http://www.gorillatoolkit.org/pkg/sessions).
-
-## Store Implementations
-
-Other implementations of the `sessions.Store` interface:
-
-* [github.com/starJammer/gorilla-sessions-arangodb](https://github.com/starJammer/gorilla-sessions-arangodb) - ArangoDB
-* [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt
-* [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
-* [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS
-* [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
-* [github.com/hnakamur/gaesessions](https://github.com/hnakamur/gaesessions) - Memcache on GAE
-* [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
-* [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
-* [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
-* [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
-* [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
-* [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
-* [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite
-* [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite)
-
-## License
-
-BSD licensed. See the LICENSE file for details.

+ 0 - 199
src/github.com/gorilla/sessions/doc.go

@@ -1,199 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-/*
-Package sessions provides cookie and filesystem sessions and
-infrastructure for custom session backends.
-
-The key features are:
-
-	* Simple API: use it as an easy way to set signed (and optionally
-	  encrypted) cookies.
-	* Built-in backends to store sessions in cookies or the filesystem.
-	* Flash messages: session values that last until read.
-	* Convenient way to switch session persistency (aka "remember me") and set
-	  other attributes.
-	* Mechanism to rotate authentication and encryption keys.
-	* Multiple sessions per request, even using different backends.
-	* Interfaces and infrastructure for custom session backends: sessions from
-	  different stores can be retrieved and batch-saved using a common API.
-
-Let's start with an example that shows the sessions API in a nutshell:
-
-	import (
-		"net/http"
-		"github.com/gorilla/sessions"
-	)
-
-	var store = sessions.NewCookieStore([]byte("something-very-secret"))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session. We're ignoring the error resulted from decoding an
-		// existing session: Get() always returns a session, even if empty.
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Set some session values.
-		session.Values["foo"] = "bar"
-		session.Values[42] = 43
-		// Save it before we write to the response/return from the handler.
-		session.Save(r, w)
-	}
-
-First we initialize a session store calling NewCookieStore() and passing a
-secret key used to authenticate the session. Inside the handler, we call
-store.Get() to retrieve an existing session or a new one. Then we set some
-session values in session.Values, which is a map[interface{}]interface{}.
-And finally we call session.Save() to save the session in the response.
-
-Note that in production code, we should check for errors when calling
-session.Save(r, w), and either display an error message or otherwise handle it.
-
-Save must be called before writing to the response, otherwise the session
-cookie will not be sent to the client.
-
-Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
-with context.ClearHandler as or else you will leak memory! An easy way to do this
-is to wrap the top-level mux when calling http.ListenAndServe:
-
-    http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
-
-The ClearHandler function is provided by the gorilla/context package.
-
-That's all you need to know for the basic usage. Let's take a look at other
-options, starting with flash messages.
-
-Flash messages are session values that last until read. The term appeared with
-Ruby On Rails a few years back. When we request a flash message, it is removed
-from the session. To add a flash, call session.AddFlash(), and to get all
-flashes, call session.Flashes(). Here is an example:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session.
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Get the previously flashes, if any.
-		if flashes := session.Flashes(); len(flashes) > 0 {
-			// Use the flash values.
-		} else {
-			// Set a new flash.
-			session.AddFlash("Hello, flash messages world!")
-		}
-		session.Save(r, w)
-	}
-
-Flash messages are useful to set information to be read after a redirection,
-like after form submissions.
-
-There may also be cases where you want to store a complex datatype within a
-session, such as a struct. Sessions are serialised using the encoding/gob package,
-so it is easy to register new datatypes for storage in sessions:
-
-	import(
-		"encoding/gob"
-		"github.com/gorilla/sessions"
-	)
-
-	type Person struct {
-		FirstName	string
-		LastName 	string
-		Email		string
-		Age			int
-	}
-
-	type M map[string]interface{}
-
-	func init() {
-
-		gob.Register(&Person{})
-		gob.Register(&M{})
-	}
-
-As it's not possible to pass a raw type as a parameter to a function, gob.Register()
-relies on us passing it a value of the desired type. In the example above we've passed
-it a pointer to a struct and a pointer to a custom type representing a
-map[string]interface. (We could have passed non-pointer values if we wished.) This will
-then allow us to serialise/deserialise values of those types to and from our sessions.
-
-Note that because session values are stored in a map[string]interface{}, there's
-a need to type-assert data when retrieving it. We'll use the Person struct we registered above:
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		session, err := store.Get(r, "session-name")
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-
-		// Retrieve our struct and type-assert it
-		val := session.Values["person"]
-		var person = &Person{}
-		if person, ok := val.(*Person); !ok {
-			// Handle the case that it's not an expected type
-		}
-
-		// Now we can use our person object
-	}
-
-By default, session cookies last for a month. This is probably too long for
-some cases, but it is easy to change this and other attributes during
-runtime. Sessions can be configured individually or the store can be
-configured and then all sessions saved using it will use that configuration.
-We access session.Options or store.Options to set a new configuration. The
-fields are basically a subset of http.Cookie fields. Let's change the
-maximum age of a session to one week:
-
-	session.Options = &sessions.Options{
-		Path:     "/",
-		MaxAge:   86400 * 7,
-		HttpOnly: true,
-	}
-
-Sometimes we may want to change authentication and/or encryption keys without
-breaking existing sessions. The CookieStore supports key rotation, and to use
-it you just need to set multiple authentication and encryption keys, in pairs,
-to be tested in order:
-
-	var store = sessions.NewCookieStore(
-		[]byte("new-authentication-key"),
-		[]byte("new-encryption-key"),
-		[]byte("old-authentication-key"),
-		[]byte("old-encryption-key"),
-	)
-
-New sessions will be saved using the first pair. Old sessions can still be
-read because the first pair will fail, and the second will be tested. This
-makes it easy to "rotate" secret keys and still be able to validate existing
-sessions. Note: for all pairs the encryption key is optional; set it to nil
-or omit it and and encryption won't be used.
-
-Multiple sessions can be used in the same request, even with different
-session backends. When this happens, calling Save() on each session
-individually would be cumbersome, so we have a way to save all sessions
-at once: it's sessions.Save(). Here's an example:
-
-	var store = sessions.NewCookieStore([]byte("something-very-secret"))
-
-	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session and set a value.
-		session1, _ := store.Get(r, "session-one")
-		session1.Values["foo"] = "bar"
-		// Get another session and set another value.
-		session2, _ := store.Get(r, "session-two")
-		session2.Values[42] = 43
-		// Save all sessions.
-		sessions.Save(r, w)
-	}
-
-This is possible because when we call Get() from a session store, it adds the
-session to a common registry. Save() uses it to save all registered sessions.
-*/
-package sessions

+ 0 - 102
src/github.com/gorilla/sessions/lex.go

@@ -1,102 +0,0 @@
-// This file contains code adapted from the Go standard library
-// https://github.com/golang/go/blob/39ad0fd0789872f9469167be7fe9578625ff246e/src/net/http/lex.go
-
-package sessions
-
-import "strings"
-
-var isTokenTable = [127]bool{
-	'!':  true,
-	'#':  true,
-	'$':  true,
-	'%':  true,
-	'&':  true,
-	'\'': true,
-	'*':  true,
-	'+':  true,
-	'-':  true,
-	'.':  true,
-	'0':  true,
-	'1':  true,
-	'2':  true,
-	'3':  true,
-	'4':  true,
-	'5':  true,
-	'6':  true,
-	'7':  true,
-	'8':  true,
-	'9':  true,
-	'A':  true,
-	'B':  true,
-	'C':  true,
-	'D':  true,
-	'E':  true,
-	'F':  true,
-	'G':  true,
-	'H':  true,
-	'I':  true,
-	'J':  true,
-	'K':  true,
-	'L':  true,
-	'M':  true,
-	'N':  true,
-	'O':  true,
-	'P':  true,
-	'Q':  true,
-	'R':  true,
-	'S':  true,
-	'T':  true,
-	'U':  true,
-	'W':  true,
-	'V':  true,
-	'X':  true,
-	'Y':  true,
-	'Z':  true,
-	'^':  true,
-	'_':  true,
-	'`':  true,
-	'a':  true,
-	'b':  true,
-	'c':  true,
-	'd':  true,
-	'e':  true,
-	'f':  true,
-	'g':  true,
-	'h':  true,
-	'i':  true,
-	'j':  true,
-	'k':  true,
-	'l':  true,
-	'm':  true,
-	'n':  true,
-	'o':  true,
-	'p':  true,
-	'q':  true,
-	'r':  true,
-	's':  true,
-	't':  true,
-	'u':  true,
-	'v':  true,
-	'w':  true,
-	'x':  true,
-	'y':  true,
-	'z':  true,
-	'|':  true,
-	'~':  true,
-}
-
-func isToken(r rune) bool {
-	i := int(r)
-	return i < len(isTokenTable) && isTokenTable[i]
-}
-
-func isNotToken(r rune) bool {
-	return !isToken(r)
-}
-
-func isCookieNameValid(raw string) bool {
-	if raw == "" {
-		return false
-	}
-	return strings.IndexFunc(raw, isNotToken) < 0
-}

+ 0 - 241
src/github.com/gorilla/sessions/sessions.go

@@ -1,241 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sessions
-
-import (
-	"encoding/gob"
-	"fmt"
-	"net/http"
-	"time"
-
-	"github.com/gorilla/context"
-)
-
-// Default flashes key.
-const flashesKey = "_flash"
-
-// Options --------------------------------------------------------------------
-
-// Options stores configuration for a session or session store.
-//
-// Fields are a subset of http.Cookie fields.
-type Options struct {
-	Path   string
-	Domain string
-	// MaxAge=0 means no 'Max-Age' attribute specified.
-	// MaxAge<0 means delete cookie now, equivalently 'Max-Age: 0'.
-	// MaxAge>0 means Max-Age attribute present and given in seconds.
-	MaxAge   int
-	Secure   bool
-	HttpOnly bool
-}
-
-// Session --------------------------------------------------------------------
-
-// NewSession is called by session stores to create a new session instance.
-func NewSession(store Store, name string) *Session {
-	return &Session{
-		Values: make(map[interface{}]interface{}),
-		store:  store,
-		name:   name,
-	}
-}
-
-// Session stores the values and optional configuration for a session.
-type Session struct {
-	// The ID of the session, generated by stores. It should not be used for
-	// user data.
-	ID string
-	// Values contains the user-data for the session.
-	Values  map[interface{}]interface{}
-	Options *Options
-	IsNew   bool
-	store   Store
-	name    string
-}
-
-// Flashes returns a slice of flash messages from the session.
-//
-// A single variadic argument is accepted, and it is optional: it defines
-// the flash key. If not defined "_flash" is used by default.
-func (s *Session) Flashes(vars ...string) []interface{} {
-	var flashes []interface{}
-	key := flashesKey
-	if len(vars) > 0 {
-		key = vars[0]
-	}
-	if v, ok := s.Values[key]; ok {
-		// Drop the flashes and return it.
-		delete(s.Values, key)
-		flashes = v.([]interface{})
-	}
-	return flashes
-}
-
-// AddFlash adds a flash message to the session.
-//
-// A single variadic argument is accepted, and it is optional: it defines
-// the flash key. If not defined "_flash" is used by default.
-func (s *Session) AddFlash(value interface{}, vars ...string) {
-	key := flashesKey
-	if len(vars) > 0 {
-		key = vars[0]
-	}
-	var flashes []interface{}
-	if v, ok := s.Values[key]; ok {
-		flashes = v.([]interface{})
-	}
-	s.Values[key] = append(flashes, value)
-}
-
-// Save is a convenience method to save this session. It is the same as calling
-// store.Save(request, response, session). You should call Save before writing to
-// the response or returning from the handler.
-func (s *Session) Save(r *http.Request, w http.ResponseWriter) error {
-	return s.store.Save(r, w, s)
-}
-
-// Name returns the name used to register the session.
-func (s *Session) Name() string {
-	return s.name
-}
-
-// Store returns the session store used to register the session.
-func (s *Session) Store() Store {
-	return s.store
-}
-
-// Registry -------------------------------------------------------------------
-
-// sessionInfo stores a session tracked by the registry.
-type sessionInfo struct {
-	s *Session
-	e error
-}
-
-// contextKey is the type used to store the registry in the context.
-type contextKey int
-
-// registryKey is the key used to store the registry in the context.
-const registryKey contextKey = 0
-
-// GetRegistry returns a registry instance for the current request.
-func GetRegistry(r *http.Request) *Registry {
-	registry := context.Get(r, registryKey)
-	if registry != nil {
-		return registry.(*Registry)
-	}
-	newRegistry := &Registry{
-		request:  r,
-		sessions: make(map[string]sessionInfo),
-	}
-	context.Set(r, registryKey, newRegistry)
-	return newRegistry
-}
-
-// Registry stores sessions used during a request.
-type Registry struct {
-	request  *http.Request
-	sessions map[string]sessionInfo
-}
-
-// Get registers and returns a session for the given name and session store.
-//
-// It returns a new session if there are no sessions registered for the name.
-func (s *Registry) Get(store Store, name string) (session *Session, err error) {
-	if !isCookieNameValid(name) {
-		return nil, fmt.Errorf("sessions: invalid character in cookie name: %s", name)
-	}
-	if info, ok := s.sessions[name]; ok {
-		session, err = info.s, info.e
-	} else {
-		session, err = store.New(s.request, name)
-		session.name = name
-		s.sessions[name] = sessionInfo{s: session, e: err}
-	}
-	session.store = store
-	return
-}
-
-// Save saves all sessions registered for the current request.
-func (s *Registry) Save(w http.ResponseWriter) error {
-	var errMulti MultiError
-	for name, info := range s.sessions {
-		session := info.s
-		if session.store == nil {
-			errMulti = append(errMulti, fmt.Errorf(
-				"sessions: missing store for session %q", name))
-		} else if err := session.store.Save(s.request, w, session); err != nil {
-			errMulti = append(errMulti, fmt.Errorf(
-				"sessions: error saving session %q -- %v", name, err))
-		}
-	}
-	if errMulti != nil {
-		return errMulti
-	}
-	return nil
-}
-
-// Helpers --------------------------------------------------------------------
-
-func init() {
-	gob.Register([]interface{}{})
-}
-
-// Save saves all sessions used during the current request.
-func Save(r *http.Request, w http.ResponseWriter) error {
-	return GetRegistry(r).Save(w)
-}
-
-// NewCookie returns an http.Cookie with the options set. It also sets
-// the Expires field calculated based on the MaxAge value, for Internet
-// Explorer compatibility.
-func NewCookie(name, value string, options *Options) *http.Cookie {
-	cookie := &http.Cookie{
-		Name:     name,
-		Value:    value,
-		Path:     options.Path,
-		Domain:   options.Domain,
-		MaxAge:   options.MaxAge,
-		Secure:   options.Secure,
-		HttpOnly: options.HttpOnly,
-	}
-	if options.MaxAge > 0 {
-		d := time.Duration(options.MaxAge) * time.Second
-		cookie.Expires = time.Now().Add(d)
-	} else if options.MaxAge < 0 {
-		// Set it to the past to expire now.
-		cookie.Expires = time.Unix(1, 0)
-	}
-	return cookie
-}
-
-// Error ----------------------------------------------------------------------
-
-// MultiError stores multiple errors.
-//
-// Borrowed from the App Engine SDK.
-type MultiError []error
-
-func (m MultiError) Error() string {
-	s, n := "", 0
-	for _, e := range m {
-		if e != nil {
-			if n == 0 {
-				s = e.Error()
-			}
-			n++
-		}
-	}
-	switch n {
-	case 0:
-		return "(0 errors)"
-	case 1:
-		return s
-	case 2:
-		return s + " (and 1 other error)"
-	}
-	return fmt.Sprintf("%s (and %d other errors)", s, n-1)
-}

+ 0 - 201
src/github.com/gorilla/sessions/sessions_test.go

@@ -1,201 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sessions
-
-import (
-	"bytes"
-	"encoding/gob"
-	"net/http"
-	"testing"
-)
-
-// ----------------------------------------------------------------------------
-// ResponseRecorder
-// ----------------------------------------------------------------------------
-// Copyright 2009 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// ResponseRecorder is an implementation of http.ResponseWriter that
-// records its mutations for later inspection in tests.
-type ResponseRecorder struct {
-	Code      int           // the HTTP response code from WriteHeader
-	HeaderMap http.Header   // the HTTP response headers
-	Body      *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to
-	Flushed   bool
-}
-
-// NewRecorder returns an initialized ResponseRecorder.
-func NewRecorder() *ResponseRecorder {
-	return &ResponseRecorder{
-		HeaderMap: make(http.Header),
-		Body:      new(bytes.Buffer),
-	}
-}
-
-// DefaultRemoteAddr is the default remote address to return in RemoteAddr if
-// an explicit DefaultRemoteAddr isn't set on ResponseRecorder.
-const DefaultRemoteAddr = "1.2.3.4"
-
-// Header returns the response headers.
-func (rw *ResponseRecorder) Header() http.Header {
-	return rw.HeaderMap
-}
-
-// Write always succeeds and writes to rw.Body, if not nil.
-func (rw *ResponseRecorder) Write(buf []byte) (int, error) {
-	if rw.Body != nil {
-		rw.Body.Write(buf)
-	}
-	if rw.Code == 0 {
-		rw.Code = http.StatusOK
-	}
-	return len(buf), nil
-}
-
-// WriteHeader sets rw.Code.
-func (rw *ResponseRecorder) WriteHeader(code int) {
-	rw.Code = code
-}
-
-// Flush sets rw.Flushed to true.
-func (rw *ResponseRecorder) Flush() {
-	rw.Flushed = true
-}
-
-// ----------------------------------------------------------------------------
-
-type FlashMessage struct {
-	Type    int
-	Message string
-}
-
-func TestFlashes(t *testing.T) {
-	var req *http.Request
-	var rsp *ResponseRecorder
-	var hdr http.Header
-	var err error
-	var ok bool
-	var cookies []string
-	var session *Session
-	var flashes []interface{}
-
-	store := NewCookieStore([]byte("secret-key"))
-
-	// Round 1 ----------------------------------------------------------------
-
-	req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
-	rsp = NewRecorder()
-	// Get a session.
-	if session, err = store.Get(req, "session-key"); err != nil {
-		t.Fatalf("Error getting session: %v", err)
-	}
-	// Get a flash.
-	flashes = session.Flashes()
-	if len(flashes) != 0 {
-		t.Errorf("Expected empty flashes; Got %v", flashes)
-	}
-	// Add some flashes.
-	session.AddFlash("foo")
-	session.AddFlash("bar")
-	// Custom key.
-	session.AddFlash("baz", "custom_key")
-	// Save.
-	if err = Save(req, rsp); err != nil {
-		t.Fatalf("Error saving session: %v", err)
-	}
-	hdr = rsp.Header()
-	cookies, ok = hdr["Set-Cookie"]
-	if !ok || len(cookies) != 1 {
-		t.Fatal("No cookies. Header:", hdr)
-	}
-
-	if _, err = store.Get(req, "session:key"); err.Error() != "sessions: invalid character in cookie name: session:key" {
-		t.Fatalf("Expected error due to invalid cookie name")
-	}
-
-	// Round 2 ----------------------------------------------------------------
-
-	req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
-	req.Header.Add("Cookie", cookies[0])
-	rsp = NewRecorder()
-	// Get a session.
-	if session, err = store.Get(req, "session-key"); err != nil {
-		t.Fatalf("Error getting session: %v", err)
-	}
-	// Check all saved values.
-	flashes = session.Flashes()
-	if len(flashes) != 2 {
-		t.Fatalf("Expected flashes; Got %v", flashes)
-	}
-	if flashes[0] != "foo" || flashes[1] != "bar" {
-		t.Errorf("Expected foo,bar; Got %v", flashes)
-	}
-	flashes = session.Flashes()
-	if len(flashes) != 0 {
-		t.Errorf("Expected dumped flashes; Got %v", flashes)
-	}
-	// Custom key.
-	flashes = session.Flashes("custom_key")
-	if len(flashes) != 1 {
-		t.Errorf("Expected flashes; Got %v", flashes)
-	} else if flashes[0] != "baz" {
-		t.Errorf("Expected baz; Got %v", flashes)
-	}
-	flashes = session.Flashes("custom_key")
-	if len(flashes) != 0 {
-		t.Errorf("Expected dumped flashes; Got %v", flashes)
-	}
-
-	// Round 3 ----------------------------------------------------------------
-	// Custom type
-
-	req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
-	rsp = NewRecorder()
-	// Get a session.
-	if session, err = store.Get(req, "session-key"); err != nil {
-		t.Fatalf("Error getting session: %v", err)
-	}
-	// Get a flash.
-	flashes = session.Flashes()
-	if len(flashes) != 0 {
-		t.Errorf("Expected empty flashes; Got %v", flashes)
-	}
-	// Add some flashes.
-	session.AddFlash(&FlashMessage{42, "foo"})
-	// Save.
-	if err = Save(req, rsp); err != nil {
-		t.Fatalf("Error saving session: %v", err)
-	}
-	hdr = rsp.Header()
-	cookies, ok = hdr["Set-Cookie"]
-	if !ok || len(cookies) != 1 {
-		t.Fatal("No cookies. Header:", hdr)
-	}
-
-	// Round 4 ----------------------------------------------------------------
-	// Custom type
-
-	req, _ = http.NewRequest("GET", "http://localhost:8080/", nil)
-	req.Header.Add("Cookie", cookies[0])
-	rsp = NewRecorder()
-	// Get a session.
-	if session, err = store.Get(req, "session-key"); err != nil {
-		t.Fatalf("Error getting session: %v", err)
-	}
-	// Check all saved values.
-	flashes = session.Flashes()
-	if len(flashes) != 1 {
-		t.Fatalf("Expected flashes; Got %v", flashes)
-	}
-	custom := flashes[0].(FlashMessage)
-	if custom.Type != 42 || custom.Message != "foo" {
-		t.Errorf("Expected %#v, got %#v", FlashMessage{42, "foo"}, custom)
-	}
-}
-
-func init() {
-	gob.Register(FlashMessage{})
-}

+ 0 - 270
src/github.com/gorilla/sessions/store.go

@@ -1,270 +0,0 @@
-// Copyright 2012 The Gorilla Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package sessions
-
-import (
-	"encoding/base32"
-	"io/ioutil"
-	"net/http"
-	"os"
-	"path/filepath"
-	"strings"
-	"sync"
-
-	"github.com/gorilla/securecookie"
-)
-
-// Store is an interface for custom session stores.
-//
-// See CookieStore and FilesystemStore for examples.
-type Store interface {
-	// Get should return a cached session.
-	Get(r *http.Request, name string) (*Session, error)
-
-	// New should create and return a new session.
-	//
-	// Note that New should never return a nil session, even in the case of
-	// an error if using the Registry infrastructure to cache the session.
-	New(r *http.Request, name string) (*Session, error)
-
-	// Save should persist session to the underlying store implementation.
-	Save(r *http.Request, w http.ResponseWriter, s *Session) error
-}
-
-// CookieStore ----------------------------------------------------------------
-
-// NewCookieStore returns a new CookieStore.
-//
-// Keys are defined in pairs to allow key rotation, but the common case is
-// to set a single authentication key and optionally an encryption key.
-//
-// The first key in a pair is used for authentication and the second for
-// encryption. The encryption key can be set to nil or omitted in the last
-// pair, but the authentication key is required in all pairs.
-//
-// It is recommended to use an authentication key with 32 or 64 bytes.
-// The encryption key, if set, must be either 16, 24, or 32 bytes to select
-// AES-128, AES-192, or AES-256 modes.
-//
-// Use the convenience function securecookie.GenerateRandomKey() to create
-// strong keys.
-func NewCookieStore(keyPairs ...[]byte) *CookieStore {
-	cs := &CookieStore{
-		Codecs: securecookie.CodecsFromPairs(keyPairs...),
-		Options: &Options{
-			Path:   "/",
-			MaxAge: 86400 * 30,
-		},
-	}
-
-	cs.MaxAge(cs.Options.MaxAge)
-	return cs
-}
-
-// CookieStore stores sessions using secure cookies.
-type CookieStore struct {
-	Codecs  []securecookie.Codec
-	Options *Options // default configuration
-}
-
-// Get returns a session for the given name after adding it to the registry.
-//
-// It returns a new session if the sessions doesn't exist. Access IsNew on
-// the session to check if it is an existing session or a new one.
-//
-// It returns a new session and an error if the session exists but could
-// not be decoded.
-func (s *CookieStore) Get(r *http.Request, name string) (*Session, error) {
-	return GetRegistry(r).Get(s, name)
-}
-
-// New returns a session for the given name without adding it to the registry.
-//
-// The difference between New() and Get() is that calling New() twice will
-// decode the session data twice, while Get() registers and reuses the same
-// decoded session after the first call.
-func (s *CookieStore) New(r *http.Request, name string) (*Session, error) {
-	session := NewSession(s, name)
-	opts := *s.Options
-	session.Options = &opts
-	session.IsNew = true
-	var err error
-	if c, errCookie := r.Cookie(name); errCookie == nil {
-		err = securecookie.DecodeMulti(name, c.Value, &session.Values,
-			s.Codecs...)
-		if err == nil {
-			session.IsNew = false
-		}
-	}
-	return session, err
-}
-
-// Save adds a single session to the response.
-func (s *CookieStore) Save(r *http.Request, w http.ResponseWriter,
-	session *Session) error {
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
-	return nil
-}
-
-// MaxAge sets the maximum age for the store and the underlying cookie
-// implementation. Individual sessions can be deleted by setting Options.MaxAge
-// = -1 for that session.
-func (s *CookieStore) MaxAge(age int) {
-	s.Options.MaxAge = age
-
-	// Set the maxAge for each securecookie instance.
-	for _, codec := range s.Codecs {
-		if sc, ok := codec.(*securecookie.SecureCookie); ok {
-			sc.MaxAge(age)
-		}
-	}
-}
-
-// FilesystemStore ------------------------------------------------------------
-
-var fileMutex sync.RWMutex
-
-// NewFilesystemStore returns a new FilesystemStore.
-//
-// The path argument is the directory where sessions will be saved. If empty
-// it will use os.TempDir().
-//
-// See NewCookieStore() for a description of the other parameters.
-func NewFilesystemStore(path string, keyPairs ...[]byte) *FilesystemStore {
-	if path == "" {
-		path = os.TempDir()
-	}
-	fs := &FilesystemStore{
-		Codecs: securecookie.CodecsFromPairs(keyPairs...),
-		Options: &Options{
-			Path:   "/",
-			MaxAge: 86400 * 30,
-		},
-		path: path,
-	}
-
-	fs.MaxAge(fs.Options.MaxAge)
-	return fs
-}
-
-// FilesystemStore stores sessions in the filesystem.
-//
-// It also serves as a reference for custom stores.
-//
-// This store is still experimental and not well tested. Feedback is welcome.
-type FilesystemStore struct {
-	Codecs  []securecookie.Codec
-	Options *Options // default configuration
-	path    string
-}
-
-// MaxLength restricts the maximum length of new sessions to l.
-// If l is 0 there is no limit to the size of a session, use with caution.
-// The default for a new FilesystemStore is 4096.
-func (s *FilesystemStore) MaxLength(l int) {
-	for _, c := range s.Codecs {
-		if codec, ok := c.(*securecookie.SecureCookie); ok {
-			codec.MaxLength(l)
-		}
-	}
-}
-
-// Get returns a session for the given name after adding it to the registry.
-//
-// See CookieStore.Get().
-func (s *FilesystemStore) Get(r *http.Request, name string) (*Session, error) {
-	return GetRegistry(r).Get(s, name)
-}
-
-// New returns a session for the given name without adding it to the registry.
-//
-// See CookieStore.New().
-func (s *FilesystemStore) New(r *http.Request, name string) (*Session, error) {
-	session := NewSession(s, name)
-	opts := *s.Options
-	session.Options = &opts
-	session.IsNew = true
-	var err error
-	if c, errCookie := r.Cookie(name); errCookie == nil {
-		err = securecookie.DecodeMulti(name, c.Value, &session.ID, s.Codecs...)
-		if err == nil {
-			err = s.load(session)
-			if err == nil {
-				session.IsNew = false
-			}
-		}
-	}
-	return session, err
-}
-
-// Save adds a single session to the response.
-func (s *FilesystemStore) Save(r *http.Request, w http.ResponseWriter,
-	session *Session) error {
-	if session.ID == "" {
-		// Because the ID is used in the filename, encode it to
-		// use alphanumeric characters only.
-		session.ID = strings.TrimRight(
-			base32.StdEncoding.EncodeToString(
-				securecookie.GenerateRandomKey(32)), "=")
-	}
-	if err := s.save(session); err != nil {
-		return err
-	}
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.ID,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	http.SetCookie(w, NewCookie(session.Name(), encoded, session.Options))
-	return nil
-}
-
-// MaxAge sets the maximum age for the store and the underlying cookie
-// implementation. Individual sessions can be deleted by setting Options.MaxAge
-// = -1 for that session.
-func (s *FilesystemStore) MaxAge(age int) {
-	s.Options.MaxAge = age
-
-	// Set the maxAge for each securecookie instance.
-	for _, codec := range s.Codecs {
-		if sc, ok := codec.(*securecookie.SecureCookie); ok {
-			sc.MaxAge(age)
-		}
-	}
-}
-
-// save writes encoded session.Values to a file.
-func (s *FilesystemStore) save(session *Session) error {
-	encoded, err := securecookie.EncodeMulti(session.Name(), session.Values,
-		s.Codecs...)
-	if err != nil {
-		return err
-	}
-	filename := filepath.Join(s.path, "session_"+session.ID)
-	fileMutex.Lock()
-	defer fileMutex.Unlock()
-	return ioutil.WriteFile(filename, []byte(encoded), 0600)
-}
-
-// load reads a file and decodes its content into session.Values.
-func (s *FilesystemStore) load(session *Session) error {
-	filename := filepath.Join(s.path, "session_"+session.ID)
-	fileMutex.RLock()
-	defer fileMutex.RUnlock()
-	fdata, err := ioutil.ReadFile(filename)
-	if err != nil {
-		return err
-	}
-	if err = securecookie.DecodeMulti(session.Name(), string(fdata),
-		&session.Values, s.Codecs...); err != nil {
-		return err
-	}
-	return nil
-}

+ 0 - 73
src/github.com/gorilla/sessions/store_test.go

@@ -1,73 +0,0 @@
-package sessions
-
-import (
-	"encoding/base64"
-	"net/http"
-	"net/http/httptest"
-	"testing"
-)
-
-// Test for GH-8 for CookieStore
-func TestGH8CookieStore(t *testing.T) {
-	originalPath := "/"
-	store := NewCookieStore()
-	store.Options.Path = originalPath
-	req, err := http.NewRequest("GET", "http://www.example.com", nil)
-	if err != nil {
-		t.Fatal("failed to create request", err)
-	}
-
-	session, err := store.New(req, "hello")
-	if err != nil {
-		t.Fatal("failed to create session", err)
-	}
-
-	store.Options.Path = "/foo"
-	if session.Options.Path != originalPath {
-		t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath)
-	}
-}
-
-// Test for GH-8 for FilesystemStore
-func TestGH8FilesystemStore(t *testing.T) {
-	originalPath := "/"
-	store := NewFilesystemStore("")
-	store.Options.Path = originalPath
-	req, err := http.NewRequest("GET", "http://www.example.com", nil)
-	if err != nil {
-		t.Fatal("failed to create request", err)
-	}
-
-	session, err := store.New(req, "hello")
-	if err != nil {
-		t.Fatal("failed to create session", err)
-	}
-
-	store.Options.Path = "/foo"
-	if session.Options.Path != originalPath {
-		t.Fatalf("bad session path: got %q, want %q", session.Options.Path, originalPath)
-	}
-}
-
-// Test for GH-2.
-func TestGH2MaxLength(t *testing.T) {
-	store := NewFilesystemStore("", []byte("some key"))
-	req, err := http.NewRequest("GET", "http://www.example.com", nil)
-	if err != nil {
-		t.Fatal("failed to create request", err)
-	}
-	w := httptest.NewRecorder()
-
-	session, err := store.New(req, "my session")
-	session.Values["big"] = make([]byte, base64.StdEncoding.DecodedLen(4096*2))
-	err = session.Save(req, w)
-	if err == nil {
-		t.Fatal("expected an error, got nil")
-	}
-
-	store.MaxLength(4096 * 3) // A bit more than the value size to account for encoding overhead.
-	err = session.Save(req, w)
-	if err != nil {
-		t.Fatal("failed to Save:", err)
-	}
-}

+ 1 - 1
src/task/task.go

@@ -111,7 +111,7 @@ type TTask struct {
 	I_fieldUpdate      int                    //分类中的保存字段信息 0:覆盖 1:更新
 	MulMgo             *u.MongodbSim          //联合查询的mgo配置信息
 	MulColl            string                 //联合查询的表名
-	I_tasktype         int                    //任务类型 0:常规任务 1:附件任务
+	I_tasktype         int                    //任务类型 0:常规任务 1:附件任务:2
 	S_idcoll           string                 //正式环境查询数据id段
 	B_UpdateRule       bool                   //是否更新任务下的规则
 	S_classField       string                 //分类字段

+ 7 - 7
src/task/updatetask.go

@@ -282,8 +282,8 @@ func NewClassificationRun(tt *TTask, tmp map[string]interface{}) *tools.SortMap
 					}
 					for _, r := range rule {
 						if s_pid != "" { //只要此类的父类不为空
-							ru_s_pid := r.S_pid //规则的父类id
-							class_s_pid := strings.Split(s_pid, ",")
+							ru_s_pid := r.S_pid                      //当前规则的父规则id
+							class_s_pid := strings.Split(s_pid, ",") //当前规则所属类的父类集合
 							bcontinue := true
 						L1:
 							for _, c_s_pid := range class_s_pid {
@@ -341,7 +341,7 @@ func NewClassificationRun(tt *TTask, tmp map[string]interface{}) *tools.SortMap
 								fflag[cid] = []string{r_id} //第一个规则中的_id
 							}
 							s_name := r.S_name
-							if tt.I_wordcount == 1 && len(rulearr) > 0 {
+							if tt.I_wordcount == 1 && len(rulearr) > 0 { //词频统计
 								tt.WcLock.Lock()
 								map1 := tt.WordCount[s_name]
 								if map1 == nil {
@@ -355,8 +355,8 @@ func NewClassificationRun(tt *TTask, tmp map[string]interface{}) *tools.SortMap
 							}
 							if savefield != "" {
 								s_code := r.S_code
-								if tt.I_multiclass == 0 {
-									if tt.I_savetype == 1 {
+								if tt.I_multiclass == 0 { //单分类
+									if tt.I_savetype == 1 { //存储属性
 										SMap.AddKey(savefield, s_name)
 									} else {
 										SMap.AddKey(savefield, s_code)
@@ -388,12 +388,12 @@ func NewClassificationRun(tt *TTask, tmp map[string]interface{}) *tools.SortMap
 			//设置默认值
 			//log.Println("smp", SMap.Map, SMap.Keys)
 			if savefield != "" && SMap.Map[savefield] == nil && c.S_default != "" {
-				if tt.I_multiclass == 0 {
+				if tt.I_multiclass == 0 { //单分类
 					//if savefield == "buyerclass" && util.ObjToString(tmp["buyer"]) == "" { //buyer不存在时,无buyerclass字段
 					//	return SMap
 					//}
 					SMap.AddKey(savefield, c.S_default)
-				} else {
+				} else { //多分类
 					SMap.AddKey(savefield, []string{c.S_default})
 				}
 			}