Giter Site home page Giter Site logo

bone's Introduction

bone GoDoc Build Status Go Report Card

What is bone ?

Bone is a lightweight and lightning fast HTTP Multiplexer for Golang. It support :

  • URL Parameters
  • REGEX Parameters
  • Wildcard routes
  • Router Prefix
  • Route params validators
  • Sub Router, mux.SubRoute(), support most standard router (bone, gorilla/mux, httpRouter etc...)
  • Http method declaration
  • Support for http.Handler and http.HandlerFunc
  • Custom NotFound handler
  • Respect the Go standard http.Handler interface

alt tag

Speed

- BenchmarkBoneMux        10000000               118 ns/op
- BenchmarkZeusMux          100000               144 ns/op
- BenchmarkHttpRouterMux  10000000               134 ns/op
- BenchmarkNetHttpMux      3000000               580 ns/op
- BenchmarkGorillaMux       300000              3333 ns/op
- BenchmarkGorillaPatMux   1000000              1889 ns/op

These tests are just for fun, all these routers are great and efficient. Bone isn't the fastest router for every job.

Example

package main

import(
  "net/http"

  "github.com/go-zoo/bone"
)

func main () {
  mux := bone.New()

  mux.RegisterValidatorFunc("isNum", func(s string) bool {
    if _, err := strconv.Atoi(s); err == nil {
      return true
    }
    return false
  })

  // mux.Get, Post, etc ... takes http.Handler
  // validator for route parameter
  mux.Get("/home/:id|isNum", http.HandlerFunc(HomeHandler))
  // multiple parameter
  mux.Get("/profil/:id/:var", http.HandlerFunc(ProfilHandler))
  mux.Post("/data", http.HandlerFunc(DataHandler))

  // Support REGEX Route params
  mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler))

  // Handle take http.Handler
  mux.Handle("/", http.HandlerFunc(RootHandler))

  // GetFunc, PostFunc etc ... takes http.HandlerFunc
  mux.GetFunc("/test", Handler)

  http.ListenAndServe(":8080", mux)
}

func Handler(rw http.ResponseWriter, req *http.Request) {
  // Get the value of the "id" parameters.
  val := bone.GetValue(req, "id")

  rw.Write([]byte(val))
}

Blog Posts

Libs

  • Errors dump for Go : Trash
  • Middleware Chaining module : Claw

bone's People

Contributors

abest0 avatar besser avatar bitdeli-chef avatar dushmis avatar hexadecy avatar kentquirk avatar madsroskar avatar mathieuleturcq avatar rpmoore avatar samwhited avatar sdkie avatar skabbes avatar stuartnelson3 avatar vahe avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bone's Issues

Panic: assignment to entry in nil map

Problem

I am occasionally getting the error http: panic serving 127.0.0.1:52703: assignment to entry in nil map

2015/06/18 15:10:00 http: panic serving 127.0.0.1:52703: assignment to entry in nil map
goroutine 98 [running]:
net/http.func·011()
        /home/ian/go/src/net/http/server.go:1130 +0xbb
github.com/go-zoo/bone.(*Route).Match(0xc20808d9a0, 0xc2081581a0, 0xc208152900)
        /home/ian/code/tester/src/github.com/go-zoo/bone/route.go:102 +0x523
github.com/go-zoo/bone.(*Mux).ServeHTTP(0xc2080c2ca0, 0x7f1d53fa5860, 0xc20807c5a0, 0xc2081581a0)
        /home/ian/code/tester/src/github.com/go-zoo/bone/bone.go:55 +0x5ec
net/http.serverHandler.ServeHTTP(0xc20808ecc0, 0x7f1d53fa5860, 0xc20807c5a0, 0xc2081581a0)
        /home/ian/go/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc2080b2460)
        /home/ian/go/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
        /home/ian/go/src/net/http/server.go:1751 +0x35e

