From 580863c002fdbea128bd4789b4b577c04e4e2203 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Tue, 31 Oct 2017 14:12:13 -0600 Subject: [PATCH 01/10] switching to ajg/form and adding http status constants --- decoder.go | 15 ++++++++++++++- responder.go | 4 ++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/decoder.go b/decoder.go index 849c56b..98fa4eb 100644 --- a/decoder.go +++ b/decoder.go @@ -7,6 +7,8 @@ import ( "io" "io/ioutil" "net/http" + + "github.com/ajg/form" ) // Decode is a package-level variable set to our default Decoder. We do this @@ -17,6 +19,8 @@ import ( // bytes allowed to be read from the request body. var Decode = DefaultDecoder +// DefaultDecoder detects the correct decoder for use on an HTTP request and +// marshals into a given interface. func DefaultDecoder(r *http.Request, v interface{}) error { var err error @@ -25,7 +29,8 @@ func DefaultDecoder(r *http.Request, v interface{}) error { err = DecodeJSON(r.Body, v) case ContentTypeXML: err = DecodeXML(r.Body, v) - // case ContentTypeForm: // TODO + case ContentTypeForm: + err = DecodeForm(r.Body, v) default: err = errors.New("render: unable to automatically decode the request content type") } @@ -33,12 +38,20 @@ func DefaultDecoder(r *http.Request, v interface{}) error { return err } +// DecodeJSON decodes a given reader into an interface using the json decoder. func DecodeJSON(r io.Reader, v interface{}) error { defer io.Copy(ioutil.Discard, r) return json.NewDecoder(r).Decode(v) } +// DecodeXML decodes a given reader into an interface using the xml decoder. func DecodeXML(r io.Reader, v interface{}) error { defer io.Copy(ioutil.Discard, r) return xml.NewDecoder(r).Decode(v) } + +// DecodeForm decodes a given reader into an interface using the form decoder. +func DecodeForm(r io.Reader, v interface{}) error { + decoder := form.NewDecoder(r) + return decoder.Decode(v) +} diff --git a/responder.go b/responder.go index 049b7af..b834847 100644 --- a/responder.go +++ b/responder.go @@ -136,7 +136,7 @@ func XML(w http.ResponseWriter, r *http.Request, v interface{}) { // NoContent returns a HTTP 204 "No Content" response. func NoContent(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(204) + w.WriteHeader(http.StatusNoContent) } func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) { @@ -147,7 +147,7 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) { w.Header().Set("Content-Type", "text/event-stream; charset=utf-8") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") - w.WriteHeader(200) + w.WriteHeader(http.StatusOK) ctx := r.Context() for { From 17b67c43885ffffd83f1172aef03196116342a97 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Wed, 17 Jan 2018 12:28:46 -0700 Subject: [PATCH 02/10] fixing merge conflicts, actually. --- Gopkg.lock | 15 + Gopkg.toml | 25 ++ responder.go | 11 - vendor/github.com/ajg/form/.travis.yml | 25 ++ vendor/github.com/ajg/form/LICENSE | 27 ++ vendor/github.com/ajg/form/README.md | 246 ++++++++++++++ vendor/github.com/ajg/form/TODO.md | 4 + vendor/github.com/ajg/form/decode.go | 370 +++++++++++++++++++++ vendor/github.com/ajg/form/decode_test.go | 114 +++++++ vendor/github.com/ajg/form/encode.go | 388 ++++++++++++++++++++++ vendor/github.com/ajg/form/encode_test.go | 101 ++++++ vendor/github.com/ajg/form/form.go | 14 + vendor/github.com/ajg/form/form_test.go | 342 +++++++++++++++++++ vendor/github.com/ajg/form/node.go | 152 +++++++++ vendor/github.com/ajg/form/node_test.go | 87 +++++ vendor/github.com/ajg/form/pre-commit.sh | 18 + 16 files changed, 1928 insertions(+), 11 deletions(-) create mode 100644 Gopkg.lock create mode 100644 Gopkg.toml create mode 100644 vendor/github.com/ajg/form/.travis.yml create mode 100644 vendor/github.com/ajg/form/LICENSE create mode 100644 vendor/github.com/ajg/form/README.md create mode 100644 vendor/github.com/ajg/form/TODO.md create mode 100644 vendor/github.com/ajg/form/decode.go create mode 100644 vendor/github.com/ajg/form/decode_test.go create mode 100644 vendor/github.com/ajg/form/encode.go create mode 100644 vendor/github.com/ajg/form/encode_test.go create mode 100644 vendor/github.com/ajg/form/form.go create mode 100644 vendor/github.com/ajg/form/form_test.go create mode 100644 vendor/github.com/ajg/form/node.go create mode 100644 vendor/github.com/ajg/form/node_test.go create mode 100644 vendor/github.com/ajg/form/pre-commit.sh diff --git a/Gopkg.lock b/Gopkg.lock new file mode 100644 index 0000000..c905886 --- /dev/null +++ b/Gopkg.lock @@ -0,0 +1,15 @@ +# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. + + +[[projects]] + name = "github.com/ajg/form" + packages = ["."] + revision = "cc2954064ec9ea8d93917f0f87456e11d7b881ad" + version = "v1.5" + +[solve-meta] + analyzer-name = "dep" + analyzer-version = 1 + inputs-digest = "d62e06f4b19c343497cc165b31a39e794c9a7995a45c205548cc08aea57a46fd" + solver-name = "gps-cdcl" + solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml new file mode 100644 index 0000000..c51f75d --- /dev/null +++ b/Gopkg.toml @@ -0,0 +1,25 @@ +# Gopkg.toml example +# +# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md +# for detailed Gopkg.toml documentation. +# +# required = ["github.com/user/thing/cmd/thing"] +# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] +# +# [[constraint]] +# name = "github.com/user/project" +# version = "1.0.0" +# +# [[constraint]] +# name = "github.com/user/project2" +# branch = "dev" +# source = "github.com/myfork/project2" +# +# [[override]] +# name = "github.com/x/y" +# version = "2.4.0" + + +[[constraint]] + name = "github.com/ajg/form" + version = "1.5.0" diff --git a/responder.go b/responder.go index 5173de7..b834847 100644 --- a/responder.go +++ b/responder.go @@ -146,19 +146,8 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) { w.Header().Set("Content-Type", "text/event-stream; charset=utf-8") w.Header().Set("Cache-Control", "no-cache") -<<<<<<< HEAD w.Header().Set("Connection", "keep-alive") w.WriteHeader(http.StatusOK) -======= - - if r.ProtoMajor == 1 { - // An endpoint MUST NOT generate an HTTP/2 message containing connection-specific header fields. - // Source: RFC7540 - w.Header().Set("Connection", "keep-alive") - } - - w.WriteHeader(200) ->>>>>>> 8c8c7a43d054b536d7e18e82c4331e7258f211a2 ctx := r.Context() for { diff --git a/vendor/github.com/ajg/form/.travis.yml b/vendor/github.com/ajg/form/.travis.yml new file mode 100644 index 0000000..fc00b03 --- /dev/null +++ b/vendor/github.com/ajg/form/.travis.yml @@ -0,0 +1,25 @@ +## Copyright 2014 Alvaro J. Genial. All rights reserved. +## Use of this source code is governed by a BSD-style +## license that can be found in the LICENSE file. + +language: go + +go: + - tip + - 1.6 + - 1.5 + - 1.4 + - 1.3 + - 1.2 + +before_install: + # - go get -v golang.org/x/tools/cmd/cover + # - go get -v golang.org/x/tools/cmd/vet + # - go get -v github.com/golang/lint/golint + - export PATH=$PATH:/home/travis/gopath/bin + +script: + - go build -v ./... + - go test -v -cover ./... + - go vet ./... + # - golint . diff --git a/vendor/github.com/ajg/form/LICENSE b/vendor/github.com/ajg/form/LICENSE new file mode 100644 index 0000000..9190b16 --- /dev/null +++ b/vendor/github.com/ajg/form/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2014 Alvaro J. Genial. 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. diff --git a/vendor/github.com/ajg/form/README.md b/vendor/github.com/ajg/form/README.md new file mode 100644 index 0000000..05f92d4 --- /dev/null +++ b/vendor/github.com/ajg/form/README.md @@ -0,0 +1,246 @@ +form +==== + +A Form Encoding & Decoding Package for Go, written by [Alvaro J. Genial](http://alva.ro). + +[![Build Status](https://travis-ci.org/ajg/form.png?branch=master)](https://travis-ci.org/ajg/form) +[![GoDoc](https://godoc.org/github.com/ajg/form?status.png)](https://godoc.org/github.com/ajg/form) + +Synopsis +-------- + +This library is designed to allow seamless, high-fidelity encoding and decoding of arbitrary data in `application/x-www-form-urlencoded` format and as [`url.Values`](http://golang.org/pkg/net/url/#Values). It is intended to be useful primarily in dealing with web forms and URI query strings, both of which natively employ said format. + +Unsurprisingly, `form` is modeled after other Go [`encoding`](http://golang.org/pkg/encoding/) packages, in particular [`encoding/json`](http://golang.org/pkg/encoding/json/), and follows the same conventions (see below for more.) It aims to automatically handle any kind of concrete Go [data value](#values) (i.e., not functions, channels, etc.) while providing mechanisms for custom behavior. + +Status +------ + +The implementation is in usable shape and is fairly well tested with its accompanying test suite. The API is unlikely to change much, but still may. Lastly, the code has not yet undergone a security review to ensure it is free of vulnerabilities. Please file an issue or send a pull request for fixes & improvements. + +Dependencies +------------ + +The only requirement is [Go 1.2](http://golang.org/doc/go1.2) or later. + +Usage +----- + +```go +import "github.com/ajg/form" +``` + +Given a type like the following... + +```go +type User struct { + Name string `form:"name"` + Email string `form:"email"` + Joined time.Time `form:"joined,omitempty"` + Posts []int `form:"posts"` + Preferences map[string]string `form:"prefs"` + Avatar []byte `form:"avatar"` + PasswordHash int64 `form:"-"` +} +``` + +...it is easy to encode data of that type... + + +```go +func PostUser(url string, u User) error { + var c http.Client + _, err := c.PostForm(url, form.EncodeToValues(u)) + return err +} +``` + +...as well as decode it... + + +```go +func Handler(w http.ResponseWriter, r *http.Request) { + var u User + + d := form.NewDecoder(r.Body) + if err := d.Decode(&u); err != nil { + http.Error(w, "Form could not be decoded", http.StatusBadRequest) + return + } + + fmt.Fprintf(w, "Decoded: %#v", u) +} +``` + +...without having to do any grunt work. + +Field Tags +---------- + +Like other encoding packages, `form` supports the following options for fields: + + - `` `form:"-"` ``: Causes the field to be ignored during encoding and decoding. + - `` `form:""` ``: Overrides the field's name; useful especially when dealing with external identifiers in camelCase, as are commonly found on the web. + - `` `form:",omitempty"` ``: Elides the field during encoding if it is empty (typically meaning equal to the type's zero value.) + - `` `form:",omitempty"` ``: The way to combine the two options above. + +Values +------ + +### Simple Values + +Values of the following types are all considered simple: + + - `bool` + - `int`, `int8`, `int16`, `int32`, `int64`, `rune` + - `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `byte` + - `float32`, `float64` + - `complex64`, `complex128` + - `string` + - `[]byte` (see note) + - [`time.Time`](http://golang.org/pkg/time/#Time) + - [`url.URL`](http://golang.org/pkg/net/url/#URL) + - An alias of any of the above + - A pointer to any of the above + +### Composite Values + +A composite value is one that can contain other values. Values of the following kinds... + + - Maps + - Slices; except `[]byte` (see note) + - Structs; except [`time.Time`](http://golang.org/pkg/time/#Time) and [`url.URL`](http://golang.org/pkg/net/url/#URL) + - Arrays + - An alias of any of the above + - A pointer to any of the above + +...are considered composites in general, unless they implement custom marshaling/unmarshaling. Composite values are encoded as a flat mapping of paths to values, where the paths are constructed by joining the parent and child paths with a period (`.`). + +(Note: a byte slice is treated as a `string` by default because it's more efficient, but can also be decoded as a slice—i.e., with indexes.) + +### Untyped Values + +While encouraged, it is not necessary to define a type (e.g. a `struct`) in order to use `form`, since it is able to encode and decode untyped data generically using the following rules: + + - Simple values will be treated as a `string`. + - Composite values will be treated as a `map[string]interface{}`, itself able to contain nested values (both scalar and compound) ad infinitum. + - However, if there is a value (of any supported type) already present in a map for a given key, then it will be used when possible, rather than being replaced with a generic value as specified above; this makes it possible to handle partially typed, dynamic or schema-less values. + +### Zero Values + +By default, and without custom marshaling, zero values (also known as empty/default values) are encoded as the empty string. To disable this behavior, meaning to keep zero values in their literal form (e.g. `0` for integral types), `Encoder` offers a `KeepZeros` setter method, which will do just that when set to `true`. + +### Unsupported Values + +Values of the following kinds aren't supported and, if present, must be ignored. + + - Channel + - Function + - Unsafe pointer + - An alias of any of the above + - A pointer to any of the above + +Custom Marshaling +----------------- + +There is a default (generally lossless) marshaling & unmarshaling scheme for any concrete data value in Go, which is good enough in most cases. However, it is possible to override it and use a custom scheme. For instance, a "binary" field could be marshaled more efficiently using [base64](http://golang.org/pkg/encoding/base64/) to prevent it from being percent-escaped during serialization to `application/x-www-form-urlencoded` format. + +Because `form` provides support for [`encoding.TextMarshaler`](http://golang.org/pkg/encoding/#TextMarshaler) and [`encoding.TextUnmarshaler`](http://golang.org/pkg/encoding/#TextUnmarshaler) it is easy to do that; for instance, like this: + +```go +import "encoding" + +type Binary []byte + +var ( + _ encoding.TextMarshaler = &Binary{} + _ encoding.TextUnmarshaler = &Binary{} +) + +func (b Binary) MarshalText() ([]byte, error) { + return []byte(base64.URLEncoding.EncodeToString([]byte(b))), nil +} + +func (b *Binary) UnmarshalText(text []byte) error { + bs, err := base64.URLEncoding.DecodeString(string(text)) + if err == nil { + *b = Binary(bs) + } + return err +} +``` + +Now any value with type `Binary` will automatically be encoded using the [URL](http://golang.org/pkg/encoding/base64/#URLEncoding) variant of base64. It is left as an exercise to the reader to improve upon this scheme by eliminating the need for padding (which, besides being superfluous, uses `=`, a character that will end up percent-escaped.) + +Keys +---- + +In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`). + +(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.) + +The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the `DelimitWith` and `EscapeWith` setter methods of `Encoder` and `Decoder`, respectively. For example... + +```go +package main + +import ( + "os" + + "github.com/ajg/form" +) + +func main() { + type B struct { + Qux string `form:"qux"` + } + type A struct { + FooBar B `form:"foo.bar"` + } + a := A{FooBar: B{"XYZ"}} + os.Stdout.WriteString("Default: ") + form.NewEncoder(os.Stdout).Encode(a) + os.Stdout.WriteString("\nCustom: ") + form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a) + os.Stdout.WriteString("\n") +} + +``` + +...will produce... + +``` +Default: foo%5C.bar.qux=XYZ +Custom: foo.bar%2Fqux=XYZ +``` + +(`%5C` and `%2F` represent `\` and `/`, respectively.) + +Limitations +----------- + + - Circular (self-referential) values are untested. + +Future Work +----------- + +The following items would be nice to have in the future—though they are not being worked on yet: + + - An option to treat all values as if they had been tagged with `omitempty`. + - An option to automatically treat all field names in `camelCase` or `underscore_case`. + - Built-in support for the types in [`math/big`](http://golang.org/pkg/math/big/). + - Built-in support for the types in [`image/color`](http://golang.org/pkg/image/color/). + - Improve encoding/decoding by reading/writing directly from/to the `io.Reader`/`io.Writer` when possible, rather than going through an intermediate representation (i.e. `node`) which requires more memory. + +(Feel free to implement any of these and then send a pull request.) + +Related Work +------------ + + - Package [gorilla/schema](https://github.com/gorilla/schema), which only implements decoding. + - Package [google/go-querystring](https://github.com/google/go-querystring), which only implements encoding. + +License +------- + +This library is distributed under a BSD-style [LICENSE](./LICENSE). diff --git a/vendor/github.com/ajg/form/TODO.md b/vendor/github.com/ajg/form/TODO.md new file mode 100644 index 0000000..d344727 --- /dev/null +++ b/vendor/github.com/ajg/form/TODO.md @@ -0,0 +1,4 @@ +TODO +==== + + - Document IgnoreCase and IgnoreUnknownKeys in README. diff --git a/vendor/github.com/ajg/form/decode.go b/vendor/github.com/ajg/form/decode.go new file mode 100644 index 0000000..dd8bd4f --- /dev/null +++ b/vendor/github.com/ajg/form/decode.go @@ -0,0 +1,370 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "fmt" + "io" + "io/ioutil" + "net/url" + "reflect" + "strconv" + "time" +) + +// NewDecoder returns a new form Decoder. +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{r, defaultDelimiter, defaultEscape, false, false} +} + +// Decoder decodes data from a form (application/x-www-form-urlencoded). +type Decoder struct { + r io.Reader + d rune + e rune + ignoreUnknown bool + ignoreCase bool +} + +// DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default. +func (d *Decoder) DelimitWith(r rune) *Decoder { + d.d = r + return d +} + +// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default. +func (d *Decoder) EscapeWith(r rune) *Decoder { + d.e = r + return d +} + +// Decode reads in and decodes form-encoded data into dst. +func (d Decoder) Decode(dst interface{}) error { + bs, err := ioutil.ReadAll(d.r) + if err != nil { + return err + } + vs, err := url.ParseQuery(string(bs)) + if err != nil { + return err + } + v := reflect.ValueOf(dst) + return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) +} + +// IgnoreUnknownKeys if set to true it will make the Decoder ignore values +// that are not found in the destination object instead of returning an error. +func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool) { + d.ignoreUnknown = ignoreUnknown +} + +// IgnoreCase if set to true it will make the Decoder try to set values in the +// destination object even if the case does not match. +func (d *Decoder) IgnoreCase(ignoreCase bool) { + d.ignoreCase = ignoreCase +} + +// DecodeString decodes src into dst. +func (d Decoder) DecodeString(dst interface{}, src string) error { + vs, err := url.ParseQuery(src) + if err != nil { + return err + } + v := reflect.ValueOf(dst) + return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) +} + +// DecodeValues decodes vs into dst. +func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error { + v := reflect.ValueOf(dst) + return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) +} + +// DecodeString decodes src into dst. +func DecodeString(dst interface{}, src string) error { + return NewDecoder(nil).DecodeString(dst, src) +} + +// DecodeValues decodes vs into dst. +func DecodeValues(dst interface{}, vs url.Values) error { + return NewDecoder(nil).DecodeValues(dst, vs) +} + +func (d Decoder) decodeNode(v reflect.Value, n node) (err error) { + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("%v", e) + } + }() + + if v.Kind() == reflect.Slice { + return fmt.Errorf("could not decode directly into slice; use pointer to slice") + } + d.decodeValue(v, n) + return nil +} + +func (d Decoder) decodeValue(v reflect.Value, x interface{}) { + t := v.Type() + k := v.Kind() + + if k == reflect.Ptr && v.IsNil() { + v.Set(reflect.New(t.Elem())) + } + + if unmarshalValue(v, x) { + return + } + + empty := isEmpty(x) + + switch k { + case reflect.Ptr: + d.decodeValue(v.Elem(), x) + return + case reflect.Interface: + if !v.IsNil() { + d.decodeValue(v.Elem(), x) + return + + } else if empty { + return // Allow nil interfaces only if empty. + } else { + panic("form: cannot decode non-empty value into into nil interface") + } + } + + if empty { + v.Set(reflect.Zero(t)) // Treat the empty string as the zero value. + return + } + + switch k { + case reflect.Struct: + if t.ConvertibleTo(timeType) { + d.decodeTime(v, x) + } else if t.ConvertibleTo(urlType) { + d.decodeURL(v, x) + } else { + d.decodeStruct(v, x) + } + case reflect.Slice: + d.decodeSlice(v, x) + case reflect.Array: + d.decodeArray(v, x) + case reflect.Map: + d.decodeMap(v, x) + case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func: + panic(t.String() + " has unsupported kind " + k.String()) + default: + d.decodeBasic(v, x) + } +} + +func (d Decoder) decodeStruct(v reflect.Value, x interface{}) { + t := v.Type() + for k, c := range getNode(x) { + if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" { + panic(getString(x) + " cannot be decoded as " + t.String()) + } else if !ok { + if !d.ignoreUnknown { + panic(k + " doesn't exist in " + t.String()) + } + } else if !f.CanSet() { + panic(k + " cannot be set in " + t.String()) + } else { + d.decodeValue(f, c) + } + } +} + +func (d Decoder) decodeMap(v reflect.Value, x interface{}) { + t := v.Type() + if v.IsNil() { + v.Set(reflect.MakeMap(t)) + } + for k, c := range getNode(x) { + i := reflect.New(t.Key()).Elem() + d.decodeValue(i, k) + + w := v.MapIndex(i) + if w.IsValid() { // We have an actual element value to decode into. + if w.Kind() == reflect.Interface { + w = w.Elem() + } + w = reflect.New(w.Type()).Elem() + } else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete. + w = reflect.New(t.Elem()).Elem() + } else { + // The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest). + // We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast, + // especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.) + switch c.(type) { + case node: + w = reflect.MakeMap(stringMapType) + case string: + w = reflect.New(stringType).Elem() + default: + panic("value is neither node nor string") + } + } + + d.decodeValue(w, c) + v.SetMapIndex(i, w) + } +} + +func (d Decoder) decodeArray(v reflect.Value, x interface{}) { + t := v.Type() + for k, c := range getNode(x) { + i, err := strconv.Atoi(k) + if err != nil { + panic(k + " is not a valid index for type " + t.String()) + } + if l := v.Len(); i >= l { + panic("index is above array size") + } + d.decodeValue(v.Index(i), c) + } +} + +func (d Decoder) decodeSlice(v reflect.Value, x interface{}) { + t := v.Type() + if t.Elem().Kind() == reflect.Uint8 { + // Allow, but don't require, byte slices to be encoded as a single string. + if s, ok := x.(string); ok { + v.SetBytes([]byte(s)) + return + } + } + + // NOTE: Implicit indexing is currently done at the parseValues level, + // so if if an implicitKey reaches here it will always replace the last. + implicit := 0 + for k, c := range getNode(x) { + var i int + if k == implicitKey { + i = implicit + implicit++ + } else { + explicit, err := strconv.Atoi(k) + if err != nil { + panic(k + " is not a valid index for type " + t.String()) + } + i = explicit + implicit = explicit + 1 + } + // "Extend" the slice if it's too short. + if l := v.Len(); i >= l { + delta := i - l + 1 + v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta))) + } + d.decodeValue(v.Index(i), c) + } +} + +func (d Decoder) decodeBasic(v reflect.Value, x interface{}) { + t := v.Type() + switch k, s := t.Kind(), getString(x); k { + case reflect.Bool: + if b, e := strconv.ParseBool(s); e == nil { + v.SetBool(b) + } else { + panic("could not parse bool from " + strconv.Quote(s)) + } + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + if i, e := strconv.ParseInt(s, 10, 64); e == nil { + v.SetInt(i) + } else { + panic("could not parse int from " + strconv.Quote(s)) + } + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64: + if u, e := strconv.ParseUint(s, 10, 64); e == nil { + v.SetUint(u) + } else { + panic("could not parse uint from " + strconv.Quote(s)) + } + case reflect.Float32, + reflect.Float64: + if f, e := strconv.ParseFloat(s, 64); e == nil { + v.SetFloat(f) + } else { + panic("could not parse float from " + strconv.Quote(s)) + } + case reflect.Complex64, + reflect.Complex128: + var c complex128 + if n, err := fmt.Sscanf(s, "%g", &c); n == 1 && err == nil { + v.SetComplex(c) + } else { + panic("could not parse complex from " + strconv.Quote(s)) + } + case reflect.String: + v.SetString(s) + default: + panic(t.String() + " has unsupported kind " + k.String()) + } +} + +func (d Decoder) decodeTime(v reflect.Value, x interface{}) { + t := v.Type() + s := getString(x) + // TODO: Find a more efficient way to do this. + for _, f := range allowedTimeFormats { + if p, err := time.Parse(f, s); err == nil { + v.Set(reflect.ValueOf(p).Convert(v.Type())) + return + } + } + panic("cannot decode string `" + s + "` as " + t.String()) +} + +func (d Decoder) decodeURL(v reflect.Value, x interface{}) { + t := v.Type() + s := getString(x) + if u, err := url.Parse(s); err == nil { + v.Set(reflect.ValueOf(*u).Convert(v.Type())) + return + } + panic("cannot decode string `" + s + "` as " + t.String()) +} + +var allowedTimeFormats = []string{ + "2006-01-02T15:04:05.999999999Z07:00", + "2006-01-02T15:04:05.999999999Z07", + "2006-01-02T15:04:05.999999999Z", + "2006-01-02T15:04:05.999999999", + "2006-01-02T15:04:05Z07:00", + "2006-01-02T15:04:05Z07", + "2006-01-02T15:04:05Z", + "2006-01-02T15:04:05", + "2006-01-02T15:04Z", + "2006-01-02T15:04", + "2006-01-02T15Z", + "2006-01-02T15", + "2006-01-02", + "2006-01", + "2006", + "15:04:05.999999999Z07:00", + "15:04:05.999999999Z07", + "15:04:05.999999999Z", + "15:04:05.999999999", + "15:04:05Z07:00", + "15:04:05Z07", + "15:04:05Z", + "15:04:05", + "15:04Z", + "15:04", + "15Z", + "15", +} diff --git a/vendor/github.com/ajg/form/decode_test.go b/vendor/github.com/ajg/form/decode_test.go new file mode 100644 index 0000000..d4e585e --- /dev/null +++ b/vendor/github.com/ajg/form/decode_test.go @@ -0,0 +1,114 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "net/url" + "reflect" + "strings" + "testing" +) + +func TestDecodeString(t *testing.T) { + for _, c := range testCases(decOnly) { + if err := DecodeString(c.a, c.s); err != nil { + t.Errorf("DecodeString(%#v): %s", c.s, err) + } else if !reflect.DeepEqual(c.a, c.b) { + t.Errorf("DecodeString(%#v)\n want (%#v)\n have (%#v)", c.s, c.b, c.a) + } + } +} + +func TestDecodeValues(t *testing.T) { + for _, c := range testCases(decOnly) { + vs := mustParseQuery(c.s) + + if err := DecodeValues(c.a, vs); err != nil { + t.Errorf("DecodeValues(%#v): %s", vs, err) + } else if !reflect.DeepEqual(c.a, c.b) { + t.Errorf("DecodeValues(%#v)\n want (%#v)\n have (%#v)", vs, c.b, c.a) + } + } +} + +func TestDecode(t *testing.T) { + for _, c := range testCases(decOnly) { + r := strings.NewReader(c.s) + d := NewDecoder(r) + + if err := d.Decode(c.a); err != nil { + t.Errorf("Decode(%#v): %s", r, err) + } else if !reflect.DeepEqual(c.a, c.b) { + t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", r, c.b, c.a) + } + } +} + +func TestDecodeIgnoreUnknown(t *testing.T) { + type simpleStruct struct{ A string } + var dst simpleStruct + values := url.Values{ + "b": []string{"2"}, + "A": []string{"1"}, + } + expected := simpleStruct{A: "1"} + d := NewDecoder(nil) + err := d.DecodeValues(&dst, values) + if err == nil || err.Error() != "b doesn't exist in form.simpleStruct" { + t.Errorf("Decode(%#v): expected error got nil", values) + } + d.IgnoreUnknownKeys(true) + err = d.DecodeValues(&dst, values) + if err != nil { + t.Errorf("Decode(%#v): %s", values, err) + } + if !reflect.DeepEqual(dst, expected) { + t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) + } +} + +func TestDecodeIgnoreCase(t *testing.T) { + type simpleStruct struct{ AaAA string } + var dst simpleStruct + values := url.Values{ + "aAaA": []string{"1"}, + } + expected := simpleStruct{AaAA: "1"} + d := NewDecoder(nil) + err := d.DecodeValues(&dst, values) + if err == nil || err.Error() != "aAaA doesn't exist in form.simpleStruct" { + t.Errorf("Decode(%#v): expected error got nil", values) + } + d.IgnoreCase(true) + err = d.DecodeValues(&dst, values) + if err != nil { + t.Errorf("Decode(%#v): %s", values, err) + } + if !reflect.DeepEqual(dst, expected) { + t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) + } +} + +func TestDecodeIgnoreCasePriority(t *testing.T) { + type simpleStruct struct { + Aaa string + AaA string + AAA string + } + var dst simpleStruct + values := url.Values{ + "AaA": []string{"1"}, + } + expected := simpleStruct{AaA: "1"} + d := NewDecoder(nil) + d.IgnoreCase(true) + err := d.DecodeValues(&dst, values) + if err != nil { + t.Errorf("Decode(%#v): %s", values, err) + } + if !reflect.DeepEqual(dst, expected) { + t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) + } +} diff --git a/vendor/github.com/ajg/form/encode.go b/vendor/github.com/ajg/form/encode.go new file mode 100644 index 0000000..57a0d0a --- /dev/null +++ b/vendor/github.com/ajg/form/encode.go @@ -0,0 +1,388 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "encoding" + "errors" + "fmt" + "io" + "net/url" + "reflect" + "strconv" + "strings" + "time" +) + +// NewEncoder returns a new form Encoder. +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{w, defaultDelimiter, defaultEscape, false} +} + +// Encoder provides a way to encode to a Writer. +type Encoder struct { + w io.Writer + d rune + e rune + z bool +} + +// DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default. +func (e *Encoder) DelimitWith(r rune) *Encoder { + e.d = r + return e +} + +// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default. +func (e *Encoder) EscapeWith(r rune) *Encoder { + e.e = r + return e +} + +// KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string. +func (e *Encoder) KeepZeros(z bool) *Encoder { + e.z = z + return e +} + +// Encode encodes dst as form and writes it out using the Encoder's Writer. +func (e Encoder) Encode(dst interface{}) error { + v := reflect.ValueOf(dst) + n, err := encodeToNode(v, e.z) + if err != nil { + return err + } + s := n.values(e.d, e.e).Encode() + l, err := io.WriteString(e.w, s) + switch { + case err != nil: + return err + case l != len(s): + return errors.New("could not write data completely") + } + return nil +} + +// EncodeToString encodes dst as a form and returns it as a string. +func EncodeToString(dst interface{}) (string, error) { + v := reflect.ValueOf(dst) + n, err := encodeToNode(v, false) + if err != nil { + return "", err + } + vs := n.values(defaultDelimiter, defaultEscape) + return vs.Encode(), nil +} + +// EncodeToValues encodes dst as a form and returns it as Values. +func EncodeToValues(dst interface{}) (url.Values, error) { + v := reflect.ValueOf(dst) + n, err := encodeToNode(v, false) + if err != nil { + return nil, err + } + vs := n.values(defaultDelimiter, defaultEscape) + return vs, nil +} + +func encodeToNode(v reflect.Value, z bool) (n node, err error) { + defer func() { + if e := recover(); e != nil { + err = fmt.Errorf("%v", e) + } + }() + return getNode(encodeValue(v, z)), nil +} + +func encodeValue(v reflect.Value, z bool) interface{} { + t := v.Type() + k := v.Kind() + + if s, ok := marshalValue(v); ok { + return s + } else if !z && isEmptyValue(v) { + return "" // Treat the zero value as the empty string. + } + + switch k { + case reflect.Ptr, reflect.Interface: + return encodeValue(v.Elem(), z) + case reflect.Struct: + if t.ConvertibleTo(timeType) { + return encodeTime(v) + } else if t.ConvertibleTo(urlType) { + return encodeURL(v) + } + return encodeStruct(v, z) + case reflect.Slice: + return encodeSlice(v, z) + case reflect.Array: + return encodeArray(v, z) + case reflect.Map: + return encodeMap(v, z) + case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func: + panic(t.String() + " has unsupported kind " + t.Kind().String()) + default: + return encodeBasic(v) + } +} + +func encodeStruct(v reflect.Value, z bool) interface{} { + t := v.Type() + n := node{} + for i := 0; i < t.NumField(); i++ { + f := t.Field(i) + k, oe := fieldInfo(f) + + if k == "-" { + continue + } else if fv := v.Field(i); oe && isEmptyValue(fv) { + delete(n, k) + } else { + n[k] = encodeValue(fv, z) + } + } + return n +} + +func encodeMap(v reflect.Value, z bool) interface{} { + n := node{} + for _, i := range v.MapKeys() { + k := getString(encodeValue(i, z)) + n[k] = encodeValue(v.MapIndex(i), z) + } + return n +} + +func encodeArray(v reflect.Value, z bool) interface{} { + n := node{} + for i := 0; i < v.Len(); i++ { + n[strconv.Itoa(i)] = encodeValue(v.Index(i), z) + } + return n +} + +func encodeSlice(v reflect.Value, z bool) interface{} { + t := v.Type() + if t.Elem().Kind() == reflect.Uint8 { + return string(v.Bytes()) // Encode byte slices as a single string by default. + } + n := node{} + for i := 0; i < v.Len(); i++ { + n[strconv.Itoa(i)] = encodeValue(v.Index(i), z) + } + return n +} + +func encodeTime(v reflect.Value) string { + t := v.Convert(timeType).Interface().(time.Time) + if t.Year() == 0 && (t.Month() == 0 || t.Month() == 1) && (t.Day() == 0 || t.Day() == 1) { + return t.Format("15:04:05.999999999Z07:00") + } else if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 { + return t.Format("2006-01-02") + } + return t.Format("2006-01-02T15:04:05.999999999Z07:00") +} + +func encodeURL(v reflect.Value) string { + u := v.Convert(urlType).Interface().(url.URL) + return u.String() +} + +func encodeBasic(v reflect.Value) string { + t := v.Type() + switch k := t.Kind(); k { + case reflect.Bool: + return strconv.FormatBool(v.Bool()) + case reflect.Int, + reflect.Int8, + reflect.Int16, + reflect.Int32, + reflect.Int64: + return strconv.FormatInt(v.Int(), 10) + case reflect.Uint, + reflect.Uint8, + reflect.Uint16, + reflect.Uint32, + reflect.Uint64: + return strconv.FormatUint(v.Uint(), 10) + case reflect.Float32: + return strconv.FormatFloat(v.Float(), 'g', -1, 32) + case reflect.Float64: + return strconv.FormatFloat(v.Float(), 'g', -1, 64) + case reflect.Complex64, reflect.Complex128: + s := fmt.Sprintf("%g", v.Complex()) + return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")") + case reflect.String: + return v.String() + } + panic(t.String() + " has unsupported kind " + t.Kind().String()) +} + +func isEmptyValue(v reflect.Value) bool { + switch t := v.Type(); v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflect.Complex64, reflect.Complex128: + return v.Complex() == 0 + case reflect.Interface, reflect.Ptr: + return v.IsNil() + case reflect.Struct: + if t.ConvertibleTo(timeType) { + return v.Convert(timeType).Interface().(time.Time).IsZero() + } + return reflect.DeepEqual(v, reflect.Zero(t)) + } + return false +} + +// canIndexOrdinally returns whether a value contains an ordered sequence of elements. +func canIndexOrdinally(v reflect.Value) bool { + if !v.IsValid() { + return false + } + switch t := v.Type(); t.Kind() { + case reflect.Ptr, reflect.Interface: + return canIndexOrdinally(v.Elem()) + case reflect.Slice, reflect.Array: + return true + } + return false +} + +func fieldInfo(f reflect.StructField) (k string, oe bool) { + if f.PkgPath != "" { // Skip private fields. + return omittedKey, oe + } + + k = f.Name + tag := f.Tag.Get("form") + if tag == "" { + return k, oe + } + + ps := strings.SplitN(tag, ",", 2) + if ps[0] != "" { + k = ps[0] + } + if len(ps) == 2 { + oe = ps[1] == "omitempty" + } + return k, oe +} + +func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) { + t := v.Type() + l := v.NumField() + + var lowerN string + caseInsensitiveMatch := -1 + if ignoreCase { + lowerN = strings.ToLower(n) + } + + // First try named fields. + for i := 0; i < l; i++ { + f := t.Field(i) + k, _ := fieldInfo(f) + if k == omittedKey { + continue + } else if n == k { + return v.Field(i), true + } else if ignoreCase && lowerN == strings.ToLower(k) { + caseInsensitiveMatch = i + } + } + + // If no exact match was found try case insensitive match. + if caseInsensitiveMatch != -1 { + return v.Field(caseInsensitiveMatch), true + } + + // Then try anonymous (embedded) fields. + for i := 0; i < l; i++ { + f := t.Field(i) + k, _ := fieldInfo(f) + if k == omittedKey || !f.Anonymous { // || k != "" ? + continue + } + fv := v.Field(i) + fk := fv.Kind() + for fk == reflect.Ptr || fk == reflect.Interface { + fv = fv.Elem() + fk = fv.Kind() + } + + if fk != reflect.Struct { + continue + } + if ev, ok := findField(fv, n, ignoreCase); ok { + return ev, true + } + } + + return reflect.Value{}, false +} + +var ( + stringType = reflect.TypeOf(string("")) + stringMapType = reflect.TypeOf(map[string]interface{}{}) + timeType = reflect.TypeOf(time.Time{}) + timePtrType = reflect.TypeOf(&time.Time{}) + urlType = reflect.TypeOf(url.URL{}) +) + +func skipTextMarshalling(t reflect.Type) bool { + /*// Skip time.Time because its text unmarshaling is overly rigid: + return t == timeType || t == timePtrType*/ + // Skip time.Time & convertibles because its text unmarshaling is overly rigid: + return t.ConvertibleTo(timeType) || t.ConvertibleTo(timePtrType) +} + +func unmarshalValue(v reflect.Value, x interface{}) bool { + if skipTextMarshalling(v.Type()) { + return false + } + + tu, ok := v.Interface().(encoding.TextUnmarshaler) + if !ok && !v.CanAddr() { + return false + } else if !ok { + return unmarshalValue(v.Addr(), x) + } + + s := getString(x) + if err := tu.UnmarshalText([]byte(s)); err != nil { + panic(err) + } + return true +} + +func marshalValue(v reflect.Value) (string, bool) { + if skipTextMarshalling(v.Type()) { + return "", false + } + + tm, ok := v.Interface().(encoding.TextMarshaler) + if !ok && !v.CanAddr() { + return "", false + } else if !ok { + return marshalValue(v.Addr()) + } + + bs, err := tm.MarshalText() + if err != nil { + panic(err) + } + return string(bs), true +} diff --git a/vendor/github.com/ajg/form/encode_test.go b/vendor/github.com/ajg/form/encode_test.go new file mode 100644 index 0000000..885c80c --- /dev/null +++ b/vendor/github.com/ajg/form/encode_test.go @@ -0,0 +1,101 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "bytes" + "reflect" + "testing" +) + +func TestEncodeToString(t *testing.T) { + for _, c := range testCases(encOnly) { + if s, err := EncodeToString(c.b); err != nil { + t.Errorf("EncodeToString(%#v): %s", c.b, err) + } else if !reflect.DeepEqual(c.s, s) { + t.Errorf("EncodeToString(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s) + } + } +} + +func TestEncodeToValues(t *testing.T) { + for _, c := range testCases(encOnly) { + cvs := mustParseQuery(c.s) + if vs, err := EncodeToValues(c.b); err != nil { + t.Errorf("EncodeToValues(%#v): %s", c.b, err) + } else if !reflect.DeepEqual(cvs, vs) { + t.Errorf("EncodeToValues(%#v)\n want (%#v)\n have (%#v)", c.b, cvs, vs) + } + } +} + +func TestEncode(t *testing.T) { + for _, c := range testCases(encOnly) { + var w bytes.Buffer + e := NewEncoder(&w) + + if err := e.Encode(c.b); err != nil { + t.Errorf("Encode(%#v): %s", c.b, err) + } else if s := w.String(); !reflect.DeepEqual(c.s, s) { + t.Errorf("Encode(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s) + } + } +} + +type Thing1 struct { + String string `form:"name,omitempty"` + Integer *uint `form:"num,omitempty"` +} + +type Thing2 struct { + String string `form:"name,omitempty"` + Integer uint `form:"num,omitempty"` +} + +type Thing3 struct { + String string `form:"name"` + Integer *uint `form:"num"` +} + +type Thing4 struct { + String string `form:"name"` + Integer uint `form:"num"` +} + +func TestEncode_KeepZero(t *testing.T) { + num := uint(0) + for _, c := range []struct { + b interface{} + s string + z bool + }{ + {Thing1{"test", &num}, "name=test&num=", false}, + {Thing1{"test", &num}, "name=test&num=0", true}, + {Thing2{"test", num}, "name=test", false}, + {Thing2{"test", num}, "name=test", true}, + {Thing3{"test", &num}, "name=test&num=", false}, + {Thing3{"test", &num}, "name=test&num=0", true}, + {Thing4{"test", num}, "name=test&num=", false}, + {Thing4{"test", num}, "name=test&num=0", true}, + {Thing1{"", &num}, "num=", false}, + {Thing1{"", &num}, "num=0", true}, + {Thing2{"", num}, "", false}, + {Thing2{"", num}, "", true}, + {Thing3{"", &num}, "name=&num=", false}, + {Thing3{"", &num}, "name=&num=0", true}, + {Thing4{"", num}, "name=&num=", false}, + {Thing4{"", num}, "name=&num=0", true}, + } { + + var w bytes.Buffer + e := NewEncoder(&w) + + if err := e.KeepZeros(c.z).Encode(c.b); err != nil { + t.Errorf("KeepZeros(%#v).Encode(%#v): %s", c.z, c.b, err) + } else if s := w.String(); c.s != s { + t.Errorf("KeepZeros(%#v).Encode(%#v)\n want (%#v)\n have (%#v)", c.z, c.b, c.s, s) + } + } +} diff --git a/vendor/github.com/ajg/form/form.go b/vendor/github.com/ajg/form/form.go new file mode 100644 index 0000000..4052369 --- /dev/null +++ b/vendor/github.com/ajg/form/form.go @@ -0,0 +1,14 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package form implements encoding and decoding of application/x-www-form-urlencoded data. +package form + +const ( + implicitKey = "_" + omittedKey = "-" + + defaultDelimiter = '.' + defaultEscape = '\\' +) diff --git a/vendor/github.com/ajg/form/form_test.go b/vendor/github.com/ajg/form/form_test.go new file mode 100644 index 0000000..0ceb4e5 --- /dev/null +++ b/vendor/github.com/ajg/form/form_test.go @@ -0,0 +1,342 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "encoding" + "fmt" + "net/url" + "time" +) + +type Struct struct { + B bool + I int `form:"life"` + F float64 + C complex128 + R rune `form:",omitempty"` // For testing when non-empty. + Re rune `form:",omitempty"` // For testing when empty. + S string + T time.Time + U url.URL + A Array + M Map + Y interface{} `form:"-"` // For testing when non-empty. + Ye interface{} `form:"-"` // For testing when empty. + Zs Slice + E // Embedded. + P P `form:"P.D\\Q.B"` +} + +type SXs map[string]interface{} +type E struct { + Bytes1 []byte // For testing explicit (qualified by embedder) name, e.g. "E.Bytes1". + Bytes2 []byte // For testing implicit (unqualified) name, e.g. just "Bytes2" +} + +type Z time.Time // Defined as such to test conversions. + +func (z Z) String() string { return time.Time(z).String() } + +type Array [3]string +type Map map[string]int +type Slice []struct { + Z Z + Q Q + Qp *Q + Q2 Q `form:"-"` + E `form:"-"` +} + +// Custom marshaling +type Q struct { + a, b uint16 +} + +var ( + _ encoding.TextMarshaler = &Q{} + _ encoding.TextUnmarshaler = &Q{} +) + +func (u Q) MarshalText() ([]byte, error) { + return []byte(fmt.Sprintf("%d_%d", u.a, u.b)), nil +} + +func (u *Q) UnmarshalText(bs []byte) error { + _, err := fmt.Sscanf(string(bs), "%d_%d", &u.a, &u.b) + return err +} + +func prepopulate(sxs SXs) SXs { + var B bool + var I int + var F float64 + var C complex128 + var R rune + var S string + var T time.Time + var U url.URL + var A Array + var M Map + // Y is ignored. + // Ye is ignored. + var Zs Slice + var E E + var P P + sxs["B"] = B + sxs["life"] = I + sxs["F"] = F + sxs["C"] = C + sxs["R"] = R + // Re is omitted. + sxs["S"] = S + sxs["T"] = T + sxs["U"] = U + sxs["A"] = A + sxs["M"] = M + // Y is ignored. + // Ye is ignored. + sxs["Zs"] = Zs + sxs["E"] = E + sxs["P.D\\Q.B"] = P + return sxs +} + +type P struct { + A, B string +} + +type direction int + +const ( + encOnly = 1 + decOnly = 2 + rndTrip = encOnly | decOnly +) + +func testCases(dir direction) (cs []testCase) { + var B bool + var I int + var F float64 + var C complex128 + var R rune + var S string + var T time.Time + var U url.URL + const canonical = `A.0=x&A.1=y&A.2=z&B=true&C=42%2B6.6i&E.Bytes1=%00%01%02&E.Bytes2=%03%04%05&F=6.6&M.Bar=8&M.Foo=7&M.Qux=9&P%5C.D%5C%5CQ%5C.B.A=P%2FD&P%5C.D%5C%5CQ%5C.B.B=Q-B&R=8734&S=Hello%2C+there.&T=2013-10-01T07%3A05%3A34.000000088Z&U=http%3A%2F%2Fexample.org%2Ffoo%23bar&Zs.0.Q=11_22&Zs.0.Qp=33_44&Zs.0.Z=2006-12-01&life=42` + const variation = `;C=42%2B6.6i;A.0=x;M.Bar=8;F=6.6;A.1=y;R=8734;A.2=z;Zs.0.Qp=33_44;B=true;M.Foo=7;T=2013-10-01T07:05:34.000000088Z;E.Bytes1=%00%01%02;Bytes2=%03%04%05;Zs.0.Q=11_22;Zs.0.Z=2006-12-01;M.Qux=9;life=42;S=Hello,+there.;P\.D\\Q\.B.A=P/D;P\.D\\Q\.B.B=Q-B;U=http%3A%2F%2Fexample.org%2Ffoo%23bar;` + + for _, c := range []testCase{ + // Bools + {rndTrip, &B, "=", b(false)}, + {rndTrip, &B, "=true", b(true)}, + {decOnly, &B, "=false", b(false)}, + + // Ints + {rndTrip, &I, "=", i(0)}, + {rndTrip, &I, "=42", i(42)}, + {rndTrip, &I, "=-42", i(-42)}, + {decOnly, &I, "=0", i(0)}, + {decOnly, &I, "=-0", i(0)}, + + // Floats + {rndTrip, &F, "=", f(0)}, + {rndTrip, &F, "=6.6", f(6.6)}, + {rndTrip, &F, "=-6.6", f(-6.6)}, + + // Complexes + {rndTrip, &C, "=", c(complex(0, 0))}, + {rndTrip, &C, "=42%2B6.6i", c(complex(42, 6.6))}, + {rndTrip, &C, "=-42-6.6i", c(complex(-42, -6.6))}, + + // Runes + {rndTrip, &R, "=", r(0)}, + {rndTrip, &R, "=97", r('a')}, + {rndTrip, &R, "=8734", r('\u221E')}, + + // Strings + {rndTrip, &S, "=", s("")}, + {rndTrip, &S, "=X+%26+Y+%26+Z", s("X & Y & Z")}, + {rndTrip, &S, "=Hello%2C+there.", s("Hello, there.")}, + {decOnly, &S, "=Hello, there.", s("Hello, there.")}, + + // Dates/Times + {rndTrip, &T, "=", t(time.Time{})}, + {rndTrip, &T, "=2013-10-01T07%3A05%3A34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))}, + {decOnly, &T, "=2013-10-01T07:05:34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))}, + {rndTrip, &T, "=07%3A05%3A34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))}, + {decOnly, &T, "=07:05:34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))}, + {rndTrip, &T, "=2013-10-01", t(time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC))}, + + // URLs + {rndTrip, &U, "=", u(url.URL{})}, + {rndTrip, &U, "=http%3A%2F%2Fexample.org%2Ffoo%23bar", u(url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"})}, + {rndTrip, &U, "=git%3A%2F%2Fgithub.com%2Fajg%2Fform.git", u(url.URL{Scheme: "git", Host: "github.com", Path: "/ajg/form.git"})}, + + // Structs + {rndTrip, &Struct{Y: 786}, canonical, + &Struct{ + true, + 42, + 6.6, + complex(42, 6.6), + '\u221E', + rune(0), + "Hello, there.", + time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), + url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, + Array{"x", "y", "z"}, + Map{"Foo": 7, "Bar": 8, "Qux": 9}, + 786, // Y: This value should not change. + nil, // Ye: This value should not change. + Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, + E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, + P{"P/D", "Q-B"}, + }, + }, + {decOnly, &Struct{Y: 786}, variation, + &Struct{ + true, + 42, + 6.6, + complex(42, 6.6), + '\u221E', + rune(0), + "Hello, there.", + time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), + url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, + Array{"x", "y", "z"}, + Map{"Foo": 7, "Bar": 8, "Qux": 9}, + 786, // Y: This value should not change. + nil, // Ye: This value should not change. + Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, + E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, + P{"P/D", "Q-B"}, + }, + }, + + // Maps + {rndTrip, prepopulate(SXs{}), canonical, + SXs{"B": true, + "life": 42, + "F": 6.6, + "C": complex(42, 6.6), + "R": '\u221E', + // Re is omitted. + "S": "Hello, there.", + "T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), + "U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, + "A": Array{"x", "y", "z"}, + "M": Map{"Foo": 7, "Bar": 8, "Qux": 9}, + // Y is ignored. + // Ye is ignored. + "Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, + "E": E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, + "P.D\\Q.B": P{"P/D", "Q-B"}, + }, + }, + {decOnly, prepopulate(SXs{}), variation, + SXs{"B": true, + "life": 42, + "F": 6.6, + "C": complex(42, 6.6), + "R": '\u221E', + // Re is omitted. + "S": "Hello, there.", + "T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), + "U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, + "A": Array{"x", "y", "z"}, + "M": Map{"Foo": 7, "Bar": 8, "Qux": 9}, + // Y is ignored. + // Ye is ignored. + "Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, + "E": E{[]byte{0, 1, 2}, nil}, + "Bytes2": string([]byte{3, 4, 5}), + "P.D\\Q.B": P{"P/D", "Q-B"}, + }, + }, + + {rndTrip, SXs{}, canonical, + SXs{"B": "true", + "life": "42", + "F": "6.6", + "C": "42+6.6i", + "R": "8734", + // Re is omitted. + "S": "Hello, there.", + "T": "2013-10-01T07:05:34.000000088Z", + "U": "http://example.org/foo#bar", + "A": map[string]interface{}{"0": "x", "1": "y", "2": "z"}, + "M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"}, + // Y is ignored. + // Ye is ignored. + "Zs": map[string]interface{}{ + "0": map[string]interface{}{ + "Z": "2006-12-01", + "Q": "11_22", + "Qp": "33_44", + }, + }, + "E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2}), "Bytes2": string([]byte{3, 4, 5})}, + "P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"}, + }, + }, + {decOnly, SXs{}, variation, + SXs{"B": "true", + "life": "42", + "F": "6.6", + "C": "42+6.6i", + "R": "8734", + // Re is omitted. + "S": "Hello, there.", + "T": "2013-10-01T07:05:34.000000088Z", + "U": "http://example.org/foo#bar", + "A": map[string]interface{}{"0": "x", "1": "y", "2": "z"}, + "M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"}, + // Y is ignored. + // Ye is ignored. + "Zs": map[string]interface{}{ + "0": map[string]interface{}{ + "Z": "2006-12-01", + "Q": "11_22", + "Qp": "33_44", + }, + }, + "E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2})}, + "Bytes2": string([]byte{3, 4, 5}), + "P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"}, + }, + }, + } { + if c.d&dir != 0 { + cs = append(cs, c) + } + } + return cs +} + +type testCase struct { + d direction + a interface{} + s string + b interface{} +} + +func b(b bool) *bool { return &b } +func i(i int) *int { return &i } +func f(f float64) *float64 { return &f } +func c(c complex128) *complex128 { return &c } +func r(r rune) *rune { return &r } +func s(s string) *string { return &s } +func t(t time.Time) *time.Time { return &t } +func u(u url.URL) *url.URL { return &u } + +func mustParseQuery(s string) url.Values { + vs, err := url.ParseQuery(s) + if err != nil { + panic(err) + } + return vs +} diff --git a/vendor/github.com/ajg/form/node.go b/vendor/github.com/ajg/form/node.go new file mode 100644 index 0000000..567aaaf --- /dev/null +++ b/vendor/github.com/ajg/form/node.go @@ -0,0 +1,152 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "net/url" + "strconv" + "strings" +) + +type node map[string]interface{} + +func (n node) values(d, e rune) url.Values { + vs := url.Values{} + n.merge(d, e, "", &vs) + return vs +} + +func (n node) merge(d, e rune, p string, vs *url.Values) { + for k, x := range n { + switch y := x.(type) { + case string: + vs.Add(p+escape(d, e, k), y) + case node: + y.merge(d, e, p+escape(d, e, k)+string(d), vs) + default: + panic("value is neither string nor node") + } + } +} + +// TODO: Add tests for implicit indexing. +func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node { + // NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works: + // i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B + // ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B + // TODO: At in-between levels; e.g. Foo._.Bar=A&Foo._.Bar=B becomes Foo.0.Bar=A&Foo.1.Bar=B + // (This last one requires that there only be one placeholder in order for it to be unambiguous.) + + m := map[string]string{} + for k, ss := range vs { + indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey) + + for i, s := range ss { + if canIndexFirstLevelOrdinally { + k = strconv.Itoa(i) + string(d) + k + } else if indexLastLevelOrdinally { + k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i) + } + + m[k] = s + } + } + + n := node{} + for k, s := range m { + n = n.split(d, e, k, s) + } + return n +} + +func splitPath(d, e rune, path string) (k, rest string) { + esc := false + for i, r := range path { + switch { + case !esc && r == e: + esc = true + case !esc && r == d: + return unescape(d, e, path[:i]), path[i+1:] + default: + esc = false + } + } + return unescape(d, e, path), "" +} + +func (n node) split(d, e rune, path, s string) node { + k, rest := splitPath(d, e, path) + if rest == "" { + return add(n, k, s) + } + if _, ok := n[k]; !ok { + n[k] = node{} + } + + c := getNode(n[k]) + n[k] = c.split(d, e, rest, s) + return n +} + +func add(n node, k, s string) node { + if n == nil { + return node{k: s} + } + + if _, ok := n[k]; ok { + panic("key " + k + " already set") + } + + n[k] = s + return n +} + +func isEmpty(x interface{}) bool { + switch y := x.(type) { + case string: + return y == "" + case node: + if s, ok := y[""].(string); ok { + return s == "" + } + return false + } + panic("value is neither string nor node") +} + +func getNode(x interface{}) node { + switch y := x.(type) { + case string: + return node{"": y} + case node: + return y + } + panic("value is neither string nor node") +} + +func getString(x interface{}) string { + switch y := x.(type) { + case string: + return y + case node: + if s, ok := y[""].(string); ok { + return s + } + return "" + } + panic("value is neither string nor node") +} + +func escape(d, e rune, s string) string { + s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\) + s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.) + return s +} + +func unescape(d, e rune, s string) string { + s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .) + s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \) + return s +} diff --git a/vendor/github.com/ajg/form/node_test.go b/vendor/github.com/ajg/form/node_test.go new file mode 100644 index 0000000..d3d1fa7 --- /dev/null +++ b/vendor/github.com/ajg/form/node_test.go @@ -0,0 +1,87 @@ +// Copyright 2014 Alvaro J. Genial. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package form + +import ( + "reflect" + "testing" +) + +type foo int +type bar interface { + void() +} +type qux struct{} +type zee []bar + +func TestCanIndexOrdinally(t *testing.T) { + for _, c := range []struct { + x interface{} + b bool + }{ + {int(0), false}, + {foo(0), false}, + {qux{}, false}, + {(*int)(nil), false}, + {(*foo)(nil), false}, + {(*bar)(nil), false}, + {(*qux)(nil), false}, + {[]qux{}, true}, + {[5]qux{}, true}, + {&[]foo{}, true}, + {&[5]foo{}, true}, + {zee{}, true}, + {&zee{}, true}, + {map[int]foo{}, false}, + {map[string]interface{}{}, false}, + {map[interface{}]bar{}, false}, + {(chan<- int)(nil), false}, + {(chan bar)(nil), false}, + {(<-chan foo)(nil), false}, + } { + v := reflect.ValueOf(c.x) + if b := canIndexOrdinally(v); b != c.b { + t.Errorf("canIndexOrdinally(%#v)\n want (%#v)\n have (%#v)", v, c.b, b) + } + } +} + +var escapingTestCases = []struct { + a, b string + d, e rune +}{ + {"Foo", "Foo", defaultDelimiter, defaultEscape}, + {"Foo", "Foo", '/', '^'}, + {"Foo.Bar.Qux", "Foo\\.Bar\\.Qux", defaultDelimiter, defaultEscape}, + {"Foo.Bar.Qux", "Foo.Bar.Qux", '/', '^'}, + {"Foo/Bar/Qux", "Foo/Bar/Qux", defaultDelimiter, defaultEscape}, + {"Foo/Bar/Qux", "Foo^/Bar^/Qux", '/', '^'}, + {"0", "0", defaultDelimiter, defaultEscape}, + {"0", "0", '/', '^'}, + {"0.1.2", "0\\.1\\.2", defaultDelimiter, defaultEscape}, + {"0.1.2", "0.1.2", '/', '^'}, + {"0/1/2", "0/1/2", defaultDelimiter, defaultEscape}, + {"0/1/2", "0^/1^/2", '/', '^'}, + {"A\\B", "A\\\\B", defaultDelimiter, defaultEscape}, + {"A\\B", "A\\B", '/', '^'}, + {"A^B", "A^B", defaultDelimiter, defaultEscape}, + {"A^B", "A^^B", '/', '^'}, +} + +func TestEscape(t *testing.T) { + for _, c := range escapingTestCases { + if b := escape(c.d, c.e, c.a); b != c.b { + t.Errorf("escape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.a, c.b, b) + } + } +} + +func TestUnescape(t *testing.T) { + for _, c := range escapingTestCases { + if a := unescape(c.d, c.e, c.b); a != c.a { + t.Errorf("unescape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.b, c.a, a) + } + } +} diff --git a/vendor/github.com/ajg/form/pre-commit.sh b/vendor/github.com/ajg/form/pre-commit.sh new file mode 100644 index 0000000..29ce311 --- /dev/null +++ b/vendor/github.com/ajg/form/pre-commit.sh @@ -0,0 +1,18 @@ +#!/bin/bash -eu + +# TODO: Only colorize messages given a suitable terminal. +# FIXME: Handle case in which no stash entry is created due to no changes. + +printf "\e[30m=== PRE-COMMIT STARTING ===\e[m\n" +git stash save --quiet --keep-index --include-untracked + +if go build -v ./... && go test -v -cover ./... && go vet ./... && golint . && travis-lint; then + result=$? + printf "\e[32m=== PRE-COMMIT SUCCEEDED ===\e[m\n" +else + result=$? + printf "\e[31m=== PRE-COMMIT FAILED ===\e[m\n" +fi + +git stash pop --quiet +exit $result From 9fd658cc4c61b0cf9d3924da5813e0490b0b732b Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Wed, 17 Jan 2018 12:32:33 -0700 Subject: [PATCH 03/10] really fixing merge conflicts --- responder.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/responder.go b/responder.go index b834847..2acc773 100644 --- a/responder.go +++ b/responder.go @@ -146,7 +146,13 @@ func channelEventStream(w http.ResponseWriter, r *http.Request, v interface{}) { w.Header().Set("Content-Type", "text/event-stream; charset=utf-8") w.Header().Set("Cache-Control", "no-cache") - w.Header().Set("Connection", "keep-alive") + + if r.ProtoMajor == 1 { + // An endpoint MUST NOT generate an HTTP/2 message containing connection-specific header fields. + // Source: RFC7540 + w.Header().Set("Connection", "keep-alive") + } + w.WriteHeader(http.StatusOK) ctx := r.Context() From a54e4ac31a23aec4f82e6c3da09f0d18c9d396f1 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Sat, 30 Jun 2018 09:31:04 -0600 Subject: [PATCH 04/10] removing vendor folder --- vendor/github.com/ajg/form/.travis.yml | 25 -- vendor/github.com/ajg/form/LICENSE | 27 -- vendor/github.com/ajg/form/README.md | 246 -------------- vendor/github.com/ajg/form/TODO.md | 4 - vendor/github.com/ajg/form/decode.go | 370 --------------------- vendor/github.com/ajg/form/decode_test.go | 114 ------- vendor/github.com/ajg/form/encode.go | 388 ---------------------- vendor/github.com/ajg/form/encode_test.go | 101 ------ vendor/github.com/ajg/form/form.go | 14 - vendor/github.com/ajg/form/form_test.go | 342 ------------------- vendor/github.com/ajg/form/node.go | 152 --------- vendor/github.com/ajg/form/node_test.go | 87 ----- vendor/github.com/ajg/form/pre-commit.sh | 18 - 13 files changed, 1888 deletions(-) delete mode 100644 vendor/github.com/ajg/form/.travis.yml delete mode 100644 vendor/github.com/ajg/form/LICENSE delete mode 100644 vendor/github.com/ajg/form/README.md delete mode 100644 vendor/github.com/ajg/form/TODO.md delete mode 100644 vendor/github.com/ajg/form/decode.go delete mode 100644 vendor/github.com/ajg/form/decode_test.go delete mode 100644 vendor/github.com/ajg/form/encode.go delete mode 100644 vendor/github.com/ajg/form/encode_test.go delete mode 100644 vendor/github.com/ajg/form/form.go delete mode 100644 vendor/github.com/ajg/form/form_test.go delete mode 100644 vendor/github.com/ajg/form/node.go delete mode 100644 vendor/github.com/ajg/form/node_test.go delete mode 100644 vendor/github.com/ajg/form/pre-commit.sh diff --git a/vendor/github.com/ajg/form/.travis.yml b/vendor/github.com/ajg/form/.travis.yml deleted file mode 100644 index fc00b03..0000000 --- a/vendor/github.com/ajg/form/.travis.yml +++ /dev/null @@ -1,25 +0,0 @@ -## Copyright 2014 Alvaro J. Genial. All rights reserved. -## Use of this source code is governed by a BSD-style -## license that can be found in the LICENSE file. - -language: go - -go: - - tip - - 1.6 - - 1.5 - - 1.4 - - 1.3 - - 1.2 - -before_install: - # - go get -v golang.org/x/tools/cmd/cover - # - go get -v golang.org/x/tools/cmd/vet - # - go get -v github.com/golang/lint/golint - - export PATH=$PATH:/home/travis/gopath/bin - -script: - - go build -v ./... - - go test -v -cover ./... - - go vet ./... - # - golint . diff --git a/vendor/github.com/ajg/form/LICENSE b/vendor/github.com/ajg/form/LICENSE deleted file mode 100644 index 9190b16..0000000 --- a/vendor/github.com/ajg/form/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2014 Alvaro J. Genial. 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. diff --git a/vendor/github.com/ajg/form/README.md b/vendor/github.com/ajg/form/README.md deleted file mode 100644 index 05f92d4..0000000 --- a/vendor/github.com/ajg/form/README.md +++ /dev/null @@ -1,246 +0,0 @@ -form -==== - -A Form Encoding & Decoding Package for Go, written by [Alvaro J. Genial](http://alva.ro). - -[![Build Status](https://travis-ci.org/ajg/form.png?branch=master)](https://travis-ci.org/ajg/form) -[![GoDoc](https://godoc.org/github.com/ajg/form?status.png)](https://godoc.org/github.com/ajg/form) - -Synopsis --------- - -This library is designed to allow seamless, high-fidelity encoding and decoding of arbitrary data in `application/x-www-form-urlencoded` format and as [`url.Values`](http://golang.org/pkg/net/url/#Values). It is intended to be useful primarily in dealing with web forms and URI query strings, both of which natively employ said format. - -Unsurprisingly, `form` is modeled after other Go [`encoding`](http://golang.org/pkg/encoding/) packages, in particular [`encoding/json`](http://golang.org/pkg/encoding/json/), and follows the same conventions (see below for more.) It aims to automatically handle any kind of concrete Go [data value](#values) (i.e., not functions, channels, etc.) while providing mechanisms for custom behavior. - -Status ------- - -The implementation is in usable shape and is fairly well tested with its accompanying test suite. The API is unlikely to change much, but still may. Lastly, the code has not yet undergone a security review to ensure it is free of vulnerabilities. Please file an issue or send a pull request for fixes & improvements. - -Dependencies ------------- - -The only requirement is [Go 1.2](http://golang.org/doc/go1.2) or later. - -Usage ------ - -```go -import "github.com/ajg/form" -``` - -Given a type like the following... - -```go -type User struct { - Name string `form:"name"` - Email string `form:"email"` - Joined time.Time `form:"joined,omitempty"` - Posts []int `form:"posts"` - Preferences map[string]string `form:"prefs"` - Avatar []byte `form:"avatar"` - PasswordHash int64 `form:"-"` -} -``` - -...it is easy to encode data of that type... - - -```go -func PostUser(url string, u User) error { - var c http.Client - _, err := c.PostForm(url, form.EncodeToValues(u)) - return err -} -``` - -...as well as decode it... - - -```go -func Handler(w http.ResponseWriter, r *http.Request) { - var u User - - d := form.NewDecoder(r.Body) - if err := d.Decode(&u); err != nil { - http.Error(w, "Form could not be decoded", http.StatusBadRequest) - return - } - - fmt.Fprintf(w, "Decoded: %#v", u) -} -``` - -...without having to do any grunt work. - -Field Tags ----------- - -Like other encoding packages, `form` supports the following options for fields: - - - `` `form:"-"` ``: Causes the field to be ignored during encoding and decoding. - - `` `form:""` ``: Overrides the field's name; useful especially when dealing with external identifiers in camelCase, as are commonly found on the web. - - `` `form:",omitempty"` ``: Elides the field during encoding if it is empty (typically meaning equal to the type's zero value.) - - `` `form:",omitempty"` ``: The way to combine the two options above. - -Values ------- - -### Simple Values - -Values of the following types are all considered simple: - - - `bool` - - `int`, `int8`, `int16`, `int32`, `int64`, `rune` - - `uint`, `uint8`, `uint16`, `uint32`, `uint64`, `byte` - - `float32`, `float64` - - `complex64`, `complex128` - - `string` - - `[]byte` (see note) - - [`time.Time`](http://golang.org/pkg/time/#Time) - - [`url.URL`](http://golang.org/pkg/net/url/#URL) - - An alias of any of the above - - A pointer to any of the above - -### Composite Values - -A composite value is one that can contain other values. Values of the following kinds... - - - Maps - - Slices; except `[]byte` (see note) - - Structs; except [`time.Time`](http://golang.org/pkg/time/#Time) and [`url.URL`](http://golang.org/pkg/net/url/#URL) - - Arrays - - An alias of any of the above - - A pointer to any of the above - -...are considered composites in general, unless they implement custom marshaling/unmarshaling. Composite values are encoded as a flat mapping of paths to values, where the paths are constructed by joining the parent and child paths with a period (`.`). - -(Note: a byte slice is treated as a `string` by default because it's more efficient, but can also be decoded as a slice—i.e., with indexes.) - -### Untyped Values - -While encouraged, it is not necessary to define a type (e.g. a `struct`) in order to use `form`, since it is able to encode and decode untyped data generically using the following rules: - - - Simple values will be treated as a `string`. - - Composite values will be treated as a `map[string]interface{}`, itself able to contain nested values (both scalar and compound) ad infinitum. - - However, if there is a value (of any supported type) already present in a map for a given key, then it will be used when possible, rather than being replaced with a generic value as specified above; this makes it possible to handle partially typed, dynamic or schema-less values. - -### Zero Values - -By default, and without custom marshaling, zero values (also known as empty/default values) are encoded as the empty string. To disable this behavior, meaning to keep zero values in their literal form (e.g. `0` for integral types), `Encoder` offers a `KeepZeros` setter method, which will do just that when set to `true`. - -### Unsupported Values - -Values of the following kinds aren't supported and, if present, must be ignored. - - - Channel - - Function - - Unsafe pointer - - An alias of any of the above - - A pointer to any of the above - -Custom Marshaling ------------------ - -There is a default (generally lossless) marshaling & unmarshaling scheme for any concrete data value in Go, which is good enough in most cases. However, it is possible to override it and use a custom scheme. For instance, a "binary" field could be marshaled more efficiently using [base64](http://golang.org/pkg/encoding/base64/) to prevent it from being percent-escaped during serialization to `application/x-www-form-urlencoded` format. - -Because `form` provides support for [`encoding.TextMarshaler`](http://golang.org/pkg/encoding/#TextMarshaler) and [`encoding.TextUnmarshaler`](http://golang.org/pkg/encoding/#TextUnmarshaler) it is easy to do that; for instance, like this: - -```go -import "encoding" - -type Binary []byte - -var ( - _ encoding.TextMarshaler = &Binary{} - _ encoding.TextUnmarshaler = &Binary{} -) - -func (b Binary) MarshalText() ([]byte, error) { - return []byte(base64.URLEncoding.EncodeToString([]byte(b))), nil -} - -func (b *Binary) UnmarshalText(text []byte) error { - bs, err := base64.URLEncoding.DecodeString(string(text)) - if err == nil { - *b = Binary(bs) - } - return err -} -``` - -Now any value with type `Binary` will automatically be encoded using the [URL](http://golang.org/pkg/encoding/base64/#URLEncoding) variant of base64. It is left as an exercise to the reader to improve upon this scheme by eliminating the need for padding (which, besides being superfluous, uses `=`, a character that will end up percent-escaped.) - -Keys ----- - -In theory any value can be a key as long as it has a string representation. However, by default, periods have special meaning to `form`, and thus, under the hood (i.e. in encoded form) they are transparently escaped using a preceding backslash (`\`). Backslashes within keys, themselves, are also escaped in this manner (e.g. as `\\`) in order to permit representing `\.` itself (as `\\\.`). - -(Note: it is normally unnecessary to deal with this issue unless keys are being constructed manually—e.g. literally embedded in HTML or in a URI.) - -The default delimiter and escape characters used for encoding and decoding composite keys can be changed using the `DelimitWith` and `EscapeWith` setter methods of `Encoder` and `Decoder`, respectively. For example... - -```go -package main - -import ( - "os" - - "github.com/ajg/form" -) - -func main() { - type B struct { - Qux string `form:"qux"` - } - type A struct { - FooBar B `form:"foo.bar"` - } - a := A{FooBar: B{"XYZ"}} - os.Stdout.WriteString("Default: ") - form.NewEncoder(os.Stdout).Encode(a) - os.Stdout.WriteString("\nCustom: ") - form.NewEncoder(os.Stdout).DelimitWith('/').Encode(a) - os.Stdout.WriteString("\n") -} - -``` - -...will produce... - -``` -Default: foo%5C.bar.qux=XYZ -Custom: foo.bar%2Fqux=XYZ -``` - -(`%5C` and `%2F` represent `\` and `/`, respectively.) - -Limitations ------------ - - - Circular (self-referential) values are untested. - -Future Work ------------ - -The following items would be nice to have in the future—though they are not being worked on yet: - - - An option to treat all values as if they had been tagged with `omitempty`. - - An option to automatically treat all field names in `camelCase` or `underscore_case`. - - Built-in support for the types in [`math/big`](http://golang.org/pkg/math/big/). - - Built-in support for the types in [`image/color`](http://golang.org/pkg/image/color/). - - Improve encoding/decoding by reading/writing directly from/to the `io.Reader`/`io.Writer` when possible, rather than going through an intermediate representation (i.e. `node`) which requires more memory. - -(Feel free to implement any of these and then send a pull request.) - -Related Work ------------- - - - Package [gorilla/schema](https://github.com/gorilla/schema), which only implements decoding. - - Package [google/go-querystring](https://github.com/google/go-querystring), which only implements encoding. - -License -------- - -This library is distributed under a BSD-style [LICENSE](./LICENSE). diff --git a/vendor/github.com/ajg/form/TODO.md b/vendor/github.com/ajg/form/TODO.md deleted file mode 100644 index d344727..0000000 --- a/vendor/github.com/ajg/form/TODO.md +++ /dev/null @@ -1,4 +0,0 @@ -TODO -==== - - - Document IgnoreCase and IgnoreUnknownKeys in README. diff --git a/vendor/github.com/ajg/form/decode.go b/vendor/github.com/ajg/form/decode.go deleted file mode 100644 index dd8bd4f..0000000 --- a/vendor/github.com/ajg/form/decode.go +++ /dev/null @@ -1,370 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "fmt" - "io" - "io/ioutil" - "net/url" - "reflect" - "strconv" - "time" -) - -// NewDecoder returns a new form Decoder. -func NewDecoder(r io.Reader) *Decoder { - return &Decoder{r, defaultDelimiter, defaultEscape, false, false} -} - -// Decoder decodes data from a form (application/x-www-form-urlencoded). -type Decoder struct { - r io.Reader - d rune - e rune - ignoreUnknown bool - ignoreCase bool -} - -// DelimitWith sets r as the delimiter used for composite keys by Decoder d and returns the latter; it is '.' by default. -func (d *Decoder) DelimitWith(r rune) *Decoder { - d.d = r - return d -} - -// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Decoder d and returns the latter; it is '\\' by default. -func (d *Decoder) EscapeWith(r rune) *Decoder { - d.e = r - return d -} - -// Decode reads in and decodes form-encoded data into dst. -func (d Decoder) Decode(dst interface{}) error { - bs, err := ioutil.ReadAll(d.r) - if err != nil { - return err - } - vs, err := url.ParseQuery(string(bs)) - if err != nil { - return err - } - v := reflect.ValueOf(dst) - return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) -} - -// IgnoreUnknownKeys if set to true it will make the Decoder ignore values -// that are not found in the destination object instead of returning an error. -func (d *Decoder) IgnoreUnknownKeys(ignoreUnknown bool) { - d.ignoreUnknown = ignoreUnknown -} - -// IgnoreCase if set to true it will make the Decoder try to set values in the -// destination object even if the case does not match. -func (d *Decoder) IgnoreCase(ignoreCase bool) { - d.ignoreCase = ignoreCase -} - -// DecodeString decodes src into dst. -func (d Decoder) DecodeString(dst interface{}, src string) error { - vs, err := url.ParseQuery(src) - if err != nil { - return err - } - v := reflect.ValueOf(dst) - return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) -} - -// DecodeValues decodes vs into dst. -func (d Decoder) DecodeValues(dst interface{}, vs url.Values) error { - v := reflect.ValueOf(dst) - return d.decodeNode(v, parseValues(d.d, d.e, vs, canIndexOrdinally(v))) -} - -// DecodeString decodes src into dst. -func DecodeString(dst interface{}, src string) error { - return NewDecoder(nil).DecodeString(dst, src) -} - -// DecodeValues decodes vs into dst. -func DecodeValues(dst interface{}, vs url.Values) error { - return NewDecoder(nil).DecodeValues(dst, vs) -} - -func (d Decoder) decodeNode(v reflect.Value, n node) (err error) { - defer func() { - if e := recover(); e != nil { - err = fmt.Errorf("%v", e) - } - }() - - if v.Kind() == reflect.Slice { - return fmt.Errorf("could not decode directly into slice; use pointer to slice") - } - d.decodeValue(v, n) - return nil -} - -func (d Decoder) decodeValue(v reflect.Value, x interface{}) { - t := v.Type() - k := v.Kind() - - if k == reflect.Ptr && v.IsNil() { - v.Set(reflect.New(t.Elem())) - } - - if unmarshalValue(v, x) { - return - } - - empty := isEmpty(x) - - switch k { - case reflect.Ptr: - d.decodeValue(v.Elem(), x) - return - case reflect.Interface: - if !v.IsNil() { - d.decodeValue(v.Elem(), x) - return - - } else if empty { - return // Allow nil interfaces only if empty. - } else { - panic("form: cannot decode non-empty value into into nil interface") - } - } - - if empty { - v.Set(reflect.Zero(t)) // Treat the empty string as the zero value. - return - } - - switch k { - case reflect.Struct: - if t.ConvertibleTo(timeType) { - d.decodeTime(v, x) - } else if t.ConvertibleTo(urlType) { - d.decodeURL(v, x) - } else { - d.decodeStruct(v, x) - } - case reflect.Slice: - d.decodeSlice(v, x) - case reflect.Array: - d.decodeArray(v, x) - case reflect.Map: - d.decodeMap(v, x) - case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func: - panic(t.String() + " has unsupported kind " + k.String()) - default: - d.decodeBasic(v, x) - } -} - -func (d Decoder) decodeStruct(v reflect.Value, x interface{}) { - t := v.Type() - for k, c := range getNode(x) { - if f, ok := findField(v, k, d.ignoreCase); !ok && k == "" { - panic(getString(x) + " cannot be decoded as " + t.String()) - } else if !ok { - if !d.ignoreUnknown { - panic(k + " doesn't exist in " + t.String()) - } - } else if !f.CanSet() { - panic(k + " cannot be set in " + t.String()) - } else { - d.decodeValue(f, c) - } - } -} - -func (d Decoder) decodeMap(v reflect.Value, x interface{}) { - t := v.Type() - if v.IsNil() { - v.Set(reflect.MakeMap(t)) - } - for k, c := range getNode(x) { - i := reflect.New(t.Key()).Elem() - d.decodeValue(i, k) - - w := v.MapIndex(i) - if w.IsValid() { // We have an actual element value to decode into. - if w.Kind() == reflect.Interface { - w = w.Elem() - } - w = reflect.New(w.Type()).Elem() - } else if t.Elem().Kind() != reflect.Interface { // The map's element type is concrete. - w = reflect.New(t.Elem()).Elem() - } else { - // The best we can do here is to decode as either a string (for scalars) or a map[string]interface {} (for the rest). - // We could try to guess the type based on the string (e.g. true/false => bool) but that'll get ugly fast, - // especially if we have to guess the kind (slice vs. array vs. map) and index type (e.g. string, int, etc.) - switch c.(type) { - case node: - w = reflect.MakeMap(stringMapType) - case string: - w = reflect.New(stringType).Elem() - default: - panic("value is neither node nor string") - } - } - - d.decodeValue(w, c) - v.SetMapIndex(i, w) - } -} - -func (d Decoder) decodeArray(v reflect.Value, x interface{}) { - t := v.Type() - for k, c := range getNode(x) { - i, err := strconv.Atoi(k) - if err != nil { - panic(k + " is not a valid index for type " + t.String()) - } - if l := v.Len(); i >= l { - panic("index is above array size") - } - d.decodeValue(v.Index(i), c) - } -} - -func (d Decoder) decodeSlice(v reflect.Value, x interface{}) { - t := v.Type() - if t.Elem().Kind() == reflect.Uint8 { - // Allow, but don't require, byte slices to be encoded as a single string. - if s, ok := x.(string); ok { - v.SetBytes([]byte(s)) - return - } - } - - // NOTE: Implicit indexing is currently done at the parseValues level, - // so if if an implicitKey reaches here it will always replace the last. - implicit := 0 - for k, c := range getNode(x) { - var i int - if k == implicitKey { - i = implicit - implicit++ - } else { - explicit, err := strconv.Atoi(k) - if err != nil { - panic(k + " is not a valid index for type " + t.String()) - } - i = explicit - implicit = explicit + 1 - } - // "Extend" the slice if it's too short. - if l := v.Len(); i >= l { - delta := i - l + 1 - v.Set(reflect.AppendSlice(v, reflect.MakeSlice(t, delta, delta))) - } - d.decodeValue(v.Index(i), c) - } -} - -func (d Decoder) decodeBasic(v reflect.Value, x interface{}) { - t := v.Type() - switch k, s := t.Kind(), getString(x); k { - case reflect.Bool: - if b, e := strconv.ParseBool(s); e == nil { - v.SetBool(b) - } else { - panic("could not parse bool from " + strconv.Quote(s)) - } - case reflect.Int, - reflect.Int8, - reflect.Int16, - reflect.Int32, - reflect.Int64: - if i, e := strconv.ParseInt(s, 10, 64); e == nil { - v.SetInt(i) - } else { - panic("could not parse int from " + strconv.Quote(s)) - } - case reflect.Uint, - reflect.Uint8, - reflect.Uint16, - reflect.Uint32, - reflect.Uint64: - if u, e := strconv.ParseUint(s, 10, 64); e == nil { - v.SetUint(u) - } else { - panic("could not parse uint from " + strconv.Quote(s)) - } - case reflect.Float32, - reflect.Float64: - if f, e := strconv.ParseFloat(s, 64); e == nil { - v.SetFloat(f) - } else { - panic("could not parse float from " + strconv.Quote(s)) - } - case reflect.Complex64, - reflect.Complex128: - var c complex128 - if n, err := fmt.Sscanf(s, "%g", &c); n == 1 && err == nil { - v.SetComplex(c) - } else { - panic("could not parse complex from " + strconv.Quote(s)) - } - case reflect.String: - v.SetString(s) - default: - panic(t.String() + " has unsupported kind " + k.String()) - } -} - -func (d Decoder) decodeTime(v reflect.Value, x interface{}) { - t := v.Type() - s := getString(x) - // TODO: Find a more efficient way to do this. - for _, f := range allowedTimeFormats { - if p, err := time.Parse(f, s); err == nil { - v.Set(reflect.ValueOf(p).Convert(v.Type())) - return - } - } - panic("cannot decode string `" + s + "` as " + t.String()) -} - -func (d Decoder) decodeURL(v reflect.Value, x interface{}) { - t := v.Type() - s := getString(x) - if u, err := url.Parse(s); err == nil { - v.Set(reflect.ValueOf(*u).Convert(v.Type())) - return - } - panic("cannot decode string `" + s + "` as " + t.String()) -} - -var allowedTimeFormats = []string{ - "2006-01-02T15:04:05.999999999Z07:00", - "2006-01-02T15:04:05.999999999Z07", - "2006-01-02T15:04:05.999999999Z", - "2006-01-02T15:04:05.999999999", - "2006-01-02T15:04:05Z07:00", - "2006-01-02T15:04:05Z07", - "2006-01-02T15:04:05Z", - "2006-01-02T15:04:05", - "2006-01-02T15:04Z", - "2006-01-02T15:04", - "2006-01-02T15Z", - "2006-01-02T15", - "2006-01-02", - "2006-01", - "2006", - "15:04:05.999999999Z07:00", - "15:04:05.999999999Z07", - "15:04:05.999999999Z", - "15:04:05.999999999", - "15:04:05Z07:00", - "15:04:05Z07", - "15:04:05Z", - "15:04:05", - "15:04Z", - "15:04", - "15Z", - "15", -} diff --git a/vendor/github.com/ajg/form/decode_test.go b/vendor/github.com/ajg/form/decode_test.go deleted file mode 100644 index d4e585e..0000000 --- a/vendor/github.com/ajg/form/decode_test.go +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "net/url" - "reflect" - "strings" - "testing" -) - -func TestDecodeString(t *testing.T) { - for _, c := range testCases(decOnly) { - if err := DecodeString(c.a, c.s); err != nil { - t.Errorf("DecodeString(%#v): %s", c.s, err) - } else if !reflect.DeepEqual(c.a, c.b) { - t.Errorf("DecodeString(%#v)\n want (%#v)\n have (%#v)", c.s, c.b, c.a) - } - } -} - -func TestDecodeValues(t *testing.T) { - for _, c := range testCases(decOnly) { - vs := mustParseQuery(c.s) - - if err := DecodeValues(c.a, vs); err != nil { - t.Errorf("DecodeValues(%#v): %s", vs, err) - } else if !reflect.DeepEqual(c.a, c.b) { - t.Errorf("DecodeValues(%#v)\n want (%#v)\n have (%#v)", vs, c.b, c.a) - } - } -} - -func TestDecode(t *testing.T) { - for _, c := range testCases(decOnly) { - r := strings.NewReader(c.s) - d := NewDecoder(r) - - if err := d.Decode(c.a); err != nil { - t.Errorf("Decode(%#v): %s", r, err) - } else if !reflect.DeepEqual(c.a, c.b) { - t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", r, c.b, c.a) - } - } -} - -func TestDecodeIgnoreUnknown(t *testing.T) { - type simpleStruct struct{ A string } - var dst simpleStruct - values := url.Values{ - "b": []string{"2"}, - "A": []string{"1"}, - } - expected := simpleStruct{A: "1"} - d := NewDecoder(nil) - err := d.DecodeValues(&dst, values) - if err == nil || err.Error() != "b doesn't exist in form.simpleStruct" { - t.Errorf("Decode(%#v): expected error got nil", values) - } - d.IgnoreUnknownKeys(true) - err = d.DecodeValues(&dst, values) - if err != nil { - t.Errorf("Decode(%#v): %s", values, err) - } - if !reflect.DeepEqual(dst, expected) { - t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) - } -} - -func TestDecodeIgnoreCase(t *testing.T) { - type simpleStruct struct{ AaAA string } - var dst simpleStruct - values := url.Values{ - "aAaA": []string{"1"}, - } - expected := simpleStruct{AaAA: "1"} - d := NewDecoder(nil) - err := d.DecodeValues(&dst, values) - if err == nil || err.Error() != "aAaA doesn't exist in form.simpleStruct" { - t.Errorf("Decode(%#v): expected error got nil", values) - } - d.IgnoreCase(true) - err = d.DecodeValues(&dst, values) - if err != nil { - t.Errorf("Decode(%#v): %s", values, err) - } - if !reflect.DeepEqual(dst, expected) { - t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) - } -} - -func TestDecodeIgnoreCasePriority(t *testing.T) { - type simpleStruct struct { - Aaa string - AaA string - AAA string - } - var dst simpleStruct - values := url.Values{ - "AaA": []string{"1"}, - } - expected := simpleStruct{AaA: "1"} - d := NewDecoder(nil) - d.IgnoreCase(true) - err := d.DecodeValues(&dst, values) - if err != nil { - t.Errorf("Decode(%#v): %s", values, err) - } - if !reflect.DeepEqual(dst, expected) { - t.Errorf("Decode(%#v)\n want (%#v)\n have (%#v)", values, expected, dst) - } -} diff --git a/vendor/github.com/ajg/form/encode.go b/vendor/github.com/ajg/form/encode.go deleted file mode 100644 index 57a0d0a..0000000 --- a/vendor/github.com/ajg/form/encode.go +++ /dev/null @@ -1,388 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "encoding" - "errors" - "fmt" - "io" - "net/url" - "reflect" - "strconv" - "strings" - "time" -) - -// NewEncoder returns a new form Encoder. -func NewEncoder(w io.Writer) *Encoder { - return &Encoder{w, defaultDelimiter, defaultEscape, false} -} - -// Encoder provides a way to encode to a Writer. -type Encoder struct { - w io.Writer - d rune - e rune - z bool -} - -// DelimitWith sets r as the delimiter used for composite keys by Encoder e and returns the latter; it is '.' by default. -func (e *Encoder) DelimitWith(r rune) *Encoder { - e.d = r - return e -} - -// EscapeWith sets r as the escape used for delimiters (and to escape itself) by Encoder e and returns the latter; it is '\\' by default. -func (e *Encoder) EscapeWith(r rune) *Encoder { - e.e = r - return e -} - -// KeepZeros sets whether Encoder e should keep zero (default) values in their literal form when encoding, and returns the former; by default zero values are not kept, but are rather encoded as the empty string. -func (e *Encoder) KeepZeros(z bool) *Encoder { - e.z = z - return e -} - -// Encode encodes dst as form and writes it out using the Encoder's Writer. -func (e Encoder) Encode(dst interface{}) error { - v := reflect.ValueOf(dst) - n, err := encodeToNode(v, e.z) - if err != nil { - return err - } - s := n.values(e.d, e.e).Encode() - l, err := io.WriteString(e.w, s) - switch { - case err != nil: - return err - case l != len(s): - return errors.New("could not write data completely") - } - return nil -} - -// EncodeToString encodes dst as a form and returns it as a string. -func EncodeToString(dst interface{}) (string, error) { - v := reflect.ValueOf(dst) - n, err := encodeToNode(v, false) - if err != nil { - return "", err - } - vs := n.values(defaultDelimiter, defaultEscape) - return vs.Encode(), nil -} - -// EncodeToValues encodes dst as a form and returns it as Values. -func EncodeToValues(dst interface{}) (url.Values, error) { - v := reflect.ValueOf(dst) - n, err := encodeToNode(v, false) - if err != nil { - return nil, err - } - vs := n.values(defaultDelimiter, defaultEscape) - return vs, nil -} - -func encodeToNode(v reflect.Value, z bool) (n node, err error) { - defer func() { - if e := recover(); e != nil { - err = fmt.Errorf("%v", e) - } - }() - return getNode(encodeValue(v, z)), nil -} - -func encodeValue(v reflect.Value, z bool) interface{} { - t := v.Type() - k := v.Kind() - - if s, ok := marshalValue(v); ok { - return s - } else if !z && isEmptyValue(v) { - return "" // Treat the zero value as the empty string. - } - - switch k { - case reflect.Ptr, reflect.Interface: - return encodeValue(v.Elem(), z) - case reflect.Struct: - if t.ConvertibleTo(timeType) { - return encodeTime(v) - } else if t.ConvertibleTo(urlType) { - return encodeURL(v) - } - return encodeStruct(v, z) - case reflect.Slice: - return encodeSlice(v, z) - case reflect.Array: - return encodeArray(v, z) - case reflect.Map: - return encodeMap(v, z) - case reflect.Invalid, reflect.Uintptr, reflect.UnsafePointer, reflect.Chan, reflect.Func: - panic(t.String() + " has unsupported kind " + t.Kind().String()) - default: - return encodeBasic(v) - } -} - -func encodeStruct(v reflect.Value, z bool) interface{} { - t := v.Type() - n := node{} - for i := 0; i < t.NumField(); i++ { - f := t.Field(i) - k, oe := fieldInfo(f) - - if k == "-" { - continue - } else if fv := v.Field(i); oe && isEmptyValue(fv) { - delete(n, k) - } else { - n[k] = encodeValue(fv, z) - } - } - return n -} - -func encodeMap(v reflect.Value, z bool) interface{} { - n := node{} - for _, i := range v.MapKeys() { - k := getString(encodeValue(i, z)) - n[k] = encodeValue(v.MapIndex(i), z) - } - return n -} - -func encodeArray(v reflect.Value, z bool) interface{} { - n := node{} - for i := 0; i < v.Len(); i++ { - n[strconv.Itoa(i)] = encodeValue(v.Index(i), z) - } - return n -} - -func encodeSlice(v reflect.Value, z bool) interface{} { - t := v.Type() - if t.Elem().Kind() == reflect.Uint8 { - return string(v.Bytes()) // Encode byte slices as a single string by default. - } - n := node{} - for i := 0; i < v.Len(); i++ { - n[strconv.Itoa(i)] = encodeValue(v.Index(i), z) - } - return n -} - -func encodeTime(v reflect.Value) string { - t := v.Convert(timeType).Interface().(time.Time) - if t.Year() == 0 && (t.Month() == 0 || t.Month() == 1) && (t.Day() == 0 || t.Day() == 1) { - return t.Format("15:04:05.999999999Z07:00") - } else if t.Hour() == 0 && t.Minute() == 0 && t.Second() == 0 && t.Nanosecond() == 0 { - return t.Format("2006-01-02") - } - return t.Format("2006-01-02T15:04:05.999999999Z07:00") -} - -func encodeURL(v reflect.Value) string { - u := v.Convert(urlType).Interface().(url.URL) - return u.String() -} - -func encodeBasic(v reflect.Value) string { - t := v.Type() - switch k := t.Kind(); k { - case reflect.Bool: - return strconv.FormatBool(v.Bool()) - case reflect.Int, - reflect.Int8, - reflect.Int16, - reflect.Int32, - reflect.Int64: - return strconv.FormatInt(v.Int(), 10) - case reflect.Uint, - reflect.Uint8, - reflect.Uint16, - reflect.Uint32, - reflect.Uint64: - return strconv.FormatUint(v.Uint(), 10) - case reflect.Float32: - return strconv.FormatFloat(v.Float(), 'g', -1, 32) - case reflect.Float64: - return strconv.FormatFloat(v.Float(), 'g', -1, 64) - case reflect.Complex64, reflect.Complex128: - s := fmt.Sprintf("%g", v.Complex()) - return strings.TrimSuffix(strings.TrimPrefix(s, "("), ")") - case reflect.String: - return v.String() - } - panic(t.String() + " has unsupported kind " + t.Kind().String()) -} - -func isEmptyValue(v reflect.Value) bool { - switch t := v.Type(); v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Complex64, reflect.Complex128: - return v.Complex() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflect.Struct: - if t.ConvertibleTo(timeType) { - return v.Convert(timeType).Interface().(time.Time).IsZero() - } - return reflect.DeepEqual(v, reflect.Zero(t)) - } - return false -} - -// canIndexOrdinally returns whether a value contains an ordered sequence of elements. -func canIndexOrdinally(v reflect.Value) bool { - if !v.IsValid() { - return false - } - switch t := v.Type(); t.Kind() { - case reflect.Ptr, reflect.Interface: - return canIndexOrdinally(v.Elem()) - case reflect.Slice, reflect.Array: - return true - } - return false -} - -func fieldInfo(f reflect.StructField) (k string, oe bool) { - if f.PkgPath != "" { // Skip private fields. - return omittedKey, oe - } - - k = f.Name - tag := f.Tag.Get("form") - if tag == "" { - return k, oe - } - - ps := strings.SplitN(tag, ",", 2) - if ps[0] != "" { - k = ps[0] - } - if len(ps) == 2 { - oe = ps[1] == "omitempty" - } - return k, oe -} - -func findField(v reflect.Value, n string, ignoreCase bool) (reflect.Value, bool) { - t := v.Type() - l := v.NumField() - - var lowerN string - caseInsensitiveMatch := -1 - if ignoreCase { - lowerN = strings.ToLower(n) - } - - // First try named fields. - for i := 0; i < l; i++ { - f := t.Field(i) - k, _ := fieldInfo(f) - if k == omittedKey { - continue - } else if n == k { - return v.Field(i), true - } else if ignoreCase && lowerN == strings.ToLower(k) { - caseInsensitiveMatch = i - } - } - - // If no exact match was found try case insensitive match. - if caseInsensitiveMatch != -1 { - return v.Field(caseInsensitiveMatch), true - } - - // Then try anonymous (embedded) fields. - for i := 0; i < l; i++ { - f := t.Field(i) - k, _ := fieldInfo(f) - if k == omittedKey || !f.Anonymous { // || k != "" ? - continue - } - fv := v.Field(i) - fk := fv.Kind() - for fk == reflect.Ptr || fk == reflect.Interface { - fv = fv.Elem() - fk = fv.Kind() - } - - if fk != reflect.Struct { - continue - } - if ev, ok := findField(fv, n, ignoreCase); ok { - return ev, true - } - } - - return reflect.Value{}, false -} - -var ( - stringType = reflect.TypeOf(string("")) - stringMapType = reflect.TypeOf(map[string]interface{}{}) - timeType = reflect.TypeOf(time.Time{}) - timePtrType = reflect.TypeOf(&time.Time{}) - urlType = reflect.TypeOf(url.URL{}) -) - -func skipTextMarshalling(t reflect.Type) bool { - /*// Skip time.Time because its text unmarshaling is overly rigid: - return t == timeType || t == timePtrType*/ - // Skip time.Time & convertibles because its text unmarshaling is overly rigid: - return t.ConvertibleTo(timeType) || t.ConvertibleTo(timePtrType) -} - -func unmarshalValue(v reflect.Value, x interface{}) bool { - if skipTextMarshalling(v.Type()) { - return false - } - - tu, ok := v.Interface().(encoding.TextUnmarshaler) - if !ok && !v.CanAddr() { - return false - } else if !ok { - return unmarshalValue(v.Addr(), x) - } - - s := getString(x) - if err := tu.UnmarshalText([]byte(s)); err != nil { - panic(err) - } - return true -} - -func marshalValue(v reflect.Value) (string, bool) { - if skipTextMarshalling(v.Type()) { - return "", false - } - - tm, ok := v.Interface().(encoding.TextMarshaler) - if !ok && !v.CanAddr() { - return "", false - } else if !ok { - return marshalValue(v.Addr()) - } - - bs, err := tm.MarshalText() - if err != nil { - panic(err) - } - return string(bs), true -} diff --git a/vendor/github.com/ajg/form/encode_test.go b/vendor/github.com/ajg/form/encode_test.go deleted file mode 100644 index 885c80c..0000000 --- a/vendor/github.com/ajg/form/encode_test.go +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "bytes" - "reflect" - "testing" -) - -func TestEncodeToString(t *testing.T) { - for _, c := range testCases(encOnly) { - if s, err := EncodeToString(c.b); err != nil { - t.Errorf("EncodeToString(%#v): %s", c.b, err) - } else if !reflect.DeepEqual(c.s, s) { - t.Errorf("EncodeToString(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s) - } - } -} - -func TestEncodeToValues(t *testing.T) { - for _, c := range testCases(encOnly) { - cvs := mustParseQuery(c.s) - if vs, err := EncodeToValues(c.b); err != nil { - t.Errorf("EncodeToValues(%#v): %s", c.b, err) - } else if !reflect.DeepEqual(cvs, vs) { - t.Errorf("EncodeToValues(%#v)\n want (%#v)\n have (%#v)", c.b, cvs, vs) - } - } -} - -func TestEncode(t *testing.T) { - for _, c := range testCases(encOnly) { - var w bytes.Buffer - e := NewEncoder(&w) - - if err := e.Encode(c.b); err != nil { - t.Errorf("Encode(%#v): %s", c.b, err) - } else if s := w.String(); !reflect.DeepEqual(c.s, s) { - t.Errorf("Encode(%#v)\n want (%#v)\n have (%#v)", c.b, c.s, s) - } - } -} - -type Thing1 struct { - String string `form:"name,omitempty"` - Integer *uint `form:"num,omitempty"` -} - -type Thing2 struct { - String string `form:"name,omitempty"` - Integer uint `form:"num,omitempty"` -} - -type Thing3 struct { - String string `form:"name"` - Integer *uint `form:"num"` -} - -type Thing4 struct { - String string `form:"name"` - Integer uint `form:"num"` -} - -func TestEncode_KeepZero(t *testing.T) { - num := uint(0) - for _, c := range []struct { - b interface{} - s string - z bool - }{ - {Thing1{"test", &num}, "name=test&num=", false}, - {Thing1{"test", &num}, "name=test&num=0", true}, - {Thing2{"test", num}, "name=test", false}, - {Thing2{"test", num}, "name=test", true}, - {Thing3{"test", &num}, "name=test&num=", false}, - {Thing3{"test", &num}, "name=test&num=0", true}, - {Thing4{"test", num}, "name=test&num=", false}, - {Thing4{"test", num}, "name=test&num=0", true}, - {Thing1{"", &num}, "num=", false}, - {Thing1{"", &num}, "num=0", true}, - {Thing2{"", num}, "", false}, - {Thing2{"", num}, "", true}, - {Thing3{"", &num}, "name=&num=", false}, - {Thing3{"", &num}, "name=&num=0", true}, - {Thing4{"", num}, "name=&num=", false}, - {Thing4{"", num}, "name=&num=0", true}, - } { - - var w bytes.Buffer - e := NewEncoder(&w) - - if err := e.KeepZeros(c.z).Encode(c.b); err != nil { - t.Errorf("KeepZeros(%#v).Encode(%#v): %s", c.z, c.b, err) - } else if s := w.String(); c.s != s { - t.Errorf("KeepZeros(%#v).Encode(%#v)\n want (%#v)\n have (%#v)", c.z, c.b, c.s, s) - } - } -} diff --git a/vendor/github.com/ajg/form/form.go b/vendor/github.com/ajg/form/form.go deleted file mode 100644 index 4052369..0000000 --- a/vendor/github.com/ajg/form/form.go +++ /dev/null @@ -1,14 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Package form implements encoding and decoding of application/x-www-form-urlencoded data. -package form - -const ( - implicitKey = "_" - omittedKey = "-" - - defaultDelimiter = '.' - defaultEscape = '\\' -) diff --git a/vendor/github.com/ajg/form/form_test.go b/vendor/github.com/ajg/form/form_test.go deleted file mode 100644 index 0ceb4e5..0000000 --- a/vendor/github.com/ajg/form/form_test.go +++ /dev/null @@ -1,342 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "encoding" - "fmt" - "net/url" - "time" -) - -type Struct struct { - B bool - I int `form:"life"` - F float64 - C complex128 - R rune `form:",omitempty"` // For testing when non-empty. - Re rune `form:",omitempty"` // For testing when empty. - S string - T time.Time - U url.URL - A Array - M Map - Y interface{} `form:"-"` // For testing when non-empty. - Ye interface{} `form:"-"` // For testing when empty. - Zs Slice - E // Embedded. - P P `form:"P.D\\Q.B"` -} - -type SXs map[string]interface{} -type E struct { - Bytes1 []byte // For testing explicit (qualified by embedder) name, e.g. "E.Bytes1". - Bytes2 []byte // For testing implicit (unqualified) name, e.g. just "Bytes2" -} - -type Z time.Time // Defined as such to test conversions. - -func (z Z) String() string { return time.Time(z).String() } - -type Array [3]string -type Map map[string]int -type Slice []struct { - Z Z - Q Q - Qp *Q - Q2 Q `form:"-"` - E `form:"-"` -} - -// Custom marshaling -type Q struct { - a, b uint16 -} - -var ( - _ encoding.TextMarshaler = &Q{} - _ encoding.TextUnmarshaler = &Q{} -) - -func (u Q) MarshalText() ([]byte, error) { - return []byte(fmt.Sprintf("%d_%d", u.a, u.b)), nil -} - -func (u *Q) UnmarshalText(bs []byte) error { - _, err := fmt.Sscanf(string(bs), "%d_%d", &u.a, &u.b) - return err -} - -func prepopulate(sxs SXs) SXs { - var B bool - var I int - var F float64 - var C complex128 - var R rune - var S string - var T time.Time - var U url.URL - var A Array - var M Map - // Y is ignored. - // Ye is ignored. - var Zs Slice - var E E - var P P - sxs["B"] = B - sxs["life"] = I - sxs["F"] = F - sxs["C"] = C - sxs["R"] = R - // Re is omitted. - sxs["S"] = S - sxs["T"] = T - sxs["U"] = U - sxs["A"] = A - sxs["M"] = M - // Y is ignored. - // Ye is ignored. - sxs["Zs"] = Zs - sxs["E"] = E - sxs["P.D\\Q.B"] = P - return sxs -} - -type P struct { - A, B string -} - -type direction int - -const ( - encOnly = 1 - decOnly = 2 - rndTrip = encOnly | decOnly -) - -func testCases(dir direction) (cs []testCase) { - var B bool - var I int - var F float64 - var C complex128 - var R rune - var S string - var T time.Time - var U url.URL - const canonical = `A.0=x&A.1=y&A.2=z&B=true&C=42%2B6.6i&E.Bytes1=%00%01%02&E.Bytes2=%03%04%05&F=6.6&M.Bar=8&M.Foo=7&M.Qux=9&P%5C.D%5C%5CQ%5C.B.A=P%2FD&P%5C.D%5C%5CQ%5C.B.B=Q-B&R=8734&S=Hello%2C+there.&T=2013-10-01T07%3A05%3A34.000000088Z&U=http%3A%2F%2Fexample.org%2Ffoo%23bar&Zs.0.Q=11_22&Zs.0.Qp=33_44&Zs.0.Z=2006-12-01&life=42` - const variation = `;C=42%2B6.6i;A.0=x;M.Bar=8;F=6.6;A.1=y;R=8734;A.2=z;Zs.0.Qp=33_44;B=true;M.Foo=7;T=2013-10-01T07:05:34.000000088Z;E.Bytes1=%00%01%02;Bytes2=%03%04%05;Zs.0.Q=11_22;Zs.0.Z=2006-12-01;M.Qux=9;life=42;S=Hello,+there.;P\.D\\Q\.B.A=P/D;P\.D\\Q\.B.B=Q-B;U=http%3A%2F%2Fexample.org%2Ffoo%23bar;` - - for _, c := range []testCase{ - // Bools - {rndTrip, &B, "=", b(false)}, - {rndTrip, &B, "=true", b(true)}, - {decOnly, &B, "=false", b(false)}, - - // Ints - {rndTrip, &I, "=", i(0)}, - {rndTrip, &I, "=42", i(42)}, - {rndTrip, &I, "=-42", i(-42)}, - {decOnly, &I, "=0", i(0)}, - {decOnly, &I, "=-0", i(0)}, - - // Floats - {rndTrip, &F, "=", f(0)}, - {rndTrip, &F, "=6.6", f(6.6)}, - {rndTrip, &F, "=-6.6", f(-6.6)}, - - // Complexes - {rndTrip, &C, "=", c(complex(0, 0))}, - {rndTrip, &C, "=42%2B6.6i", c(complex(42, 6.6))}, - {rndTrip, &C, "=-42-6.6i", c(complex(-42, -6.6))}, - - // Runes - {rndTrip, &R, "=", r(0)}, - {rndTrip, &R, "=97", r('a')}, - {rndTrip, &R, "=8734", r('\u221E')}, - - // Strings - {rndTrip, &S, "=", s("")}, - {rndTrip, &S, "=X+%26+Y+%26+Z", s("X & Y & Z")}, - {rndTrip, &S, "=Hello%2C+there.", s("Hello, there.")}, - {decOnly, &S, "=Hello, there.", s("Hello, there.")}, - - // Dates/Times - {rndTrip, &T, "=", t(time.Time{})}, - {rndTrip, &T, "=2013-10-01T07%3A05%3A34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))}, - {decOnly, &T, "=2013-10-01T07:05:34.000000088Z", t(time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC))}, - {rndTrip, &T, "=07%3A05%3A34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))}, - {decOnly, &T, "=07:05:34.000000088Z", t(time.Date(0, 1, 1, 7, 5, 34, 88, time.UTC))}, - {rndTrip, &T, "=2013-10-01", t(time.Date(2013, 10, 1, 0, 0, 0, 0, time.UTC))}, - - // URLs - {rndTrip, &U, "=", u(url.URL{})}, - {rndTrip, &U, "=http%3A%2F%2Fexample.org%2Ffoo%23bar", u(url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"})}, - {rndTrip, &U, "=git%3A%2F%2Fgithub.com%2Fajg%2Fform.git", u(url.URL{Scheme: "git", Host: "github.com", Path: "/ajg/form.git"})}, - - // Structs - {rndTrip, &Struct{Y: 786}, canonical, - &Struct{ - true, - 42, - 6.6, - complex(42, 6.6), - '\u221E', - rune(0), - "Hello, there.", - time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), - url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, - Array{"x", "y", "z"}, - Map{"Foo": 7, "Bar": 8, "Qux": 9}, - 786, // Y: This value should not change. - nil, // Ye: This value should not change. - Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, - E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, - P{"P/D", "Q-B"}, - }, - }, - {decOnly, &Struct{Y: 786}, variation, - &Struct{ - true, - 42, - 6.6, - complex(42, 6.6), - '\u221E', - rune(0), - "Hello, there.", - time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), - url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, - Array{"x", "y", "z"}, - Map{"Foo": 7, "Bar": 8, "Qux": 9}, - 786, // Y: This value should not change. - nil, // Ye: This value should not change. - Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, - E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, - P{"P/D", "Q-B"}, - }, - }, - - // Maps - {rndTrip, prepopulate(SXs{}), canonical, - SXs{"B": true, - "life": 42, - "F": 6.6, - "C": complex(42, 6.6), - "R": '\u221E', - // Re is omitted. - "S": "Hello, there.", - "T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), - "U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, - "A": Array{"x", "y", "z"}, - "M": Map{"Foo": 7, "Bar": 8, "Qux": 9}, - // Y is ignored. - // Ye is ignored. - "Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, - "E": E{[]byte{0, 1, 2}, []byte{3, 4, 5}}, - "P.D\\Q.B": P{"P/D", "Q-B"}, - }, - }, - {decOnly, prepopulate(SXs{}), variation, - SXs{"B": true, - "life": 42, - "F": 6.6, - "C": complex(42, 6.6), - "R": '\u221E', - // Re is omitted. - "S": "Hello, there.", - "T": time.Date(2013, 10, 1, 7, 5, 34, 88, time.UTC), - "U": url.URL{Scheme: "http", Host: "example.org", Path: "/foo", Fragment: "bar"}, - "A": Array{"x", "y", "z"}, - "M": Map{"Foo": 7, "Bar": 8, "Qux": 9}, - // Y is ignored. - // Ye is ignored. - "Zs": Slice{{Z(time.Date(2006, 12, 1, 0, 0, 0, 0, time.UTC)), Q{11, 22}, &Q{33, 44}, Q{}, E{}}}, - "E": E{[]byte{0, 1, 2}, nil}, - "Bytes2": string([]byte{3, 4, 5}), - "P.D\\Q.B": P{"P/D", "Q-B"}, - }, - }, - - {rndTrip, SXs{}, canonical, - SXs{"B": "true", - "life": "42", - "F": "6.6", - "C": "42+6.6i", - "R": "8734", - // Re is omitted. - "S": "Hello, there.", - "T": "2013-10-01T07:05:34.000000088Z", - "U": "http://example.org/foo#bar", - "A": map[string]interface{}{"0": "x", "1": "y", "2": "z"}, - "M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"}, - // Y is ignored. - // Ye is ignored. - "Zs": map[string]interface{}{ - "0": map[string]interface{}{ - "Z": "2006-12-01", - "Q": "11_22", - "Qp": "33_44", - }, - }, - "E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2}), "Bytes2": string([]byte{3, 4, 5})}, - "P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"}, - }, - }, - {decOnly, SXs{}, variation, - SXs{"B": "true", - "life": "42", - "F": "6.6", - "C": "42+6.6i", - "R": "8734", - // Re is omitted. - "S": "Hello, there.", - "T": "2013-10-01T07:05:34.000000088Z", - "U": "http://example.org/foo#bar", - "A": map[string]interface{}{"0": "x", "1": "y", "2": "z"}, - "M": map[string]interface{}{"Foo": "7", "Bar": "8", "Qux": "9"}, - // Y is ignored. - // Ye is ignored. - "Zs": map[string]interface{}{ - "0": map[string]interface{}{ - "Z": "2006-12-01", - "Q": "11_22", - "Qp": "33_44", - }, - }, - "E": map[string]interface{}{"Bytes1": string([]byte{0, 1, 2})}, - "Bytes2": string([]byte{3, 4, 5}), - "P.D\\Q.B": map[string]interface{}{"A": "P/D", "B": "Q-B"}, - }, - }, - } { - if c.d&dir != 0 { - cs = append(cs, c) - } - } - return cs -} - -type testCase struct { - d direction - a interface{} - s string - b interface{} -} - -func b(b bool) *bool { return &b } -func i(i int) *int { return &i } -func f(f float64) *float64 { return &f } -func c(c complex128) *complex128 { return &c } -func r(r rune) *rune { return &r } -func s(s string) *string { return &s } -func t(t time.Time) *time.Time { return &t } -func u(u url.URL) *url.URL { return &u } - -func mustParseQuery(s string) url.Values { - vs, err := url.ParseQuery(s) - if err != nil { - panic(err) - } - return vs -} diff --git a/vendor/github.com/ajg/form/node.go b/vendor/github.com/ajg/form/node.go deleted file mode 100644 index 567aaaf..0000000 --- a/vendor/github.com/ajg/form/node.go +++ /dev/null @@ -1,152 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "net/url" - "strconv" - "strings" -) - -type node map[string]interface{} - -func (n node) values(d, e rune) url.Values { - vs := url.Values{} - n.merge(d, e, "", &vs) - return vs -} - -func (n node) merge(d, e rune, p string, vs *url.Values) { - for k, x := range n { - switch y := x.(type) { - case string: - vs.Add(p+escape(d, e, k), y) - case node: - y.merge(d, e, p+escape(d, e, k)+string(d), vs) - default: - panic("value is neither string nor node") - } - } -} - -// TODO: Add tests for implicit indexing. -func parseValues(d, e rune, vs url.Values, canIndexFirstLevelOrdinally bool) node { - // NOTE: Because of the flattening of potentially multiple strings to one key, implicit indexing works: - // i. At the first level; e.g. Foo.Bar=A&Foo.Bar=B becomes 0.Foo.Bar=A&1.Foo.Bar=B - // ii. At the last level; e.g. Foo.Bar._=A&Foo.Bar._=B becomes Foo.Bar.0=A&Foo.Bar.1=B - // TODO: At in-between levels; e.g. Foo._.Bar=A&Foo._.Bar=B becomes Foo.0.Bar=A&Foo.1.Bar=B - // (This last one requires that there only be one placeholder in order for it to be unambiguous.) - - m := map[string]string{} - for k, ss := range vs { - indexLastLevelOrdinally := strings.HasSuffix(k, string(d)+implicitKey) - - for i, s := range ss { - if canIndexFirstLevelOrdinally { - k = strconv.Itoa(i) + string(d) + k - } else if indexLastLevelOrdinally { - k = strings.TrimSuffix(k, implicitKey) + strconv.Itoa(i) - } - - m[k] = s - } - } - - n := node{} - for k, s := range m { - n = n.split(d, e, k, s) - } - return n -} - -func splitPath(d, e rune, path string) (k, rest string) { - esc := false - for i, r := range path { - switch { - case !esc && r == e: - esc = true - case !esc && r == d: - return unescape(d, e, path[:i]), path[i+1:] - default: - esc = false - } - } - return unescape(d, e, path), "" -} - -func (n node) split(d, e rune, path, s string) node { - k, rest := splitPath(d, e, path) - if rest == "" { - return add(n, k, s) - } - if _, ok := n[k]; !ok { - n[k] = node{} - } - - c := getNode(n[k]) - n[k] = c.split(d, e, rest, s) - return n -} - -func add(n node, k, s string) node { - if n == nil { - return node{k: s} - } - - if _, ok := n[k]; ok { - panic("key " + k + " already set") - } - - n[k] = s - return n -} - -func isEmpty(x interface{}) bool { - switch y := x.(type) { - case string: - return y == "" - case node: - if s, ok := y[""].(string); ok { - return s == "" - } - return false - } - panic("value is neither string nor node") -} - -func getNode(x interface{}) node { - switch y := x.(type) { - case string: - return node{"": y} - case node: - return y - } - panic("value is neither string nor node") -} - -func getString(x interface{}) string { - switch y := x.(type) { - case string: - return y - case node: - if s, ok := y[""].(string); ok { - return s - } - return "" - } - panic("value is neither string nor node") -} - -func escape(d, e rune, s string) string { - s = strings.Replace(s, string(e), string(e)+string(e), -1) // Escape the escape (\ => \\) - s = strings.Replace(s, string(d), string(e)+string(d), -1) // Escape the delimiter (. => \.) - return s -} - -func unescape(d, e rune, s string) string { - s = strings.Replace(s, string(e)+string(d), string(d), -1) // Unescape the delimiter (\. => .) - s = strings.Replace(s, string(e)+string(e), string(e), -1) // Unescape the escape (\\ => \) - return s -} diff --git a/vendor/github.com/ajg/form/node_test.go b/vendor/github.com/ajg/form/node_test.go deleted file mode 100644 index d3d1fa7..0000000 --- a/vendor/github.com/ajg/form/node_test.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright 2014 Alvaro J. Genial. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package form - -import ( - "reflect" - "testing" -) - -type foo int -type bar interface { - void() -} -type qux struct{} -type zee []bar - -func TestCanIndexOrdinally(t *testing.T) { - for _, c := range []struct { - x interface{} - b bool - }{ - {int(0), false}, - {foo(0), false}, - {qux{}, false}, - {(*int)(nil), false}, - {(*foo)(nil), false}, - {(*bar)(nil), false}, - {(*qux)(nil), false}, - {[]qux{}, true}, - {[5]qux{}, true}, - {&[]foo{}, true}, - {&[5]foo{}, true}, - {zee{}, true}, - {&zee{}, true}, - {map[int]foo{}, false}, - {map[string]interface{}{}, false}, - {map[interface{}]bar{}, false}, - {(chan<- int)(nil), false}, - {(chan bar)(nil), false}, - {(<-chan foo)(nil), false}, - } { - v := reflect.ValueOf(c.x) - if b := canIndexOrdinally(v); b != c.b { - t.Errorf("canIndexOrdinally(%#v)\n want (%#v)\n have (%#v)", v, c.b, b) - } - } -} - -var escapingTestCases = []struct { - a, b string - d, e rune -}{ - {"Foo", "Foo", defaultDelimiter, defaultEscape}, - {"Foo", "Foo", '/', '^'}, - {"Foo.Bar.Qux", "Foo\\.Bar\\.Qux", defaultDelimiter, defaultEscape}, - {"Foo.Bar.Qux", "Foo.Bar.Qux", '/', '^'}, - {"Foo/Bar/Qux", "Foo/Bar/Qux", defaultDelimiter, defaultEscape}, - {"Foo/Bar/Qux", "Foo^/Bar^/Qux", '/', '^'}, - {"0", "0", defaultDelimiter, defaultEscape}, - {"0", "0", '/', '^'}, - {"0.1.2", "0\\.1\\.2", defaultDelimiter, defaultEscape}, - {"0.1.2", "0.1.2", '/', '^'}, - {"0/1/2", "0/1/2", defaultDelimiter, defaultEscape}, - {"0/1/2", "0^/1^/2", '/', '^'}, - {"A\\B", "A\\\\B", defaultDelimiter, defaultEscape}, - {"A\\B", "A\\B", '/', '^'}, - {"A^B", "A^B", defaultDelimiter, defaultEscape}, - {"A^B", "A^^B", '/', '^'}, -} - -func TestEscape(t *testing.T) { - for _, c := range escapingTestCases { - if b := escape(c.d, c.e, c.a); b != c.b { - t.Errorf("escape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.a, c.b, b) - } - } -} - -func TestUnescape(t *testing.T) { - for _, c := range escapingTestCases { - if a := unescape(c.d, c.e, c.b); a != c.a { - t.Errorf("unescape(%q, %q, %q)\n want (%#v)\n have (%#v)", c.d, c.e, c.b, c.a, a) - } - } -} diff --git a/vendor/github.com/ajg/form/pre-commit.sh b/vendor/github.com/ajg/form/pre-commit.sh deleted file mode 100644 index 29ce311..0000000 --- a/vendor/github.com/ajg/form/pre-commit.sh +++ /dev/null @@ -1,18 +0,0 @@ -#!/bin/bash -eu - -# TODO: Only colorize messages given a suitable terminal. -# FIXME: Handle case in which no stash entry is created due to no changes. - -printf "\e[30m=== PRE-COMMIT STARTING ===\e[m\n" -git stash save --quiet --keep-index --include-untracked - -if go build -v ./... && go test -v -cover ./... && go vet ./... && golint . && travis-lint; then - result=$? - printf "\e[32m=== PRE-COMMIT SUCCEEDED ===\e[m\n" -else - result=$? - printf "\e[31m=== PRE-COMMIT FAILED ===\e[m\n" -fi - -git stash pop --quiet -exit $result From bf4aca9d0d05388848c00bdccef488aac6416bd7 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Sat, 30 Jun 2018 09:31:23 -0600 Subject: [PATCH 05/10] ignoring vendor folder from vcs --- .gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..61ead86 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/vendor From af1759ac836fd3a4acd01d709456fc28bcf32f05 Mon Sep 17 00:00:00 2001 From: Chase Hutchins Date: Sat, 30 Jun 2018 09:31:57 -0600 Subject: [PATCH 06/10] removing boilerplate toml --- Gopkg.toml | 22 ---------------------- 1 file changed, 22 deletions(-) diff --git a/Gopkg.toml b/Gopkg.toml index c51f75d..d767d8c 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -1,25 +1,3 @@ -# Gopkg.toml example -# -# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" - - [[constraint]] name = "github.com/ajg/form" version = "1.5.0" From 99dff9a94cc179fcbc60bbc95919715dc91d9ae8 Mon Sep 17 00:00:00 2001 From: Chase Pierce Date: Tue, 27 Apr 2021 14:23:04 -0600 Subject: [PATCH 07/10] modernizing DecodeForm changeset Removes dep, introduces Go modules, and updates a missing http const --- .gitignore | 2 +- Gopkg.lock | 15 --------------- Gopkg.toml | 3 --- go.mod | 5 +++++ go.sum | 2 ++ responder.go | 2 +- 6 files changed, 9 insertions(+), 20 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml create mode 100644 go.mod create mode 100644 go.sum diff --git a/.gitignore b/.gitignore index 61ead86..22d0d82 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1 @@ -/vendor +vendor diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index c905886..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,15 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[[projects]] - name = "github.com/ajg/form" - packages = ["."] - revision = "cc2954064ec9ea8d93917f0f87456e11d7b881ad" - version = "v1.5" - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - inputs-digest = "d62e06f4b19c343497cc165b31a39e794c9a7995a45c205548cc08aea57a46fd" - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index d767d8c..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,3 +0,0 @@ -[[constraint]] - name = "github.com/ajg/form" - version = "1.5.0" diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..e47a59c --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/go-chi/render + +go 1.16 + +require github.com/ajg/form v1.5.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..866445b --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/ajg/form v1.5.1 h1:t9c7v8JUKu/XxOGBU0yjNpaMloxGEJhUkqFRq0ibGeU= +github.com/ajg/form v1.5.1/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY= diff --git a/responder.go b/responder.go index 2acc773..d48703b 100644 --- a/responder.go +++ b/responder.go @@ -209,7 +209,7 @@ func channelIntoSlice(w http.ResponseWriter, r *http.Request, from interface{}) {Dir: reflect.SelectRecv, Chan: reflect.ValueOf(from)}, }); chosen { case 0: // equivalent to: case <-ctx.Done() - http.Error(w, "Server Timeout", 504) + http.Error(w, "Server Timeout", http.StatusGatewayTimeout) return nil default: // equivalent to: case v, ok := <-stream From 6a082d97118f6053277c8b20bd5a3d1188114c17 Mon Sep 17 00:00:00 2001 From: Chase Pierce Date: Tue, 27 Apr 2021 14:47:43 -0600 Subject: [PATCH 08/10] swapping travis for github actions --- .github/workflows/golangci-lint.yml | 19 +++++++++++++++++++ .github/workflows/test.yml | 24 ++++++++++++++++++++++++ .travis.yml | 15 --------------- README.md | 4 ++++ 4 files changed, 47 insertions(+), 15 deletions(-) create mode 100644 .github/workflows/golangci-lint.yml create mode 100644 .github/workflows/test.yml delete mode 100644 .travis.yml diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml new file mode 100644 index 0000000..057d2af --- /dev/null +++ b/.github/workflows/golangci-lint.yml @@ -0,0 +1,19 @@ +name: golangci-lint +on: + push: + tags: + - v* + branches: + - master + - main + pull_request: +jobs: + golangci: + name: lint + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: golangci-lint + uses: golangci/golangci-lint-action@v2 + with: + version: v1.29 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..87b6bb9 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,24 @@ +name: test +on: + push: + tags: + - v* + branches: + - master + - main + pull_request: +jobs: + test: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions/setup-go@v2 + - uses: actions/cache@v2.1.2 + with: + path: ~/go/pkg/mod + key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} + restore-keys: | + ${{ runner.os }}-go- + - run: go mod download + - name: Run tests + run: go test -v -race -coverprofile=coverage.out -covermode=atomic ./... diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index a026204..0000000 --- a/.travis.yml +++ /dev/null @@ -1,15 +0,0 @@ -language: go - -go: - - 1.7.x - - 1.8.x - - tip - -install: - - go get -u golang.org/x/tools/cmd/goimports - -script: - - go get -d -t ./... - - go test ./... - - > - goimports -d -e ./ | grep '.*' && { echo; echo "Aborting due to non-empty goimports output."; exit 1; } || : diff --git a/README.md b/README.md index 068e0bf..090fdae 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,9 @@ # render +![tests](https://github.com/go-chi/render/actions/workflows/test.yml/badge.svg) +[![Go Report Card](https://goreportcard.com/badge/github.com/go-chi/render)](https://goreportcard.com/report/github.com/go-chi/render) +[![Go Reference](https://pkg.go.dev/badge/github.com/go-chi/render.svg)](https://pkg.go.dev/github.com/go-chi/render) + The `render` package helps manage HTTP request / response payloads. Every well-designed, robust and maintainable Web Service / REST API also needs From 56c7eb90e53625b478493cd584d5c8b31d5477b0 Mon Sep 17 00:00:00 2001 From: Chase Pierce Date: Tue, 27 Apr 2021 14:52:40 -0600 Subject: [PATCH 09/10] removing minor.patch specificity of actions/cache --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 87b6bb9..5e3321f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -13,7 +13,7 @@ jobs: steps: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 - - uses: actions/cache@v2.1.2 + - uses: actions/cache@v2 with: path: ~/go/pkg/mod key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} From d0988512d7221a22f2f455f1f750abf049faaa97 Mon Sep 17 00:00:00 2001 From: Chase Pierce Date: Tue, 27 Apr 2021 14:58:22 -0600 Subject: [PATCH 10/10] adding nolint errcheck until a config can be added --- README.md | 1 - decoder.go | 6 +++--- responder.go | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 090fdae..4d37153 100644 --- a/README.md +++ b/README.md @@ -25,4 +25,3 @@ request bodies. Please have a look at the [rest](https://github.com/go-chi/chi/b example which uses the latest chi/render sub-pkg. All feedback is welcome, thank you! - diff --git a/decoder.go b/decoder.go index 98fa4eb..883b2f8 100644 --- a/decoder.go +++ b/decoder.go @@ -40,18 +40,18 @@ func DefaultDecoder(r *http.Request, v interface{}) error { // DecodeJSON decodes a given reader into an interface using the json decoder. func DecodeJSON(r io.Reader, v interface{}) error { - defer io.Copy(ioutil.Discard, r) + defer io.Copy(ioutil.Discard, r) //nolint:errcheck return json.NewDecoder(r).Decode(v) } // DecodeXML decodes a given reader into an interface using the xml decoder. func DecodeXML(r io.Reader, v interface{}) error { - defer io.Copy(ioutil.Discard, r) + defer io.Copy(ioutil.Discard, r) //nolint:errcheck return xml.NewDecoder(r).Decode(v) } // DecodeForm decodes a given reader into an interface using the form decoder. func DecodeForm(r io.Reader, v interface{}) error { - decoder := form.NewDecoder(r) + decoder := form.NewDecoder(r) //nolint:errcheck return decoder.Decode(v) } diff --git a/responder.go b/responder.go index 2d5832f..66d6bbf 100644 --- a/responder.go +++ b/responder.go @@ -66,7 +66,7 @@ func PlainText(w http.ResponseWriter, r *http.Request, v string) { if status, ok := r.Context().Value(StatusCtxKey).(int); ok { w.WriteHeader(status) } - w.Write([]byte(v)) + w.Write([]byte(v)) //nolint:errcheck } // Data writes raw bytes to the response, setting the Content-Type as @@ -76,7 +76,7 @@ func Data(w http.ResponseWriter, r *http.Request, v []byte) { if status, ok := r.Context().Value(StatusCtxKey).(int); ok { w.WriteHeader(status) } - w.Write(v) + w.Write(v) //nolint:errcheck } // HTML writes a string to the response, setting the Content-Type as text/html. @@ -85,7 +85,7 @@ func HTML(w http.ResponseWriter, r *http.Request, v string) { if status, ok := r.Context().Value(StatusCtxKey).(int); ok { w.WriteHeader(status) } - w.Write([]byte(v)) + w.Write([]byte(v)) //nolint:errcheck } // JSON marshals 'v' to JSON, automatically escaping HTML and setting the @@ -103,7 +103,7 @@ func JSON(w http.ResponseWriter, r *http.Request, v interface{}) { if status, ok := r.Context().Value(StatusCtxKey).(int); ok { w.WriteHeader(status) } - w.Write(buf.Bytes()) + w.Write(buf.Bytes()) //nolint:errcheck } // XML marshals 'v' to JSON, setting the Content-Type as application/xml. It @@ -128,10 +128,10 @@ func XML(w http.ResponseWriter, r *http.Request, v interface{}) { } if !bytes.Contains(b[:findHeaderUntil], []byte("