Skip to content

Commit d49d84e

Browse files
Dean KarnDean Karn
authored andcommitted
Merge branch 'minor-additions-and-improvements'
2 parents f331ac5 + 2c9b857 commit d49d84e

File tree

5 files changed

+127
-64
lines changed

5 files changed

+127
-64
lines changed

README.md

Lines changed: 25 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
##Pure
22
<img align="right" src="https://raw.githubusercontent.com/go-playground/pure/master/logo.png">
3-
![Project status](https://img.shields.io/badge/version-3.0.1-green.svg)
3+
![Project status](https://img.shields.io/badge/version-3.1.0-green.svg)
44
[![Build Status](https://semaphoreci.com/api/v1/joeybloggs/pure/branches/master/badge.svg)](https://semaphoreci.com/joeybloggs/pure)
55
[![Coverage Status](https://coveralls.io/repos/github/go-playground/pure/badge.svg?branch=master)](https://coveralls.io/github/go-playground/pure?branch=master)
66
[![Go Report Card](https://goreportcard.com/badge/github.com/go-playground/pure)](https://goreportcard.com/report/github.com/go-playground/pure)
@@ -116,7 +116,8 @@ admin.Use(SomeAdminSecurityMiddleware)
116116

117117
Decoding Body
118118
-------------
119-
currently JSON, XML, FORM, Multipart Form and url.Values are support out of the box.
119+
currently JSON, XML, FORM, Multipart Form and url.Values are support out of the box; there are also
120+
individual functions for each as well when you know the Content-Type.
120121
```go
121122
// second argument denotes yes or no I would like URL query parameter fields
122123
// to be included. i.e. 'id' and 'id2' in route '/user/:id?id2=val' should it be included.
@@ -155,40 +156,40 @@ Other middleware will be listed under the examples/middleware/... folder for a q
155156

156157
Benchmarks
157158
-----------
158-
Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3 using Go version go1.7.3 darwin/amd64
159+
Run on MacBook Pro (Retina, 15-inch, Late 2013) 2.6 GHz Intel Core i7 16 GB 1600 MHz DDR3 using Go version go1.7.4 darwin/amd64
159160

160161
NOTICE: pure uses a custom version of [httprouter](https://github.com/julienschmidt/httprouter)'s radix tree, benchmarks can be found [here](https://github.com/joeybloggs/go-http-routing-benchmark/tree/pure-and-lars) the slowdown is with the use of the `context` package, as you can see when no SEO params are defined, and therefore no need to store anything in the context, it is faster than even lars.
161162

162163
```go
163164
go test -bench=. -benchmem=true
164165
#GithubAPI Routes: 203
165-
Pure: 37560 Bytes
166+
Pure: 37544 Bytes
166167

167168
#GPlusAPI Routes: 13
168-
Pure: 2808 Bytes
169+
Pure: 2792 Bytes
169170

170171
#ParseAPI Routes: 26
171-
Pure: 5072 Bytes
172+
Pure: 5056 Bytes
172173

173174
#Static Routes: 157
174-
Pure: 21224 Bytes
175-
176-
BenchmarkPure_Param 10000000 156 ns/op 240 B/op 1 allocs/op
177-
BenchmarkPure_Param5 10000000 199 ns/op 240 B/op 1 allocs/op
178-
BenchmarkPure_Param20 5000000 349 ns/op 240 B/op 1 allocs/op
179-
BenchmarkPure_ParamWrite 10000000 209 ns/op 240 B/op 1 allocs/op
180-
BenchmarkPure_GithubStatic 30000000 45.4 ns/op 0 B/op 0 allocs/op
181-
BenchmarkPure_GithubParam 10000000 219 ns/op 240 B/op 1 allocs/op
182-
BenchmarkPure_GithubAll 30000 40244 ns/op 40082 B/op 167 allocs/op
183-
BenchmarkPure_GPlusStatic 50000000 30.4 ns/op 0 B/op 0 allocs/op
184-
BenchmarkPure_GPlusParam 10000000 173 ns/op 240 B/op 1 allocs/op
185-
BenchmarkPure_GPlus2Params 10000000 190 ns/op 240 B/op 1 allocs/op
186-
BenchmarkPure_GPlusAll 1000000 2108 ns/op 2640 B/op 11 allocs/op
187-
BenchmarkPure_ParseStatic 50000000 29.9 ns/op 0 B/op 0 allocs/op
188-
BenchmarkPure_ParseParam 10000000 154 ns/op 240 B/op 1 allocs/op
189-
BenchmarkPure_Parse2Params 10000000 167 ns/op 240 B/op 1 allocs/op
190-
BenchmarkPure_ParseAll 500000 3209 ns/op 3840 B/op 16 allocs/op
191-
BenchmarkPure_StaticAll 200000 9881 ns/op 0 B/op 0 allocs/op
175+
Pure: 21208 Bytes
176+
177+
BenchmarkPure_Param 10000000 159 ns/op 240 B/op 1 allocs/op
178+
BenchmarkPure_Param5 10000000 207 ns/op 240 B/op 1 allocs/op
179+
BenchmarkPure_Param20 5000000 353 ns/op 240 B/op 1 allocs/op
180+
BenchmarkPure_ParamWrite 10000000 224 ns/op 240 B/op 1 allocs/op
181+
BenchmarkPure_GithubStatic 30000000 47.0 ns/op 0 B/op 0 allocs/op
182+
BenchmarkPure_GithubParam 10000000 226 ns/op 240 B/op 1 allocs/op
183+
BenchmarkPure_GithubAll 30000 41178 ns/op 40082 B/op 167 allocs/op
184+
BenchmarkPure_GPlusStatic 50000000 30.1 ns/op 0 B/op 0 allocs/op
185+
BenchmarkPure_GPlusParam 10000000 172 ns/op 240 B/op 1 allocs/op
186+
BenchmarkPure_GPlus2Params 10000000 192 ns/op 240 B/op 1 allocs/op
187+
BenchmarkPure_GPlusAll 1000000 2127 ns/op 2640 B/op 11 allocs/op
188+
BenchmarkPure_ParseStatic 50000000 30.0 ns/op 0 B/op 0 allocs/op
189+
BenchmarkPure_ParseParam 10000000 165 ns/op 240 B/op 1 allocs/op
190+
BenchmarkPure_Parse2Params 10000000 177 ns/op 240 B/op 1 allocs/op
191+
BenchmarkPure_ParseAll 500000 3298 ns/op 3840 B/op 16 allocs/op
192+
BenchmarkPure_StaticAll 200000 9685 ns/op 0 B/op 0 allocs/op
192193
```
193194

194195
Package Versioning

helpers.go

Lines changed: 87 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -264,54 +264,112 @@ func Decode(r *http.Request, includeQueryParams bool, maxMemory int64, v interfa
264264
switch typ {
265265

266266
case ApplicationJSON:
267+
err = DecodeJSON(r, includeQueryParams, maxMemory, v)
267268

268-
err = json.NewDecoder(io.LimitReader(r.Body, maxMemory)).Decode(v)
269+
case ApplicationXML:
270+
err = DecodeXML(r, includeQueryParams, maxMemory, v)
269271

270-
if includeQueryParams && err == nil {
271-
err = DecodeQueryParams(r, includeQueryParams, v)
272-
}
272+
case ApplicationForm:
273+
err = DecodeForm(r, includeQueryParams, v)
273274

274-
case ApplicationXML:
275+
case MultipartForm:
276+
err = DecodeMultipartForm(r, includeQueryParams, maxMemory, v)
275277

276-
err = xml.NewDecoder(io.LimitReader(r.Body, maxMemory)).Decode(v)
278+
case ApplicationQueryParams:
277279

278-
if includeQueryParams && err == nil {
280+
if includeQueryParams {
279281
err = DecodeQueryParams(r, includeQueryParams, v)
280282
}
283+
}
281284

282-
case ApplicationForm:
285+
return
286+
}
283287

284-
if includeQueryParams {
288+
// DecodeForm parses the requests form data into the provided struct.
289+
//
290+
// The Content-Type and http method are not checked.
291+
//
292+
// NOTE: when includeQueryParams=true both query params and SEO query params will be parsed and
293+
// included eg. route /user/:id?test=true both 'id' and 'test' are treated as query params and added
294+
// to the request.Form prior to decoding; in short SEO query params are treated just like normal query params.
295+
func DecodeForm(r *http.Request, includeQueryParams bool, v interface{}) (err error) {
285296

286-
if err = ParseForm(r); err == nil {
287-
err = DefaultDecoder.Decode(v, r.Form)
288-
}
297+
if includeQueryParams {
289298

290-
} else {
291-
if err = r.ParseForm(); err == nil {
292-
err = DefaultDecoder.Decode(v, r.PostForm)
293-
}
299+
if err = ParseForm(r); err == nil {
300+
err = DefaultDecoder.Decode(v, r.Form)
294301
}
295302

296-
case MultipartForm:
303+
return
304+
}
297305

298-
if includeQueryParams {
306+
if err = r.ParseForm(); err == nil {
307+
err = DefaultDecoder.Decode(v, r.PostForm)
308+
}
299309

300-
if err = ParseMultipartForm(r, maxMemory); err == nil {
301-
err = DefaultDecoder.Decode(v, r.Form)
302-
}
310+
return
311+
}
303312

304-
} else {
305-
if err = r.ParseMultipartForm(maxMemory); err == nil {
306-
err = DefaultDecoder.Decode(v, r.MultipartForm.Value)
307-
}
308-
}
313+
// DecodeForm parses the requests form data into the provided struct.
314+
//
315+
// The Content-Type and http method are not checked.
316+
//
317+
// NOTE: when includeQueryParams=true both query params and SEO query params will be parsed and
318+
// included eg. route /user/:id?test=true both 'id' and 'test' are treated as query params and added
319+
// to the request.Form prior to decoding; in short SEO query params are treated just like normal query params.
320+
func DecodeMultipartForm(r *http.Request, includeQueryParams bool, maxMemory int64, v interface{}) (err error) {
309321

310-
case ApplicationQueryParams:
311-
if includeQueryParams {
312-
err = DecodeQueryParams(r, includeQueryParams, v)
322+
if includeQueryParams {
323+
324+
if err = ParseMultipartForm(r, maxMemory); err == nil {
325+
err = DefaultDecoder.Decode(v, r.Form)
313326
}
327+
328+
return
314329
}
330+
331+
if err = r.ParseMultipartForm(maxMemory); err == nil {
332+
err = DefaultDecoder.Decode(v, r.MultipartForm.Value)
333+
}
334+
335+
return
336+
}
337+
338+
// DecodeJSON decodes the request body into the provided struct and limits the request size via
339+
// an io.LimitReader using the maxMemory param.
340+
//
341+
// The Content-Type e.g. "application/json" and http method are not checked.
342+
//
343+
// NOTE: when includeQueryParams=true both query params and SEO query params will be parsed and
344+
// included eg. route /user/:id?test=true both 'id' and 'test' are treated as query params and
345+
// added to parsed JSON; in short SEO query params are treated just like normal query params.
346+
func DecodeJSON(r *http.Request, includeQueryParams bool, maxMemory int64, v interface{}) (err error) {
347+
348+
err = json.NewDecoder(io.LimitReader(r.Body, maxMemory)).Decode(v)
349+
350+
if includeQueryParams && err == nil {
351+
err = DecodeQueryParams(r, includeQueryParams, v)
352+
}
353+
354+
return
355+
}
356+
357+
// DecodeXML decodes the request body into the provided struct and limits the request size via
358+
// an io.LimitReader using the maxMemory param.
359+
//
360+
// The Content-Type e.g. "application/xml" and http method are not checked.
361+
//
362+
// NOTE: when includeQueryParams=true both query params and SEO query params will be parsed and
363+
// included eg. route /user/:id?test=true both 'id' and 'test' are treated as query params and
364+
// added to parsed XML; in short SEO query params are treated just like normal query params.
365+
func DecodeXML(r *http.Request, includeQueryParams bool, maxMemory int64, v interface{}) (err error) {
366+
367+
err = xml.NewDecoder(io.LimitReader(r.Body, maxMemory)).Decode(v)
368+
369+
if includeQueryParams && err == nil {
370+
err = DecodeQueryParams(r, includeQueryParams, v)
371+
}
372+
315373
return
316374
}
317375

node.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,11 +49,9 @@ func (n *node) incrementChildPrio(pos int) int {
4949
// adjust position (move to front)
5050
newPos := pos
5151
for newPos > 0 && n.children[newPos-1].priority < prio {
52-
// swap node positions
53-
tmpN := n.children[newPos-1]
54-
n.children[newPos-1] = n.children[newPos]
55-
n.children[newPos] = tmpN
5652

53+
// swap node positions
54+
n.children[newPos-1], n.children[newPos] = n.children[newPos], n.children[newPos-1]
5755
newPos--
5856
}
5957

pure.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ type Mux struct {
3232
// pool is used for reusable request scoped RequestVars content
3333
pool sync.Pool
3434

35+
http404 http.HandlerFunc // 404 Not Found
36+
http405 http.HandlerFunc // 405 Method Not Allowed
37+
httpOPTIONS http.HandlerFunc
38+
3539
// mostParams used to keep track of the most amount of
3640
// params in any URL and this will set the default capacity
3741
// of each Params
3842
mostParams uint8
3943

40-
http404 http.HandlerFunc // 404 Not Found
41-
http405 http.HandlerFunc // 405 Method Not Allowed
42-
httpOPTIONS http.HandlerFunc
43-
4444
// Enables automatic redirection if the current route can't be matched but a
4545
// handler for the path with (without) the trailing slash exists.
4646
// For example if /foo/ is requested but a route only exists for /foo, the

pure_test.go

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,17 +27,23 @@ import (
2727

2828
var (
2929
defaultHandler = func(w http.ResponseWriter, r *http.Request) {
30-
w.Write([]byte(r.Method))
30+
if _, err := w.Write([]byte(r.Method)); err != nil {
31+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
32+
}
3133
}
3234

3335
idHandler = func(w http.ResponseWriter, r *http.Request) {
3436
rv := RequestVars(r)
35-
w.Write([]byte(rv.URLParam("id")))
37+
if _, err := w.Write([]byte(rv.URLParam("id"))); err != nil {
38+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
39+
}
3640
}
3741

3842
params2Handler = func(w http.ResponseWriter, r *http.Request) {
3943
rv := RequestVars(r)
40-
w.Write([]byte(rv.URLParam("p1") + "|" + rv.URLParam("p2")))
44+
if _, err := w.Write([]byte(rv.URLParam("p1") + "|" + rv.URLParam("p2"))); err != nil {
45+
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
46+
}
4147
}
4248

4349
defaultMiddleware = func(next http.HandlerFunc) http.HandlerFunc {

0 commit comments

Comments
 (0)