This only happens intermittently and seemed to be only when the server had many simultaneous requests to the same url (but different parameters), eg calling /test/:id/result with ids 0-100 asynchronously via ajax.

Cause

The initial search for the cause was in route.go#L102 which is assigning a variable in a map created on L91. But between L91 and L102 the map was apparently being deleted somehow.

The deletion happens in bone.go#L56. I figured possibly the key was not unique across requests. So I tested it.

It turns out the request pointers are not unique in some circumstances. By logging just before delete(vars, token) in bone.go#L56 it was revealed that the same pointer is used for multiple requests (see full log below).

Solution

The solution is to make each request unique and use the unique key in the map, not the pointer.
edit: This did not solve it. See pull request below for the solution using locks.

In some proof-of-concept code I wrote I added a unique token to each request (by adding a unique header to the request) just before r.Match(req) is called (bone.go#L54).

Then instead of using *http.Request as the key for vars, change the key to be a string and use the unique request header value instead of the request itself.

This has fixed the issue.

I can submit a pull request if you like.

Full log

Log that shows reuse of pointers.

Before bone.go#L56 add log.Println(&req, req.URL.Path)

2015/06/18 15:09:58 0xc208120030 /api/v1/test/3/inputs
2015/06/18 15:09:58 0xc208030068 /api/v1/test/3/results
2015/06/18 15:09:58 0xc2080ec070 /api/v1/test/4/results
2015/06/18 15:09:58 0xc2080ec0a8 /api/v1/test/4/inputs
2015/06/18 15:09:58 0xc2080ec0b0 /api/v1/test/2/results
2015/06/18 15:09:58 0xc20816c000 /api/v1/test/5/inputs
2015/06/18 15:09:58 0xc2080ec0b8 /api/v1/test/2/inputs
2015/06/18 15:09:58 0xc208120038 /api/v1/test/5/results
2015/06/18 15:09:58 0xc208030028 /api/v1/test/6/results
2015/06/18 15:09:58 0xc208030048 /api/v1/test/6/inputs
2015/06/18 15:09:58 0xc2080ec070 /api/v1/test/1/inputs
2015/06/18 15:09:59 0xc208120050 /api/v1/test/8/results
2015/06/18 15:09:59 0xc2080ec0e0 /api/v1/test/9/results
2015/06/18 15:09:59 0xc2080ec010 /api/v1/test/7/inputs
2015/06/18 15:09:59 0xc2080ec0c0 /api/v1/test/7/results
2015/06/18 15:09:59 0xc2080ec068 /api/v1/test/1/results
2015/06/18 15:09:59 0xc2080ec0c8 /api/v1/test/8/inputs
2015/06/18 15:09:59 0xc20816c028 /api/v1/test/9/inputs
2015/06/18 15:09:59 0xc208030040 /api/v1/test/10/results
2015/06/18 15:09:59 0xc20816c040 /api/v1/test/10/inputs
2015/06/18 15:09:59 0xc20816c058 /api/v1/test/11/inputs
2015/06/18 15:09:59 0xc208030060 /api/v1/test/11/results
2015/06/18 15:09:59 0xc208030070 /api/v1/test/12/results
2015/06/18 15:09:59 0xc208120058 /api/v1/test/13/results
2015/06/18 15:09:59 0xc208030090 /api/v1/test/12/inputs
2015/06/18 15:09:59 0xc2080300a0 /api/v1/test/14/inputs
2015/06/18 15:09:59 0xc2080ec028 /api/v1/result/14/detail
2015/06/18 15:09:59 0xc2080ec018 /api/v1/result/13/detail
2015/06/18 15:09:59 0xc20816c068 /api/v1/test/14/results
2015/06/18 15:09:59 0xc208030020 /api/v1/result/15/detail
2015/06/18 15:09:59 0xc208120060 /api/v1/test/13/inputs
2015/06/18 15:09:59 0xc2080ec070 /api/v1/result/11/detail
2015/06/18 15:09:59 0xc2080ec078 /api/v1/result/12/detail
2015/06/18 15:09:59 0xc208120020 /api/v1/result/10/detail
2015/06/18 15:09:59 0xc208030038 /api/v1/result/2/detail
2015/06/18 15:09:59 0xc208030040 /api/v1/result/3/detail
2015/06/18 15:09:59 0xc208120058 /api/v1/result/4/detail
2015/06/18 15:09:59 0xc208120068 /api/v1/result/5/detail
2015/06/18 15:09:59 0xc2080ec0a0 /api/v1/result/6/detail
2015/06/18 15:09:59 0xc208030060 /api/v1/result/7/detail
2015/06/18 15:09:59 0xc208120080 /api/v1/result/8/detail
2015/06/18 15:09:59 0xc2080ec0d8 /api/v1/result/9/detail
2015/06/18 15:10:00 0xc2081200a0 /api/v1/test/3/results
2015/06/18 15:10:00 0xc20816c010 /api/v1/test/3/inputs
2015/06/18 15:10:00 0xc208030020 /api/v1/test/4/results
2015/06/18 15:10:00 0xc208030048 /api/v1/test/2/results
2015/06/18 15:10:00 0xc208030040 /api/v1/test/4/inputs
2015/06/18 15:10:00 0xc208030058 /api/v1/test/2/inputs
2015/06/18 15:10:00 0xc2080ec028 /api/v1/test/5/inputs
2015/06/18 15:10:00 0xc208120038 /api/v1/test/5/results
2015/06/18 15:10:00 http: panic serving 127.0.0.1:52703: assignment to entry in nil map
goroutine 98 [running]:
net/http.func·011()
        /home/ian/go/src/net/http/server.go:1130 +0xbb
github.com/go-zoo/bone.(*Route).Match(0xc20808d9a0, 0xc2081581a0, 0xc208152900)
        /home/ian/code/tester/src/github.com/go-zoo/bone/route.go:102 +0x523
github.com/go-zoo/bone.(*Mux).ServeHTTP(0xc2080c2ca0, 0x7f1d53fa5860, 0xc20807c5a0, 0xc2081581a0)
        /home/ian/code/tester/src/github.com/go-zoo/bone/bone.go:55 +0x5ec
net/http.serverHandler.ServeHTTP(0xc20808ecc0, 0x7f1d53fa5860, 0xc20807c5a0, 0xc2081581a0)
        /home/ian/go/src/net/http/server.go:1703 +0x19a
net/http.(*conn).serve(0xc2080b2460)
        /home/ian/go/src/net/http/server.go:1204 +0xb57
created by net/http.(*Server).Serve
        /home/ian/go/src/net/http/server.go:1751 +0x35e
2015/06/18 15:10:00 0xc208030068 /api/v1/test/6/results
2015/06/18 15:10:01 0xc208120060 /api/v1/test/1/results
2015/06/18 15:10:01 0xc20816c040 /api/v1/test/1/inputs
2015/06/18 15:10:01 0xc208120038 /api/v1/test/7/results
2015/06/18 15:10:01 0xc208120050 /api/v1/test/7/inputs
2015/06/18 15:10:01 0xc208030030 /api/v1/test/8/results
2015/06/18 15:10:01 0xc208030048 /api/v1/test/8/inputs
2015/06/18 15:10:01 0xc208030068 /api/v1/test/9/results
2015/06/18 15:10:01 0xc208030078 /api/v1/test/10/results
2015/06/18 15:10:01 0xc208120088 /api/v1/test/9/inputs
2015/06/18 15:10:01 0xc2081200a8 /api/v1/test/11/results
2015/06/18 15:10:01 0xc2080300a0 /api/v1/test/11/inputs
2015/06/18 15:10:01 0xc2081200c0 /api/v1/test/12/results
2015/06/18 15:10:01 0xc2080300b0 /api/v1/test/12/inputs
2015/06/18 15:10:01 0xc2080ec008 /api/v1/test/10/inputs
2015/06/18 15:10:01 0xc2080300b8 /api/v1/test/13/results
2015/06/18 15:10:01 0xc208030020 /api/v1/result/13/detail
2015/06/18 15:10:01 0xc20816c020 /api/v1/test/13/inputs
2015/06/18 15:10:01 0xc208030048 /api/v1/test/14/inputs
2015/06/18 15:10:01 0xc208030058 /api/v1/result/14/detail
2015/06/18 15:10:01 0xc2080ec010 /api/v1/test/14/results
2015/06/18 15:10:01 0xc208120030 /api/v1/result/15/detail
2015/06/18 15:10:01 0xc20816c008 /api/v1/result/11/detail
2015/06/18 15:10:01 0xc20816c040 /api/v1/result/12/detail
2015/06/18 15:10:01 0xc20816c048 /api/v1/result/2/detail
2015/06/18 15:10:01 0xc20816c060 /api/v1/result/3/detail
2015/06/18 15:10:01 0xc208120050 /api/v1/result/4/detail
2015/06/18 15:10:01 0xc208120068 /api/v1/result/5/detail
2015/06/18 15:10:01 0xc20816c078 /api/v1/result/6/detail
2015/06/18 15:10:01 0xc20816c090 /api/v1/result/7/detail
2015/06/18 15:10:01 0xc20816c0b8 /api/v1/result/8/detail
2015/06/18 15:10:01 0xc2080ec020 /api/v1/result/9/detail
2015/06/18 15:10:01 0xc208120000 /api/v1/result/10/detail

case insensitive urls

Is there any support for using case insensitive urls?

Say I have a page at http://test.com/promo/ and the user types http://test.com/Promo/ I would like it to still match.

Sorry if there is a feature I am missing that allows for this.

Mutliple resposne:WriteHeader calls.

Using this code:

package main

import (
    "net/http"

    "github.com/go-zoo/bone"
)

func idex(w http.ResponseWriter, r *http.Request) {
    w.Header().Set("Content-Type", "application/vnd.api+json")
    w.Write([]byte("This is the index page!\n"))
}

func main() {
    mux := bone.New()
    mux.Get("/", http.HandlerFunc(idex))
    http.ListenAndServe(":8080", mux)
}

This is the output of a curl call:

> curl -I localhost:8080//
HTTP/1.1 302 Found
Location: /
Date: Thu, 08 Oct 2015 08:05:28 GMT
Content-Length: 19
Content-Type: text/plain; charset=utf-8

The problem here is that the Content-Type can't be set. The go application prints out:

2015/10/ 08 10:05:28 http: multiple response.WriteHeader calls

After googling this for a little it seems that once you have written to the header once, later writes will
not work. The code above works using the default mux. Quickly searching through the codebase hints that this part:

bone/helper.go

Lines 67 to 68 in e63596f

rw.Header().Set("Location", req.URL.Path)
rw.WriteHeader(http.StatusFound)

Might be the problem. I hope that I have included enough information to reproduce.

panic when trying to handle semi weird paths

Let's say you have the following code:

mux = bone.New()
mux.Get("/cars/?", AllCarsHandler)
mux.Get("/cars/:id", SingleCarHandler)
http.ListenAndServer(":80", mux)

When a request is made, it panics with:

2015/10/04 02:54:07 Listening on port 80
2015/10/04 02:54:08 http: panic serving 172.17.42.1:48718: runtime error: index out of range
goroutine 5 [running]:
net/http.(*conn).serve.func1(0xc820098000, 0x7f7e044ac678, 0xc820028040)
    /usr/local/go/src/net/http/server.go:1287 +0xb5
github.com/go-zoo/bone.(*Route).Match(0xc82008c320, 0xc82009c000, 0xc82000a700)
    /go/src/github.com/go-zoo/bone/route.go:104 +0x4d0
github.com/go-zoo/bone.(*Mux).parse(0xc82000ce70, 0x7f7e044ac7f8, 0xc8200980b0, 0xc82009c000, 0x0)
    /go/src/github.com/go-zoo/bone/helper.go:29 +0x31d
github.com/go-zoo/bone.(*Mux).ServeHTTP(0xc82000ce70, 0x7f7e044ac7f8, 0xc8200980b0, 0xc82009c000)
    /go/src/github.com/go-zoo/bone/bone.go:47 +0x43
net/http.serverHandler.ServeHTTP(0xc8200121e0, 0x7f7e044ac7f8, 0xc8200980b0, 0xc82009c000)
    /usr/local/go/src/net/http/server.go:1862 +0x19e
net/http.(*conn).serve(0xc820098000)
    /usr/local/go/src/net/http/server.go:1361 +0xbee
created by net/http.(*Server).Serve
    /usr/local/go/src/net/http/server.go:1910 +0x3f6
^Cexit status 2

Whether or not you want to support optional trailing slashes, it seems like it should not panic on request.

Consider tagging semver releases

Hey there 👋, it would be awesome if you could tag semantic versioned releases like v1.3.0 to allow other go projects to depend on bone via that version. Unfortunately go modules only support semver tags. :) WDYT?

