From 121a7d861c8e0fb048aac5a8bc1a644414b16dc3 Mon Sep 17 00:00:00 2001 From: alantong Date: Thu, 6 Dec 2018 15:50:03 +0800 Subject: [PATCH] fix path --- cos.go | 2 +- vendor/go-httpheader/.bumpversion.cfg | 7 + vendor/go-httpheader/.gitignore | 27 ++++ vendor/go-httpheader/.travis.yml | 25 +++ vendor/go-httpheader/CHANGELOG.md | 10 ++ vendor/go-httpheader/LICENSE | 21 +++ vendor/go-httpheader/Makefile | 15 ++ vendor/go-httpheader/README.md | 59 +++++++ vendor/go-httpheader/encode.go | 290 ++++++++++++++++++++++++++++++++++ vendor/go-httpheader/encode_test.go | 282 +++++++++++++++++++++++++++++++++ vendor/go-httpheader/example_test.go | 52 ++++++ 11 files changed, 789 insertions(+), 1 deletion(-) create mode 100644 vendor/go-httpheader/.bumpversion.cfg create mode 100644 vendor/go-httpheader/.gitignore create mode 100644 vendor/go-httpheader/.travis.yml create mode 100644 vendor/go-httpheader/CHANGELOG.md create mode 100644 vendor/go-httpheader/LICENSE create mode 100644 vendor/go-httpheader/Makefile create mode 100644 vendor/go-httpheader/README.md create mode 100644 vendor/go-httpheader/encode.go create mode 100644 vendor/go-httpheader/encode_test.go create mode 100644 vendor/go-httpheader/example_test.go diff --git a/cos.go b/cos.go index 848f8df..353d555 100644 --- a/cos.go +++ b/cos.go @@ -16,7 +16,7 @@ import ( "strconv" "github.com/google/go-querystring/query" - "github.com/tencentyun/go-httpheader" + "github.com/mozillazg/go-httpheader" ) const ( diff --git a/vendor/go-httpheader/.bumpversion.cfg b/vendor/go-httpheader/.bumpversion.cfg new file mode 100644 index 0000000..84453b5 --- /dev/null +++ b/vendor/go-httpheader/.bumpversion.cfg @@ -0,0 +1,7 @@ +[bumpversion] +commit = True +tag = True +current_version = 0.2.0 + +[bumpversion:file:encode.go] + diff --git a/vendor/go-httpheader/.gitignore b/vendor/go-httpheader/.gitignore new file mode 100644 index 0000000..098e254 --- /dev/null +++ b/vendor/go-httpheader/.gitignore @@ -0,0 +1,27 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +*.test +*.prof +dist/ +cover.html +cover.out diff --git a/vendor/go-httpheader/.travis.yml b/vendor/go-httpheader/.travis.yml new file mode 100644 index 0000000..fbb9792 --- /dev/null +++ b/vendor/go-httpheader/.travis.yml @@ -0,0 +1,25 @@ +language: go +go: + - 1.6 + - 1.7 + - 1.8 + - tip + +sudo: false + +before_install: + - go get github.com/mattn/goveralls + +install: + - go get + - go build + +script: + - make test + - $HOME/gopath/bin/goveralls -service=travis-ci -ignore=vendor/ + +matrix: + allow_failures: + - go: 1.6 + - go: 1.7 + - go: tip diff --git a/vendor/go-httpheader/CHANGELOG.md b/vendor/go-httpheader/CHANGELOG.md new file mode 100644 index 0000000..8ca152c --- /dev/null +++ b/vendor/go-httpheader/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +## 0.2.0 (2017-06-24) + +* support http.Header field. + + +## 0.1.0 (2017-06-10) + +* Initial Release diff --git a/vendor/go-httpheader/LICENSE b/vendor/go-httpheader/LICENSE new file mode 100644 index 0000000..8ff7942 --- /dev/null +++ b/vendor/go-httpheader/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 mozillazg + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/go-httpheader/Makefile b/vendor/go-httpheader/Makefile new file mode 100644 index 0000000..aadfe82 --- /dev/null +++ b/vendor/go-httpheader/Makefile @@ -0,0 +1,15 @@ +help: + @echo "test run test" + @echo "lint run lint" + +.PHONY: test +test: + go test -v -cover -coverprofile cover.out + go tool cover -html=cover.out -o cover.html + +.PHONY: lint +lint: + gofmt -s -w . + goimports -w . + golint . + go vet diff --git a/vendor/go-httpheader/README.md b/vendor/go-httpheader/README.md new file mode 100644 index 0000000..36ffeec --- /dev/null +++ b/vendor/go-httpheader/README.md @@ -0,0 +1,59 @@ +# go-httpheader + +go-httpheader is a Go library for encoding structs into Header fields. + + +## install + +`go get -u github.com/tencentyun/go-httpheader` + + +## usage + +```go +package main + +import ( + "fmt" + "net/http" + + "github.com/tencentyun/go-httpheader" +) + +type Options struct { + hide string + ContentType string `header:"Content-Type"` + Length int + XArray []string `header:"X-Array"` + TestHide string `header:"-"` + IgnoreEmpty string `header:"X-Empty,omitempty"` + IgnoreEmptyN string `header:"X-Empty-N,omitempty"` + CustomHeader http.Header +} + +func main() { + opt := Options{ + hide: "hide", + ContentType: "application/json", + Length: 2, + XArray: []string{"test1", "test2"}, + TestHide: "hide", + IgnoreEmptyN: "n", + CustomHeader: http.Header{ + "X-Test-1": []string{"233"}, + "X-Test-2": []string{"666"}, + }, + } + h, _ := httpheader.Header(opt) + fmt.Printf("%#v", h) + // h: + // http.Header{ + // "X-Test-1": []string{"233"}, + // "X-Test-2": []string{"666"}, + // "Content-Type": []string{"application/json"}, + // "Length": []string{"2"}, + // "X-Array": []string{"test1", "test2"}, + // "X-Empty-N": []string{"n"}, + //} +} +``` diff --git a/vendor/go-httpheader/encode.go b/vendor/go-httpheader/encode.go new file mode 100644 index 0000000..510b42b --- /dev/null +++ b/vendor/go-httpheader/encode.go @@ -0,0 +1,290 @@ +// Package query implements encoding of structs into http.Header fields. +// +// As a simple example: +// +// type Options struct { +// ContentType string `header:"Content-Type"` +// Length int +// } +// +// opt := Options{"application/json", 2} +// h, _ := httpheader.Header(opt) +// fmt.Printf("%#v", h) +// // will output: +// // http.Header{"Content-Type":[]string{"application/json"},"Length":[]string{"2"}} +// +// The exact mapping between Go values and http.Header is described in the +// documentation for the Header() function. +package httpheader + +import ( + "fmt" + "net/http" + "reflect" + "strconv" + "strings" + "time" +) + +const tagName = "header" + +// Version ... +const Version = "0.2.0" + +var timeType = reflect.TypeOf(time.Time{}) +var headerType = reflect.TypeOf(http.Header{}) + +var encoderType = reflect.TypeOf(new(Encoder)).Elem() + +// Encoder is an interface implemented by any type that wishes to encode +// itself into Header fields in a non-standard way. +type Encoder interface { + EncodeHeader(key string, v *http.Header) error +} + +// Header returns the http.Header encoding of v. +// +// Header expects to be passed a struct, and traverses it recursively using the +// following encoding rules. +// +// Each exported struct field is encoded as a Header field unless +// +// - the field's tag is "-", or +// - the field is empty and its tag specifies the "omitempty" option +// +// The empty values are false, 0, any nil pointer or interface value, any array +// slice, map, or string of length zero, and any time.Time that returns true +// for IsZero(). +// +// The Header field name defaults to the struct field name but can be +// specified in the struct field's tag value. The "header" key in the struct +// field's tag value is the key name, followed by an optional comma and +// options. For example: +// +// // Field is ignored by this package. +// Field int `header:"-"` +// +// // Field appears as Header field "X-Name". +// Field int `header:"X-Name"` +// +// // Field appears as Header field "X-Name" and the field is omitted if +// // its value is empty +// Field int `header:"X-Name,omitempty"` +// +// // Field appears as Header field "Field" (the default), but the field +// // is skipped if empty. Note the leading comma. +// Field int `header:",omitempty"` +// +// For encoding individual field values, the following type-dependent rules +// apply: +// +// Boolean values default to encoding as the strings "true" or "false". +// Including the "int" option signals that the field should be encoded as the +// strings "1" or "0". +// +// time.Time values default to encoding as RFC1123("Mon, 02 Jan 2006 15:04:05 GMT") +// timestamps. Including the "unix" option signals that the field should be +// encoded as a Unix time (see time.Unix()) +// +// Slice and Array values default to encoding as multiple Header values of the +// same name. example: +// X-Name: []string{"Tom", "Jim"}, etc. +// +// http.Header values will be used to extend the Header fields. +// +// Anonymous struct fields are usually encoded as if their inner exported +// fields were fields in the outer struct, subject to the standard Go +// visibility rules. An anonymous struct field with a name given in its Header +// tag is treated as having that name, rather than being anonymous. +// +// Non-nil pointer values are encoded as the value pointed to. +// +// All other values are encoded using their default string representation. +// +// Multiple fields that encode to the same Header filed name will be included +// as multiple Header values of the same name. +func Header(v interface{}) (http.Header, error) { + h := make(http.Header) + val := reflect.ValueOf(v) + for val.Kind() == reflect.Ptr { + if val.IsNil() { + return h, nil + } + val = val.Elem() + } + + if v == nil { + return h, nil + } + + if val.Kind() != reflect.Struct { + return nil, fmt.Errorf("httpheader: Header() expects struct input. Got %v", val.Kind()) + } + + err := reflectValue(h, val) + return h, err +} + +// reflectValue populates the header fields from the struct fields in val. +// Embedded structs are followed recursively (using the rules defined in the +// Values function documentation) breadth-first. +func reflectValue(header http.Header, val reflect.Value) error { + var embedded []reflect.Value + + typ := val.Type() + for i := 0; i < typ.NumField(); i++ { + sf := typ.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { // unexported + continue + } + + sv := val.Field(i) + tag := sf.Tag.Get(tagName) + if tag == "-" { + continue + } + name, opts := parseTag(tag) + if name == "" { + if sf.Anonymous && sv.Kind() == reflect.Struct { + // save embedded struct for later processing + embedded = append(embedded, sv) + continue + } + + name = sf.Name + } + + if opts.Contains("omitempty") && isEmptyValue(sv) { + continue + } + + if sv.Type().Implements(encoderType) { + if !reflect.Indirect(sv).IsValid() { + sv = reflect.New(sv.Type().Elem()) + } + + m := sv.Interface().(Encoder) + if err := m.EncodeHeader(name, &header); err != nil { + return err + } + continue + } + + if sv.Kind() == reflect.Slice || sv.Kind() == reflect.Array { + for i := 0; i < sv.Len(); i++ { + k := name + header.Add(k, valueString(sv.Index(i), opts)) + } + continue + } + + for sv.Kind() == reflect.Ptr { + if sv.IsNil() { + break + } + sv = sv.Elem() + } + + if sv.Type() == timeType { + header.Add(name, valueString(sv, opts)) + continue + } + if sv.Type() == headerType { + h := sv.Interface().(http.Header) + for k, vs := range h { + for _, v := range vs { + header.Add(k, v) + } + } + continue + } + + if sv.Kind() == reflect.Struct { + reflectValue(header, sv) + continue + } + + header.Add(name, valueString(sv, opts)) + } + + for _, f := range embedded { + if err := reflectValue(header, f); err != nil { + return err + } + } + + return nil +} + +// valueString returns the string representation of a value. +func valueString(v reflect.Value, opts tagOptions) string { + for v.Kind() == reflect.Ptr { + if v.IsNil() { + return "" + } + v = v.Elem() + } + + if v.Kind() == reflect.Bool && opts.Contains("int") { + if v.Bool() { + return "1" + } + return "0" + } + + if v.Type() == timeType { + t := v.Interface().(time.Time) + if opts.Contains("unix") { + return strconv.FormatInt(t.Unix(), 10) + } + return t.Format(http.TimeFormat) + } + + return fmt.Sprint(v.Interface()) +} + +// isEmptyValue checks if a value should be considered empty for the purposes +// of omitting fields with the "omitempty" option. +func isEmptyValue(v reflect.Value) bool { + switch 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.Interface, reflect.Ptr: + return v.IsNil() + } + + if v.Type() == timeType { + return v.Interface().(time.Time).IsZero() + } + + return false +} + +// tagOptions is the string following a comma in a struct field's "header" tag, or +// the empty string. It does not include the leading comma. +type tagOptions []string + +// parseTag splits a struct field's header tag into its name and comma-separated +// options. +func parseTag(tag string) (string, tagOptions) { + s := strings.Split(tag, ",") + return s[0], s[1:] +} + +// Contains checks whether the tagOptions contains the specified option. +func (o tagOptions) Contains(option string) bool { + for _, s := range o { + if s == option { + return true + } + } + return false +} diff --git a/vendor/go-httpheader/encode_test.go b/vendor/go-httpheader/encode_test.go new file mode 100644 index 0000000..91eaf34 --- /dev/null +++ b/vendor/go-httpheader/encode_test.go @@ -0,0 +1,282 @@ +package httpheader + +import ( + "fmt" + "net/http" + "reflect" + "testing" + "time" +) + +func TestHeader_types(t *testing.T) { + str := "string" + strPtr := &str + timeVal := time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC) + + tests := []struct { + in interface{} + want http.Header + }{ + { + // basic primitives + struct { + A string + B int + C uint + D float32 + E bool + }{}, + http.Header{ + "A": []string{""}, + "B": []string{"0"}, + "C": []string{"0"}, + "D": []string{"0"}, + "E": []string{"false"}, + }, + }, + { + // pointers + struct { + A *string + B *int + C **string + D *time.Time + }{ + A: strPtr, + C: &strPtr, + D: &timeVal, + }, + http.Header{ + "A": []string{str}, + "B": []string{""}, + "C": []string{str}, + "D": []string{"Sat, 01 Jan 2000 12:34:56 GMT"}, + }, + }, + { + // slices and arrays + struct { + A []string + B []*string + C [2]string + D []bool `header:",int"` + }{ + A: []string{"a", "b"}, + B: []*string{&str, &str}, + C: [2]string{"a", "b"}, + D: []bool{true, false}, + }, + http.Header{ + "A": []string{"a", "b"}, + "B": {"string", "string"}, + "C": []string{"a", "b"}, + "D": {"1", "0"}, + }, + }, + { + // other types + struct { + A time.Time + B time.Time `header:",unix"` + C bool `header:",int"` + D bool `header:",int"` + E http.Header + }{ + A: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC), + B: time.Date(2000, 1, 1, 12, 34, 56, 0, time.UTC), + C: true, + D: false, + E: http.Header{ + "F": []string{"f1"}, + "G": []string{"gg"}, + }, + }, + http.Header{ + "A": []string{"Sat, 01 Jan 2000 12:34:56 GMT"}, + "B": []string{"946730096"}, + "C": []string{"1"}, + "D": []string{"0"}, + "F": []string{"f1"}, + "G": []string{"gg"}, + }, + }, + { + nil, + http.Header{}, + }, + { + &struct { + A string + }{"test"}, + http.Header{ + "A": []string{"test"}, + }, + }, + } + + for i, tt := range tests { + v, err := Header(tt.in) + if err != nil { + t.Errorf("%d. Header(%q) returned error: %v", i, tt.in, err) + } + + if !reflect.DeepEqual(tt.want, v) { + t.Errorf("%d. Header(%q) returned %#v, want %#v", i, tt.in, v, tt.want) + } + } +} + +func TestHeader_omitEmpty(t *testing.T) { + str := "" + s := struct { + a string + A string + B string `header:",omitempty"` + C string `header:"-"` + D string `header:"omitempty"` // actually named omitempty, not an option + E *string `header:",omitempty"` + F bool `header:",omitempty"` + G int `header:",omitempty"` + H uint `header:",omitempty"` + I float32 `header:",omitempty"` + J time.Time `header:",omitempty"` + K struct{} `header:",omitempty"` + }{E: &str} + + v, err := Header(s) + if err != nil { + t.Errorf("Header(%#v) returned error: %v", s, err) + } + + want := http.Header{ + "A": []string{""}, + "Omitempty": []string{""}, + "E": []string{""}, // E is included because the pointer is not empty, even though the string being pointed to is + } + if !reflect.DeepEqual(want, v) { + t.Errorf("Header(%#v) returned %v, want %v", s, v, want) + } +} + +type A struct { + B +} + +type B struct { + C string +} + +type D struct { + B + C string +} + +type e struct { + B + C string +} + +type F struct { + e +} + +func TestHeader_embeddedStructs(t *testing.T) { + tests := []struct { + in interface{} + want http.Header + }{ + { + A{B{C: "foo"}}, + http.Header{"C": []string{"foo"}}, + }, + { + D{B: B{C: "bar"}, C: "foo"}, + http.Header{"C": []string{"foo", "bar"}}, + }, + { + F{e{B: B{C: "bar"}, C: "foo"}}, // With unexported embed + http.Header{"C": []string{"foo", "bar"}}, + }, + } + + for i, tt := range tests { + v, err := Header(tt.in) + if err != nil { + t.Errorf("%d. Header(%q) returned error: %v", i, tt.in, err) + } + + if !reflect.DeepEqual(tt.want, v) { + t.Errorf("%d. Header(%q) returned %v, want %v", i, tt.in, v, tt.want) + } + } +} + +func TestHeader_invalidInput(t *testing.T) { + _, err := Header("") + if err == nil { + t.Errorf("expected Header() to return an error on invalid input") + } +} + +type EncodedArgs []string + +func (m EncodedArgs) EncodeHeader(key string, v *http.Header) error { + for i, arg := range m { + v.Set(fmt.Sprintf("%s.%d", key, i), arg) + } + return nil +} + +func TestHeader_Marshaler(t *testing.T) { + s := struct { + Args EncodedArgs `header:"arg"` + }{[]string{"a", "b", "c"}} + v, err := Header(s) + if err != nil { + t.Errorf("Header(%q) returned error: %v", s, err) + } + + want := http.Header{ + "Arg.0": []string{"a"}, + "Arg.1": []string{"b"}, + "Arg.2": []string{"c"}, + } + if !reflect.DeepEqual(want, v) { + t.Errorf("Header(%q) returned %v, want %v", s, v, want) + } +} + +func TestHeader_MarshalerWithNilPointer(t *testing.T) { + s := struct { + Args *EncodedArgs `header:"arg"` + }{} + v, err := Header(s) + if err != nil { + t.Errorf("Header(%q) returned error: %v", s, err) + } + + want := http.Header{} + if !reflect.DeepEqual(want, v) { + t.Errorf("Header(%q) returned %v, want %v", s, v, want) + } +} + +func TestTagParsing(t *testing.T) { + name, opts := parseTag("field,foobar,foo") + if name != "field" { + t.Fatalf("name = %q, want field", name) + } + for _, tt := range []struct { + opt string + want bool + }{ + {"foobar", true}, + {"foo", true}, + {"bar", false}, + {"field", false}, + } { + if opts.Contains(tt.opt) != tt.want { + t.Errorf("Contains(%q) = %v", tt.opt, !tt.want) + } + } +} diff --git a/vendor/go-httpheader/example_test.go b/vendor/go-httpheader/example_test.go new file mode 100644 index 0000000..03eb3d1 --- /dev/null +++ b/vendor/go-httpheader/example_test.go @@ -0,0 +1,52 @@ +package httpheader_test + +import ( + "fmt" + "net/http" + + "github.com/tencentyun/go-httpheader" +) + +func ExampleHeader() { + type Options struct { + ContentType string `header:"Content-Type"` + Length int + XArray []string `header:"X-Array"` + TestHide string `header:"-"` + IgnoreEmpty string `header:"X-Empty,omitempty"` + IgnoreEmptyN string `header:"X-Empty-N,omitempty"` + CustomHeader http.Header + } + + opt := Options{ + ContentType: "application/json", + Length: 2, + XArray: []string{"test1", "test2"}, + TestHide: "hide", + IgnoreEmptyN: "n", + CustomHeader: http.Header{ + "X-Test-1": []string{"233"}, + "X-Test-2": []string{"666"}, + }, + } + h, _ := httpheader.Header(opt) + fmt.Println(h["Content-Type"]) + fmt.Println(h["Length"]) + fmt.Println(h["X-Array"]) + _, ok := h["TestHide"] + fmt.Println(ok) + _, ok = h["X-Empty"] + fmt.Println(ok) + fmt.Println(h["X-Empty-N"]) + fmt.Println(h["X-Test-1"]) + fmt.Println(h["X-Test-2"]) + // Output: + // [application/json] + // [2] + // [test1 test2] + // false + // false + // [n] + // [233] + // [666] +}