Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(366)

Side by Side Diff: server/router/router.go

Issue 2043423004: Make HTTP middleware easier to use (Closed) Base URL: https://github.com/luci/luci-go@master
Patch Set: router: Do not allocate merged array in Handle Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2016 The LUCI Authors. All rights reserved.
2 // Use of this source code is governed under the Apache License, Version 2.0
3 // that can be found in the LICENSE file.
4
5 package router
6
7 import (
8 "net/http"
9
10 "github.com/julienschmidt/httprouter"
11 "golang.org/x/net/context"
12 )
13
14 type (
15 // Router is the main type for the package. To create a Router, use New.
16 Router struct {
17 hrouter *httprouter.Router
18 middleware MiddlewareChain
19 BasePath string
20 parent *Router
nodir 2016/06/15 20:14:43 why do you need parent? is not used and seems unne
nishanths 2016/06/16 00:14:18 Done. Remnants of old stuff I was trying, thanks f
21 }
22
23 // Context contains the context, response writer, request, and params sh ared
24 // across Middleware and Handler functions.
25 Context struct {
26 context.Context
27 writer http.ResponseWriter
28 Request *http.Request
29 Params httprouter.Params
30 status int
31 }
32 )
33
34 var (
35 _ http.Handler = (*Router)(nil)
36 _ http.ResponseWriter = (*Context)(nil)
37 _ context.Context = (*Context)(nil)
38 )
39
40 // New creates a Router.
41 func New() *Router {
42 return &Router{
43 hrouter: httprouter.New(),
44 BasePath: "/",
45 }
46 }
47
48 // Use adds middleware chains to the group. The added middleware applies to
49 // all handlers registered on the router and to all handlers handlers registered on
nodir 2016/06/15 20:14:43 s/handlers handlers/handlers/
nishanths 2016/06/16 00:14:18 Done.
50 // routers derived from the router (using Group).
nodir 2016/06/15 20:14:44 s/derived/that will be derived/ because Group copi
nishanths 2016/06/16 00:14:19 Done.
51 func (r *Router) Use(mc MiddlewareChain) {
nodir 2016/06/15 20:14:43 consider `...Middleware`
nishanths 2016/06/16 00:14:18 +1 Will reconsider while refactoring the rest of t
52 r.middleware = append(r.middleware, mc...)
53 }
54
55 // Group creates a new router with an updated base path.
56 // The new router carries over configuration from the router it derives
57 // from.
58 func (r *Router) Group(relativePath string) *Router {
59 newRouter := &Router{
60 hrouter: r.hrouter,
61 BasePath: httprouter.CleanPath(r.BasePath + relativePath),
nodir 2016/06/15 20:14:44 this line assumes that BasePath ends with "/" at t
nishanths 2016/06/16 00:14:18 Fixed now. See the makeBasePath function. I'm stil
62 parent: r,
63 }
64 if len(r.middleware) > 0 {
65 newRouter.middleware = make(MiddlewareChain, len(r.middleware))
66 copy(newRouter.middleware, r.middleware)
67 }
68 return newRouter
69 }
70
71 // GET is a shortcut for router.Handle("GET", mc, h)
72 func (r *Router) GET(path string, mc MiddlewareChain, h Handler) {
73 r.Handle("GET", path, mc, h)
74 }
75
76 // HEAD is a shortcut for router.Handle("HEAD", mc, h)
77 func (r *Router) HEAD(path string, mc MiddlewareChain, h Handler) {
78 r.Handle("HEAD", path, mc, h)
79 }
80
81 // OPTIONS is a shortcut for router.Handle("OPTIONS", mc, h)
82 func (r *Router) OPTIONS(path string, mc MiddlewareChain, h Handler) {
83 r.Handle("OPTIONS", path, mc, h)
84 }
85
86 // POST is a shortcut for router.Handle("POST", mc, h)
87 func (r *Router) POST(path string, mc MiddlewareChain, h Handler) {
88 r.Handle("POST", path, mc, h)
89 }
90
91 // PUT is a shortcut for router.Handle("PUT", mc, h)
92 func (r *Router) PUT(path string, mc MiddlewareChain, h Handler) {
93 r.Handle("PUT", path, mc, h)
94 }
95
96 // PATCH is a shortcut for router.Handle("PATCH", mc, h)
97 func (r *Router) PATCH(path string, mc MiddlewareChain, h Handler) {
98 r.Handle("PATCH", path, mc, h)
99 }
100
101 // DELETE is a shortcut for router.Handle("DELETE", mc, h)
102 func (r *Router) DELETE(path string, mc MiddlewareChain, h Handler) {
103 r.Handle("DELETE", path, mc, h)
104 }
105
106 // Handle registers a middleware chain and a handler for the given method and
107 // path. len(mc)==0 is allowed.
108 func (r *Router) Handle(method, path string, mc MiddlewareChain, h Handler) {
109 handle := r.adapt(mc, h)
110 r.hrouter.Handle(method, httprouter.CleanPath(r.BasePath+path), handle)
111 }
112
113 // ServeHTTP makes Router implement the http.Handler interface.
114 func (r *Router) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
115 r.hrouter.ServeHTTP(rw, req)
116 }
117
118 // adapt adapts given middleware chain and handler into a httprouter-style handl e.
119 func (r *Router) adapt(mc MiddlewareChain, h Handler) httprouter.Handle {
120 return httprouter.Handle(func(rw http.ResponseWriter, req *http.Request, p httprouter.Params) {
121 // TODO(maybe): Use a free list for making Contexts.
122 run(NewContext(context.Background(), rw, req, p), r.middleware, mc, h)
123 })
124 }
125
126 // NewContext creates a Context that with the given parameters.
nodir 2016/06/15 20:14:43 s/that //
nishanths 2016/06/16 00:14:18 Done.
127 func NewContext(c context.Context, rw http.ResponseWriter, req *http.Request, p httprouter.Params) *Context {
128 return &Context{
129 Context: c,
130 writer: rw,
131 Request: req,
132 Params: p,
133 }
134 }
135
136 // Header is used to implement http.ResponseWriter interface on Context.
nodir 2016/06/15 20:14:43 s/ on Context//g
nishanths 2016/06/16 00:14:18 Done.
137 func (c *Context) Header() http.Header {
138 return c.writer.Header()
139 }
140
141 // Write is used to implement http.ResponseWriter interface on Context.
142 // If called from a Middleware function, the rules mentioned in the
143 // documentation for Middleware must be followed.
144 func (c *Context) Write(p []byte) (int, error) {
145 c.status = http.StatusOK
nodir 2016/06/15 20:14:44 do it only if c.status == 0
nishanths 2016/06/16 00:14:18 Done.
146 return c.writer.Write(p)
147 }
148
149 // WriteHeader is used to implement http.ResponseWriter interface on Context.
150 // If called from a Middleware function, the rules mentioned in the
151 // documentation for Middleware must be followed.
152 func (c *Context) WriteHeader(code int) {
153 c.status = code
nodir 2016/06/15 20:14:44 do it only if c.status == 0
nishanths 2016/06/16 00:14:18 Done.
154 c.writer.WriteHeader(code)
155 }
156
157 // StatusCode returns the written HTTP status code.
nodir 2016/06/15 20:14:43 " or 0 if it was not written"
nishanths 2016/06/16 00:14:18 Done.
158 func (c *Context) StatusCode() int {
159 return c.status
160 }
161
162 // Written indicates whether a HTTP response has been written.
163 func (c *Context) Written() bool {
164 return c.status != 0
165 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698