Cookies dont have domain and path info

When I was using Gorrila Mux a cookie would get the correct path and domain information when I used http.SetCookie(w, cookie)

Swapping to bone I get

image

Let me know if you need more info

Typo

Hi,

just a small thing:

In the README is a typo:

 // Support REGEX Route params
  mux.Get("/index/#id^[0-9]$", http.HandleFunc(IndexHandler))

->

 // Support REGEX Route params
  mux.Get("/index/#id^[0-9]$", http.HandlerFunc(IndexHandler))

Problem in setting Route.Atts bitflag

In route.go the (Route *)save method seems to have a problem in the way the r.Atts variable is set; += operators are used in stead of |= operators. This will cause an issue when for example there are 4 parameters set in the routing path. Using r.Atts +=PARAM will eventually set r.Atts flagged with the WC bit set therefore ignoring the rest of the request when matched against that particular routing path.

Please let me know if you want to receive a PR.

Are sub-routers or router-groups possible?

Like for instance the following:

subRouter := bone.New()
subRouter.GetFunc("/getNames", GetUserNamesControllerFunc)
subRouter.GetFunc("/getEmail", GetUserEmailControllerFunc)

router.Handle("/user", subRouter)

I would like this code to handle the /user/getNames and /user/getEmail urls but it does not work. Is this functionality supported?

