Skip to content

Commit

Permalink
Rebase upstream commits
Browse files Browse the repository at this point in the history
  • Loading branch information
buaazp committed Feb 14, 2016
1 parent 054b54e commit 2ddeed1
Show file tree
Hide file tree
Showing 2 changed files with 140 additions and 192 deletions.
51 changes: 5 additions & 46 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# FastHttpRouter
[![Build Status](https://travis-ci.org/buaazp/fasthttprouter.png?branch=master)](https://travis-ci.org/buaazp/fasthttprouter) [![Coverage Status](https://coveralls.io/repos/buaazp/fasthttprouter/badge.svg?branch=master&service=github)](https://coveralls.io/github/buaazp/fasthttprouter?branch=master) [![GoDoc](http://godoc.org/github.com/buaazp/fasthttprouter?status.png)](http://godoc.org/github.com/buaazp/fasthttprouter)
[![Build Status](https://travis-ci.org/buaazp/fasthttprouter.png?branch=master)](https://travis-ci.org/buaazp/fasthttprouter)
[![Coverage Status](https://coveralls.io/repos/buaazp/fasthttprouter/badge.svg?branch=master&service=github)](https://coveralls.io/github/buaazp/fasthttprouter?branch=master)
[![GoDoc](http://godoc.org/github.com/buaazp/fasthttprouter?status.png)](http://godoc.org/github.com/buaazp/fasthttprouter)

FastHttpRouter is forked from [httprouter](https://github.com/julienschmidt/httprouter) which is a lightweight high performance HTTP request router
(also called *multiplexer* or just *mux* for short) for [fasthttp](https://github.com/valyala/fasthttp).
Expand Down Expand Up @@ -86,15 +88,8 @@ func main() {
```

### Named parameters
<<<<<<< ef4f6943f50f34ccda187f9eddb931ce10e1d74e

As you can see, `:name` is a *named parameter*. The values are accessible via `httprouter.Params`, which is just a slice of `httprouter.Param`s. You can get the value of a parameter either by its index in the slice, or by using the `ByName(name)` method: `:name` can be retrived by `ByName("name")`.
=======
As you can see, `:name` is a *named parameter*.
The values are accessible via `fasthttprouter.Params`, which is just a slice of `fasthttprouter.Param`s.
You can get the value of a parameter either by its index in the slice, or by using the `ByName(name)` method:
`:name` can be retrived by `ByName("name")`.
>>>>>>> Update docs

Named parameters only match a single path segment:

Expand Down Expand Up @@ -162,18 +157,11 @@ For even better scalability, the child nodes on each tree level are ordered by p

## Why doesn't this work with `http.Handler`?

<<<<<<< ef4f6943f50f34ccda187f9eddb931ce10e1d74e
Becasue fasthttp doesn't provide http.Handler. See this [description](https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp).

Fasthttp works with [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler) functions instead of objects implementing Handler interface. So a FastHttpRouter provides a [Handler](https://godoc.org/github.com/buaazp/fasthttprouter#Router.Handler) interface to implement the fasthttp.ListenAndServe interface.
=======
## Why doesn't this work with http.Handler?
Becasue fasthttp doesn't provide http.Handler. See this [description](https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp).

Fasthttp works with [RequestHandler](https://godoc.org/github.com/valyala/fasthttp#RequestHandler) functions instead of objects implementing Handler interface. So a FastHttpRouter provides a [Handler](https://godoc.org/github.com/buaazp/fasthttprouter#Router.Handler) interface to implement the fasthttp.ListenAndServe interface.

Just try it out for yourself, the usage of FastHttpRouter is very straightforward. The package is compact and minimalistic, but also probably one of the easiest routers to set up.
>>>>>>> Update docs

Just try it out for yourself, the usage of FastHttpRouter is very straightforward. The package is compact and minimalistic, but also probably one of the easiest routers to set up.

Expand Down Expand Up @@ -302,37 +290,8 @@ router.NotFound = fasthttp.FSHandler("./public", 0)

But this approach sidesteps the strict core rules of this router to avoid routing problems. A cleaner approach is to use a distinct sub-path for serving files, like `/static/*filepath` or `/files/*filepath`.

<<<<<<< ef4f6943f50f34ccda187f9eddb931ce10e1d74e
## Web Frameworks based on HttpRouter
## Web Frameworks based on FastHttpRouter

If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package:

* [Ace](https://github.com/plimble/ace): Blazing fast Go Web Framework
* [api2go](https://github.com/manyminds/api2go): A JSON API Implementation for Go
* [Gin](https://github.com/gin-gonic/gin): Features a martini-like API with much better performance
* [Goat](https://github.com/bahlo/goat): A minimalistic REST API server in Go
* [Hikaru](https://github.com/najeira/hikaru): Supports standalone and Google AppEngine
* [Hitch](https://github.com/nbio/hitch): Hitch ties httprouter, [httpcontext](https://github.com/nbio/httpcontext), and middleware up in a bow
* [httpway](https://github.com/corneldamian/httpway): Simple middleware extension with context for httprouter and a server with gracefully shutdown support
* [kami](https://github.com/guregu/kami): A tiny web framework using x/net/context
* [Medeina](https://github.com/imdario/medeina): Inspired by Ruby's Roda and Cuba
* [Neko](https://github.com/rocwong/neko): A lightweight web application framework for Golang
* [Roxanna](https://github.com/iamthemuffinman/Roxanna): An amalgamation of httprouter, better logging, and hot reload
* [siesta](https://github.com/VividCortex/siesta): Composable HTTP handlers with contexts
* [xmux](https://github.com/rs/xmux): xmux is a httprouter fork on top of xhandler (net/context aware)

[benchmark]: <https://github.com/julienschmidt/go-http-routing-benchmark>
[http.Handler]: <https://golang.org/pkg/net/http/#Handler
[http.ServeMux]: <https://golang.org/pkg/net/http/#ServeMux>
[Router.Handle]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.Handle>
[Router.HandleMethodNotAllowed]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.HandleMethodNotAllowed>
[Router.Handler]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.Handler>
[Router.HandlerFunc]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.HandlerFunc>
[Router.NotFound]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.NotFound>
[Router.PanicHandler]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.PanicHandler>
[Router.ServeFiles]: <https://godoc.org/github.com/julienschmidt/httprouter#Router.ServeFiles>
=======
## Web Frameworks based on FastHttpRouter
If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package:
* Waiting for you to do this...
>>>>>>> Update docs
- Waiting for you to do this...
281 changes: 135 additions & 146 deletions router_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,165 +343,132 @@ func TestRouterOPTIONS(t *testing.T) {
rw := &readWriter{}
ch := make(chan error)

/*
rw.r.WriteString("OPTIONS * HTTP/1.1\r\nHost:\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
br := bufio.NewReader(&rw.w)
var resp fasthttp.Response
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST" {
t.Error("unexpected Allow header value: " + allow)
rw.r.WriteString("OPTIONS * HTTP/1.1\r\nHost:\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
br := bufio.NewReader(&rw.w)
var resp fasthttp.Response
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST" {
t.Error("unexpected Allow header value: " + allow)
}

// path
rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST" {
t.Error("unexpected Allow header value: " + allow)
// path
rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST" {
t.Error("unexpected Allow header value: " + allow)
}

rw.r.WriteString("OPTIONS /doesnotexist HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if !(resp.Header.StatusCode() == fasthttp.StatusNotFound) {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
rw.r.WriteString("OPTIONS /doesnotexist HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if !(resp.Header.StatusCode() == fasthttp.StatusNotFound) {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
}

// add another method
router.GET("/path", handlerFunc)
// test again
// * (server)
rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
}
// add another method
router.GET("/path", handlerFunc)

// path
rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
// test again
// * (server)
rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
}

// custom handler
var custom bool
router.OPTIONS("/path", func(_ *fasthttp.RequestCtx, _ Params) {
custom = true
})
// test again
// * (server)
rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
}
if custom {
t.Error("custom handler called on *")
// path
rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
*/
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
}

// path
// custom handler
var custom bool
router.OPTIONS("/path", func(_ *fasthttp.RequestCtx, _ Params) {
custom = true
})

rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
// test again
// * (server)
rw.r.WriteString("OPTIONS * HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
Expand All @@ -513,10 +480,32 @@ func TestRouterOPTIONS(t *testing.T) {
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
if resp.Header.StatusCode() != fasthttp.StatusOK {
t.Errorf("OPTIONS handling failed: Code=%d, Header=%v",
resp.Header.StatusCode(), resp.Header.String())
} else if allow := string(resp.Header.Peek("Allow")); allow != "POST, GET" && allow != "GET, POST" {
t.Error("unexpected Allow header value: " + allow)
}
if custom {
t.Error("custom handler called on *")
}

br := bufio.NewReader(&rw.w)
var resp fasthttp.Response

// path
rw.r.WriteString("OPTIONS /path HTTP/1.1\r\n\r\n")
go func() {
ch <- s.ServeConn(rw)
}()
select {
case err := <-ch:
if err != nil {
t.Fatalf("return error %s", err)
}
case <-time.After(100 * time.Millisecond):
t.Fatalf("timeout")
}
if err := resp.Read(br); err != nil {
t.Fatalf("Unexpected error when reading response: %s", err)
}
Expand Down

0 comments on commit 2ddeed1

Please sign in to comment.