From 36b51a851e90735f11f13f136f68e91d494c9ec8 Mon Sep 17 00:00:00 2001 From: andrewsykim Date: Sun, 9 Jul 2017 23:42:26 -0400 Subject: [PATCH] vendor github.com/tent/http-link-go --- .gitmodules | 3 + _vendor/github.com/tent/http-link-go | 1 + .../github.com/tent/http-link-go/.gitignore | 1 + .../github.com/tent/http-link-go/.travis.yml | 6 + vendor/github.com/tent/http-link-go/LICENSE | 27 +++ vendor/github.com/tent/http-link-go/README.md | 12 ++ vendor/github.com/tent/http-link-go/link.go | 185 ++++++++++++++++++ .../github.com/tent/http-link-go/link_test.go | 67 +++++++ 8 files changed, 302 insertions(+) create mode 160000 _vendor/github.com/tent/http-link-go create mode 100644 vendor/github.com/tent/http-link-go/.gitignore create mode 100644 vendor/github.com/tent/http-link-go/.travis.yml create mode 100644 vendor/github.com/tent/http-link-go/LICENSE create mode 100644 vendor/github.com/tent/http-link-go/README.md create mode 100644 vendor/github.com/tent/http-link-go/link.go create mode 100644 vendor/github.com/tent/http-link-go/link_test.go diff --git a/.gitmodules b/.gitmodules index ae5a466f8b..c50fe13195 100644 --- a/.gitmodules +++ b/.gitmodules @@ -319,3 +319,6 @@ [submodule "_vendor/github.com/google/go-querystring"] path = _vendor/github.com/google/go-querystring url = https://github.com/google/go-querystring.git +[submodule "_vendor/github.com/tent/http-link-go"] + path = _vendor/github.com/tent/http-link-go + url = https://github.com/tent/http-link-go.git diff --git a/_vendor/github.com/tent/http-link-go b/_vendor/github.com/tent/http-link-go new file mode 160000 index 0000000000..ac974c61c2 --- /dev/null +++ b/_vendor/github.com/tent/http-link-go @@ -0,0 +1 @@ +Subproject commit ac974c61c2f990f4115b119354b5e0b47550e888 diff --git a/vendor/github.com/tent/http-link-go/.gitignore b/vendor/github.com/tent/http-link-go/.gitignore new file mode 100644 index 0000000000..9ed3b07cef --- /dev/null +++ b/vendor/github.com/tent/http-link-go/.gitignore @@ -0,0 +1 @@ +*.test diff --git a/vendor/github.com/tent/http-link-go/.travis.yml b/vendor/github.com/tent/http-link-go/.travis.yml new file mode 100644 index 0000000000..7362f08e4c --- /dev/null +++ b/vendor/github.com/tent/http-link-go/.travis.yml @@ -0,0 +1,6 @@ +language: go +go: + - 1.1 + - tip +before_install: + - go get launchpad.net/gocheck diff --git a/vendor/github.com/tent/http-link-go/LICENSE b/vendor/github.com/tent/http-link-go/LICENSE new file mode 100644 index 0000000000..88dcd4afd0 --- /dev/null +++ b/vendor/github.com/tent/http-link-go/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) 2013 Tent.is, LLC. 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 Tent.is, LLC 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/tent/http-link-go/README.md b/vendor/github.com/tent/http-link-go/README.md new file mode 100644 index 0000000000..07d470e4d9 --- /dev/null +++ b/vendor/github.com/tent/http-link-go/README.md @@ -0,0 +1,12 @@ +# http-link-go [![Build Status](https://travis-ci.org/tent/http-link-go.png?branch=master)](https://travis-ci.org/tent/http-link-go) + +http-link-go implements parsing and serialization of Link header values as +defined in [RFC 5988](https://tools.ietf.org/html/rfc5988). + +[**Documentation**](http://godoc.org/github.com/tent/http-link-go) + +## Installation + +```text +go get github.com/tent/http-link-go +``` diff --git a/vendor/github.com/tent/http-link-go/link.go b/vendor/github.com/tent/http-link-go/link.go new file mode 100644 index 0000000000..584dfd0515 --- /dev/null +++ b/vendor/github.com/tent/http-link-go/link.go @@ -0,0 +1,185 @@ +// Package link implements parsing and serialization of Link header values as +// defined in RFC 5988. +package link + +import ( + "bytes" + "errors" + "sort" + "unicode" +) + +type Link struct { + URI string + Rel string + Params map[string]string +} + +// Format serializes a slice of Links into a header value. It does not currently +// implement RFC 2231 handling of non-ASCII character encoding and language +// information. +func Format(links []Link) string { + buf := &bytes.Buffer{} + for i, link := range links { + if i > 0 { + buf.Write([]byte(", ")) + } + buf.WriteByte('<') + buf.WriteString(link.URI) + buf.WriteByte('>') + + writeParam(buf, "rel", link.Rel) + + keys := make([]string, 0, len(link.Params)) + for k := range link.Params { + keys = append(keys, k) + } + sort.Strings(keys) + + for _, k := range keys { + writeParam(buf, k, link.Params[k]) + } + } + + return buf.String() +} + +func writeParam(buf *bytes.Buffer, key, value string) { + buf.Write([]byte("; ")) + buf.WriteString(key) + buf.Write([]byte(`="`)) + buf.WriteString(value) + buf.WriteByte('"') +} + +// Parse parses a Link header value into a slice of Links. It does not currently +// implement RFC 2231 handling of non-ASCII character encoding and language +// information. +func Parse(l string) ([]Link, error) { + v := []byte(l) + v = bytes.TrimSpace(v) + if len(v) == 0 { + return nil, nil + } + + links := make([]Link, 0, 1) + for len(v) > 0 { + if v[0] != '<' { + return nil, errors.New("link: does not start with <") + } + lend := bytes.IndexByte(v, '>') + if lend == -1 { + return nil, errors.New("link: does not contain ending >") + } + + params := make(map[string]string) + link := Link{URI: string(v[1:lend]), Params: params} + links = append(links, link) + + // trim off parsed url + v = v[lend+1:] + if len(v) == 0 { + break + } + v = bytes.TrimLeftFunc(v, unicode.IsSpace) + + for len(v) > 0 { + if v[0] != ';' && v[0] != ',' { + return nil, errors.New(`link: expected ";" or "'", got "` + string(v[0:1]) + `"`) + } + var next bool + if v[0] == ',' { + next = true + } + v = bytes.TrimLeftFunc(v[1:], unicode.IsSpace) + if next || len(v) == 0 { + break + } + var key, value []byte + key, value, v = consumeParam(v) + if key == nil || value == nil { + return nil, errors.New("link: malformed param") + } + if k := string(key); k == "rel" { + if links[len(links)-1].Rel == "" { + links[len(links)-1].Rel = string(value) + } + } else { + params[k] = string(value) + } + v = bytes.TrimLeftFunc(v, unicode.IsSpace) + } + } + + return links, nil +} + +func isTokenChar(r rune) bool { + return r > 0x20 && r < 0x7f && r != '"' && r != ',' && r != '=' && r != ';' +} + +func isNotTokenChar(r rune) bool { return !isTokenChar(r) } + +func consumeToken(v []byte) (token, rest []byte) { + notPos := bytes.IndexFunc(v, isNotTokenChar) + if notPos == -1 { + return v, nil + } + if notPos == 0 { + return nil, v + } + return v[0:notPos], v[notPos:] +} + +func consumeValue(v []byte) (value, rest []byte) { + if v[0] != '"' { + return nil, v + } + + rest = v[1:] + buffer := &bytes.Buffer{} + var nextIsLiteral bool + for idx, r := range string(rest) { + switch { + case nextIsLiteral: + buffer.WriteRune(r) + nextIsLiteral = false + case r == '"': + return buffer.Bytes(), rest[idx+1:] + case r == '\\': + nextIsLiteral = true + case r != '\r' && r != '\n': + buffer.WriteRune(r) + default: + return nil, v + } + } + return nil, v +} + +func consumeParam(v []byte) (param, value, rest []byte) { + param, rest = consumeToken(v) + param = bytes.ToLower(param) + if param == nil { + return nil, nil, v + } + + rest = bytes.TrimLeftFunc(rest, unicode.IsSpace) + if len(rest) == 0 || rest[0] != '=' { + return nil, nil, v + } + rest = rest[1:] // consume equals sign + rest = bytes.TrimLeftFunc(rest, unicode.IsSpace) + if len(rest) == 0 { + return nil, nil, v + } + if rest[0] != '"' { + value, rest = consumeToken(rest) + } else { + value, rest = consumeValue(rest) + } + if value == nil { + return nil, nil, v + } + return param, value, rest +} diff --git a/vendor/github.com/tent/http-link-go/link_test.go b/vendor/github.com/tent/http-link-go/link_test.go new file mode 100644 index 0000000000..8a78eeabb8 --- /dev/null +++ b/vendor/github.com/tent/http-link-go/link_test.go @@ -0,0 +1,67 @@ +package link + +import ( + "testing" + + . "launchpad.net/gocheck" +) + +// Hook up gocheck into the "go test" runner. +func Test(t *testing.T) { TestingT(t) } + +type LinkSuite struct{} + +var _ = Suite(&LinkSuite{}) + +// TODO: add more tests +var linkParseTests = []struct { + in string + out []Link +}{ + { + "; rel=\"previous\";\n title=\"previous chapter\"", + []Link{{URI: "http://example.com/TheBook/chapter2", Rel: "previous", Params: map[string]string{"title": "previous chapter"}}}, + }, + { + ";\n rel=\"previous\"; title*=UTF-8'de'letztes%20Kapitel,\n ;\n rel=\"next\"; title*=UTF-8'de'n%c3%a4chstes%20Kapitel", + []Link{ + {URI: "/TheBook/chapter2", Rel: "previous", Params: map[string]string{"title*": "UTF-8'de'letztes%20Kapitel"}}, + {URI: "/TheBook/chapter4", Rel: "next", Params: map[string]string{"title*": "UTF-8'de'n%c3%a4chstes%20Kapitel"}}, + }, + }, +} + +func (s *LinkSuite) TestLinkParsing(c *C) { + for i, t := range linkParseTests { + res, err := Parse(t.in) + c.Assert(err, IsNil, Commentf("test %d", i)) + c.Assert(res, DeepEquals, t.out, Commentf("test %d", i)) + } +} + +var linkFormatTests = []struct { + in []Link + out string +}{ + { + []Link{{URI: "/a", Rel: "foo", Params: map[string]string{"a": "b", "c": "d"}}}, + `; rel="foo"; a="b"; c="d"`, + }, + { + []Link{ + {URI: "/b", Rel: "foo", Params: map[string]string{"a": "b", "c": "d"}}, + {URI: "/a", Rel: "foo", Params: map[string]string{"a": "b", "c": "d"}}}, + `; rel="foo"; a="b"; c="d", ; rel="foo"; a="b"; c="d"`, + }, +} + +func (s *LinkSuite) TestLinkGeneration(c *C) { + for i, t := range linkFormatTests { + res := Format(t.in) + cm := Commentf("test %d", i) + c.Assert(res, Equals, t.out, cm) + parsed, err := Parse(res) + c.Assert(err, IsNil, cm) + c.Assert(parsed, DeepEquals, t.in, cm) + } +}