/api/home/ with trail slash should be not found

package main

import (
	"encoding/json"
	"fmt"
	"log"
	"net/http"
	"time"

	"github.com/go-zoo/bone"
)

var (
	mux = bone.New(Serve, Wrap)
)

func Wrap(mux *bone.Mux) *bone.Mux {
	return mux.Prefix("/api")
}

func Serve(mux *bone.Mux) *bone.Mux {
	mux.Serve = func(rw http.ResponseWriter, req *http.Request) {
		tr := time.Now()
		mux.DefaultServe(rw, req)
		fmt.Println("Serve request from", req.RemoteAddr, "in", time.Since(tr))
	}
	return mux
}

func main() {
	// Custom 404
	mux.NotFoundFunc(Handler404)
	// Handle with any http method, Handle takes http.Handler as argument.
	mux.Handle("/index", http.HandlerFunc(homeHandler))
	mux.Handle("/index/:var/info/:test", http.HandlerFunc(varHandler))
	// Get, Post etc... takes http.HandlerFunc as argument.
	mux.Post("/home", http.HandlerFunc(homeHandler))
	mux.Get("/home/:var", http.HandlerFunc(varHandler))

	mux.GetFunc("/test/*", func(rw http.ResponseWriter, req *http.Request) {
		rw.Write([]byte(req.RequestURI))
	})

	// Start Listening
	log.Fatal(mux.ListenAndServe(":8080"))
}

func homeHandler(rw http.ResponseWriter, req *http.Request) {
	rw.Write([]byte("WELCOME HOME"))
}

func varHandler(rw http.ResponseWriter, req *http.Request) {
	varr := bone.GetValue(req, "var")
	test := bone.GetValue(req, "test")

	var args = struct {
		First  string
		Second string
	}{varr, test}

	if err := json.NewEncoder(rw).Encode(&args); err != nil {
		panic(err)
	}
}

func Handler404(rw http.ResponseWriter, req *http.Request) {
	rw.Write([]byte("These are not the droids you're looking for ..."))
}

visist http://localhost:8080/api/home/xxx
{"First":"xxx","Second":""}
visit http://localhost:8080/api/home/
{"First":"","Second":""}

Automatic 404 in custom NotFoundFunc

Bone internally sets a 404 code before running the NotFoundFunc.
This causes problems in 2 ways.

  1. I can't use a generic error handler because I need to avoid setting the response code.
  2. What if I want to do my own special handling that might not result in a 404?

Support more than one path variable

It would be useful if we could define multiple path variables, such as /bands/:band/musicians/:musician. However the bone router only works with exactly one variable. The following test does't pass as it would on zeus or gorilla, two of the other routers referred to in the bone README:

func TestMultipleRoutingVariables(t *testing.T) {
    var (
        expected1 = "variable1"
        expected2 = "variable2"
        got1      string
        got2      string
        mux       = New()
        w         = httptest.NewRecorder()
    )
    mux.Get("/:var1/:var2", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        got1 = GetValue(r, "var1")
        got2 = GetValue(r, "var2")
    }))

    r, err := http.NewRequest("GET", fmt.Sprintf("/%s/%s", expected1, expected2), nil)
    if err != nil {
        t.Fatal(err)
    }
    mux.ServeHTTP(w, r)

    if got1 != expected1 {
        t.Fatalf("expected %s, got %s", expected1, got1)
    }

    if got2 != expected2 {
        t.Fatalf("expected %s, got %s", expected2, got2)
    }
}

Include Allow header with 405 response

When bone returns a 405 Method Not Allowed response, it would be good if it could include an Allow header detailing which methods are permitted.

I think it could perhaps be done by amending the otherMethods helper. Something like:

func (m *Mux) otherMethods(rw http.ResponseWriter, req *http.Request) bool {
	allowed := []string{}
	for _, met := range method {
		if met != req.Method {
			for _, r := range m.Routes[met] {
				ok := r.exists(rw, req)
				if ok {
					allowed = append(allowed, r.Method)
				}
			}
		}
	}
	if len(allowed) > 0 {
		rw.Header()["Allow"] = allowed
		rw.WriteHeader(http.StatusMethodNotAllowed)
		return true
	}
	return false
}

Also, what are your thoughts on including a plain text "Method Not Allowed" message in the response body, similar to the "404 page not allowed" body for 404s?

Unable to serve static files (css, js , html)

Hi,

I think i am not able to find documentation for serving static files, I am new to golang and mux , i am done with setup but now my static file server is not working

fs := http.FileServer(http.Dir("./views"))
	http.Handle("/static/", http.StripPrefix("/static/", fs))

Requests are handled by mux.NotFound route.

Need Help!, Thanks in advance.

Query string not working in nested routers

I have a sub route like:

subRouter.GetFunc("*/users", ...)
mainRouter.Get("/app/*", subRouter)

This matches /app/users, but I can't figure out how to match the same path with an added query string. e.g. /app/users?active=true or /app/users?foo=1&bar=3

I just get 404s. When I use a query string in the main router it works, but somehow a sub router fails. Any clues?

Subrouter path issue

     mux := bone.New()

    sub := bone.New()

    sub.GetFunc("/test/example", func(rw http.ResponseWriter, req *http.Request) {
        rw.Write([]byte("From Sub router !"))
    })

    mux.Get("/api", sub)

This is example from Readme, and it doesn't work. But example 003 in examples folder, works. Only difference is the path of the subrouter. If subrouter has more than 1 hardcoded pathsegments, it doesn't work. Example - "/test/example" Doesn't work. Whereas this - "/user/:id" works.

getRequestRoute for subroutes

Using getRequestRoute for sub routes isn't working properly. Let's assume I have the following setup:

func Main() {
    mux := bone.New()
    mux.SubRoute("/v0", apiMux)
    http.ListenAndServe("127.0.0.1:3000", mux)
}

apiMux have the following endpoints registered:

apiMux.Post("/users", usersHandler)
apiMux.Post("/posts", postsHandler)

Doing a request to /users will generate a http.Request with an URL equal to /v0/users. Calling getRequestRoute(req) returns /v0. I'd assume it returns /v0/users or /users.

Is this a bug? If so, how do we want to fix it? I'd be happy to help in any way possible.

Catch all route

There doesn't seem to be a way to catch all routes, eg: mux.Get("/users/*", handler). I've tried using a regexp too, but it only matches till the next /. Any plans to implement it?

NewRouter() undefined for mux type

Hey there, first off, awesome router.

I'm currently trying to add a route prefix (SubRoute as in your example), and I'm getting an error saying that the Mux type doesn't have a NewRouter() function.

Here's the specific error text after compiling the SubRoute example on the README:

mux.NewRouter undefined (type *bone.Mux has no field or method NewRouter)

I've checked through the source code and it seems it's correct. NewRouter isn't defined for the Mux type, and so route prefixes aren't possible at the moment. I'll look into implementing it myself, do you accept pull requests?

New release 1.2.1 shouldn't have been called a patch

Hi. Thanks for working on this.

The previous release was over two years ago, and some changes were made in the intervening time to insert a QueryUnescape call in for parameters.

When we upgraded to the latest release, it broke some things. Can I suggest that you delete 1.2.1 and rename it to 1.3 to save other people from this?

Method is not set on individual routes

I have a mux with some defined handlers. I want to print out all defined routes as follows:

POST /endpoint1
PUT  /endpoint2
GET  /endpoint3

If I iterate over mux.Routes all defined Routes have their method set to "". I'd expect the field Method to be set when the route was defined using PostFunc, GetFunc and so on.

Am I missing something? How can I programatically check what verb is associated with what route?

Cheers!

Issue with bone.GetVars()

Just a quick thought.

Example:

runtime.GOMAXPROCS(2)
mux.Get("/home/:id", Handler)

And as http.ListenAndServe() emits each client in the separate goroutine,
it might happen that two clients access /home/1 and /home/2 at the same time.

According to the variant of the GetValue() as a global var , it I'm not sure that both clients will get the correct bone.GetValue("id").

Panic running example 001

I got panic running example code:

% go run 001/example.go -race

2015/10/03 20:58:39 http: panic serving [::1]:45814: runtime error: invalid memory address or nil pointer dereference
goroutine 182 [running]:
net/http.(*conn).serve.func1(0xc8201786e0, 0x7f33df087650, 0xc820080398)
        /usr/lib/go/src/net/http/server.go:1287 +0xb5
github.com/go-zoo/bone.(*Route).Match(0xc8200b0c80, 0xc820171880, 0xc820083a00)
        /tmp/b/src/github.com/go-zoo/bone/route.go:101 +0x28f
github.com/go-zoo/bone.(*Mux).parse(0xc820076cf0, 0x7f33df0877d0, 0xc820178790, 0xc820171880, 0x0)
        /tmp/b/src/github.com/go-zoo/bone/helper.go:29 +0x31d
github.com/go-zoo/bone.(*Mux).ServeHTTP(0xc820076cf0, 0x7f33df0877d0, 0xc820178790, 0xc820171880)
        /tmp/b/src/github.com/go-zoo/bone/bone.go:49 +0x43
net/http.serverHandler.ServeHTTP(0xc8200700c0, 0x7f33df0877d0, 0xc820178790, 0xc820171880)
        /usr/lib/go/src/net/http/server.go:1862 +0x19e
net/http.(*conn).serve(0xc8201786e0)
        /usr/lib/go/src/net/http/server.go:1361 +0xbee
created by net/http.(*Server).Serve
        /usr/lib/go/src/net/http/server.go:1910 +0x3f6

tested with curl:

% (repeat 100 {curl localhost:8080/home/foo & })

Any plans to remove handler wrapper?

Hi.

First off I really like the look of this.

Secondly, do you have any plans to make the router like so:

mux.Get("/home/:id", HomeHandler)

instead of

mux.Get("/home/:id", http.HandlerFunc(HomeHandler))

go1.7: using http.Request.WithContext breaks bone GetValues

If you use the go1.7 contexts in the http lifecycle sometime after bone has routed your request, but before the application specific routes are run, then bone is unable to find the values from the request.

There are a few workarounds, but given how common it will be for new go users to build this pattern, I think it would be helpful to enable this use case without too many "WTF's". The changes are fairly simple I think - probably require storing the bone values in the request's context, and I am happy to help make this change. I just wanted to get the OK from a project maintainer before proceeding to code anything.

func (r AuthedRoute) ServeHTTP(w http.ResponseWriter, req *http.Request) {
    user := r.AuthedUser()
    ctx := context.WithValue(req.Context(), authKey, user)

    // adding this line this breaks bone values, since it uses the *http.Request as the key 
    req = req.WithContext(ctx)
    needsBoneHandler(w, req)
}

func needsBoneHandler(w http.ResponseWriter, req *http.Request) {
    boneVals := bone.GetAllValues(req)
    // is empty :(
}

Concurrency issue in route.go

Hi,
There is a concurrency issue in route.go:104

at:
for k, v := range r.Pattern {
vars.v[req][v] = ss[k]
}

vars should have a mutex lock enabled before getting ss[k].
I'll see if I have time to create a pull request.

  • Eelco

Concurrent map read and map write under Go 1.6.0

Since Go 1.6.0 and the concurrent acces detector, my app crashes under heavy load:

fatal error: concurrent map read and map write

at github.com/go-zoo/bone/route.go:98

Does anybody else is experiencing the same issue ?

404 Error instead of 405 Status Code

mux := bone.New()
mux.Get("/test/", http.HandlerFunc(myHandler))

If I make requests to /test/ endpoint with POST method then I get 404 Not Found error instead of 405 Method Not Allowed.

Probable reason:
map[string][]*Route the key in this map is method name (e.g., GET, POST, etc..) and the requested endpoint is searched in the slice of the requested method, and if the endpoint is not found then 404 is returned.

Proposed Solution:

  1. Search all Method's slices. (too costly operation)
    OR
  2. Register routes with the different way.

Static files browser caching

Just running a site in production through google page speed insights and getting expiration not specified errors for static files. Is there a way in bone to specify

Setting an expiry date or a maximum age in the HTTP headers for static resources instructs the browser to load previously downloaded resources from local disk rather than over the network.

Code in question is:

	r.Mux.Handle("/public/", http.StripPrefix("/public/", http.FileServer(http.Dir("./public/"))))
	r.Mux.Handle("/attachments/", http.StripPrefix("/attachments/", http.FileServer(http.Dir("./attachments/"))))

As I write this I am starting to think its not an issue with bone, but I am still unsure of what to do. Any help / point to a feature I should be using would be hugely appreciated.

More comprehensive benchmarks.

Your benchmarks are comparing the fetching of a single url - This is a misleading benchmark which is heavily biased towards bone because of its simple algorithm.

Please add some benchmarks where the number of routes is medium and large with varying degrees of shared prefixes.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.