From 961c04cae992eadb42d286d2f85f8a675bdc68c8 Mon Sep 17 00:00:00 2001 From: Christopher Speller Date: Mon, 29 Jan 2018 14:17:40 -0800 Subject: Upgrading server dependancies (#8154) --- vendor/github.com/NYTimes/gziphandler/gzip.go | 2 +- vendor/github.com/NYTimes/gziphandler/gzip_test.go | 19 +- vendor/github.com/avct/uasurfer/.gitignore | 56 - vendor/github.com/avct/uasurfer/.travis.yml | 11 - vendor/github.com/avct/uasurfer/LICENSE | 192 - vendor/github.com/avct/uasurfer/README.md | 169 - vendor/github.com/avct/uasurfer/browser.go | 192 - vendor/github.com/avct/uasurfer/const_string.go | 49 - vendor/github.com/avct/uasurfer/device.go | 60 - vendor/github.com/avct/uasurfer/system.go | 332 - vendor/github.com/avct/uasurfer/uasurfer.go | 227 - vendor/github.com/avct/uasurfer/uasurfer_test.go | 1064 --- vendor/github.com/cpanato/html2text/.gitignore | 24 - vendor/github.com/cpanato/html2text/.travis.yml | 14 - vendor/github.com/cpanato/html2text/LICENSE | 23 - vendor/github.com/cpanato/html2text/README.md | 108 - vendor/github.com/cpanato/html2text/html2text.go | 312 - .../github.com/cpanato/html2text/html2text_test.go | 674 -- .../cpanato/html2text/testdata/utf8.html | 22 - .../cpanato/html2text/testdata/utf8_with_bom.xhtml | 24 - vendor/github.com/davecgh/go-spew/.travis.yml | 27 +- vendor/github.com/davecgh/go-spew/LICENSE | 4 +- vendor/github.com/davecgh/go-spew/README.md | 21 +- vendor/github.com/davecgh/go-spew/spew/bypass.go | 8 +- .../github.com/davecgh/go-spew/spew/bypasssafe.go | 2 +- vendor/github.com/davecgh/go-spew/spew/common.go | 4 +- .../github.com/davecgh/go-spew/spew/common_test.go | 2 +- vendor/github.com/davecgh/go-spew/spew/config.go | 11 +- vendor/github.com/davecgh/go-spew/spew/doc.go | 11 +- vendor/github.com/davecgh/go-spew/spew/dump.go | 18 +- .../github.com/davecgh/go-spew/spew/dump_test.go | 4 +- .../davecgh/go-spew/spew/dumpcgo_test.go | 8 +- .../davecgh/go-spew/spew/example_test.go | 2 +- vendor/github.com/davecgh/go-spew/spew/format.go | 6 +- .../github.com/davecgh/go-spew/spew/format_test.go | 8 +- .../davecgh/go-spew/spew/internal_test.go | 7 +- .../davecgh/go-spew/spew/internalunsafe_test.go | 2 +- vendor/github.com/davecgh/go-spew/spew/spew.go | 2 +- .../github.com/davecgh/go-spew/spew/spew_test.go | 13 +- .../github.com/disintegration/imaging/helpers.go | 43 +- vendor/github.com/fsnotify/fsnotify/.travis.yml | 4 +- vendor/github.com/fsnotify/fsnotify/AUTHORS | 6 + vendor/github.com/fsnotify/fsnotify/CHANGELOG.md | 16 +- .../github.com/fsnotify/fsnotify/CONTRIBUTING.md | 6 +- vendor/github.com/fsnotify/fsnotify/README.md | 37 +- vendor/github.com/fsnotify/fsnotify/fsnotify.go | 4 + .../github.com/fsnotify/fsnotify/fsnotify_test.go | 32 +- vendor/github.com/fsnotify/fsnotify/inotify.go | 66 +- .../github.com/fsnotify/fsnotify/inotify_test.go | 109 +- .../fsnotify/fsnotify/integration_darwin_test.go | 4 +- vendor/github.com/fsnotify/fsnotify/kqueue.go | 62 +- vendor/github.com/go-ldap/ldap/.travis.yml | 6 +- vendor/github.com/go-ldap/ldap/Makefile | 12 +- vendor/github.com/go-ldap/ldap/atomic_value.go | 13 + .../github.com/go-ldap/ldap/atomic_value_go13.go | 28 + vendor/github.com/go-ldap/ldap/conn.go | 73 +- vendor/github.com/go-ldap/ldap/conn_test.go | 10 +- vendor/github.com/go-ldap/ldap/debug.go | 2 +- vendor/github.com/go-ldap/ldap/dn.go | 7 +- vendor/github.com/go-ldap/ldap/dn_test.go | 12 +- vendor/github.com/go-ldap/ldap/error.go | 7 + vendor/github.com/go-ldap/ldap/error_test.go | 4 +- vendor/github.com/go-ldap/ldap/example_test.go | 12 +- vendor/github.com/go-ldap/ldap/filter.go | 5 +- vendor/github.com/go-ldap/ldap/filter_test.go | 6 + vendor/github.com/go-ldap/ldap/ldap.go | 2 +- vendor/github.com/go-ldap/ldap/passwdmodify.go | 8 +- vendor/github.com/go-ldap/ldap/search_test.go | 6 +- vendor/github.com/go-redis/redis/.travis.yml | 2 - vendor/github.com/go-redis/redis/README.md | 5 +- vendor/github.com/go-redis/redis/cluster.go | 76 +- vendor/github.com/go-redis/redis/cluster_test.go | 26 + vendor/github.com/go-redis/redis/command.go | 42 +- vendor/github.com/go-redis/redis/commands.go | 10 + vendor/github.com/go-redis/redis/commands_test.go | 11 + vendor/github.com/go-redis/redis/example_test.go | 4 +- .../go-redis/redis/internal/hashtag/hashtag.go | 8 +- .../go-redis/redis/internal/proto/scan.go | 5 +- vendor/github.com/go-redis/redis/internal/safe.go | 4 - .../github.com/go-redis/redis/internal/unsafe.go | 19 +- vendor/github.com/go-redis/redis/options_test.go | 2 +- vendor/github.com/go-redis/redis/parser.go | 14 + vendor/github.com/go-redis/redis/redis.go | 2 +- vendor/github.com/go-redis/redis/ring.go | 9 +- vendor/github.com/go-redis/redis/universal.go | 2 + vendor/github.com/go-sql-driver/mysql/.gitignore | 1 + vendor/github.com/go-sql-driver/mysql/.travis.yml | 93 +- .../go-sql-driver/mysql/.travis/docker.cnf | 5 + .../go-sql-driver/mysql/.travis/wait_mysql.sh | 8 + vendor/github.com/go-sql-driver/mysql/AUTHORS | 27 + vendor/github.com/go-sql-driver/mysql/README.md | 113 +- vendor/github.com/go-sql-driver/mysql/appengine.go | 2 +- .../go-sql-driver/mysql/benchmark_go18_test.go | 93 + .../go-sql-driver/mysql/benchmark_test.go | 6 +- .../github.com/go-sql-driver/mysql/collations.go | 1 + .../github.com/go-sql-driver/mysql/connection.go | 148 +- .../go-sql-driver/mysql/connection_go18.go | 202 + .../go-sql-driver/mysql/connection_go18_test.go | 30 + vendor/github.com/go-sql-driver/mysql/const.go | 9 +- vendor/github.com/go-sql-driver/mysql/driver.go | 14 +- .../go-sql-driver/mysql/driver_go18_test.go | 798 ++ .../github.com/go-sql-driver/mysql/driver_test.go | 308 +- vendor/github.com/go-sql-driver/mysql/dsn.go | 132 +- vendor/github.com/go-sql-driver/mysql/dsn_test.go | 86 +- vendor/github.com/go-sql-driver/mysql/errors.go | 79 +- vendor/github.com/go-sql-driver/mysql/fields.go | 194 + vendor/github.com/go-sql-driver/mysql/infile.go | 3 +- vendor/github.com/go-sql-driver/mysql/packets.go | 213 +- .../github.com/go-sql-driver/mysql/packets_test.go | 24 +- vendor/github.com/go-sql-driver/mysql/rows.go | 174 +- vendor/github.com/go-sql-driver/mysql/statement.go | 85 +- .../go-sql-driver/mysql/statement_test.go | 126 + .../github.com/go-sql-driver/mysql/transaction.go | 4 +- vendor/github.com/go-sql-driver/mysql/utils.go | 84 +- .../github.com/go-sql-driver/mysql/utils_go17.go | 40 + .../github.com/go-sql-driver/mysql/utils_go18.go | 49 + .../go-sql-driver/mysql/utils_go18_test.go | 54 + .../github.com/go-sql-driver/mysql/utils_test.go | 80 + vendor/github.com/golang/protobuf/jsonpb/jsonpb.go | 3 +- .../golang/protobuf/jsonpb/jsonpb_test.go | 1 - vendor/github.com/golang/protobuf/proto/discard.go | 151 + vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md | 11 + vendor/github.com/gorilla/mux/README.md | 209 +- vendor/github.com/gorilla/mux/doc.go | 65 + .../github.com/gorilla/mux/example_route_test.go | 51 + vendor/github.com/gorilla/mux/middleware.go | 28 + vendor/github.com/gorilla/mux/middleware_test.go | 336 + vendor/github.com/gorilla/mux/mux.go | 20 +- vendor/github.com/gorilla/mux/mux_test.go | 314 +- vendor/github.com/gorilla/mux/old_test.go | 2 +- vendor/github.com/gorilla/mux/regexp.go | 74 +- vendor/github.com/gorilla/mux/route.go | 26 +- vendor/github.com/gorilla/mux/test_helpers.go | 18 + vendor/github.com/gorilla/websocket/.travis.yml | 1 + vendor/github.com/gorilla/websocket/client.go | 140 +- .../gorilla/websocket/client_server_test.go | 124 +- vendor/github.com/gorilla/websocket/client_test.go | 40 - vendor/github.com/gorilla/websocket/conn.go | 44 +- vendor/github.com/gorilla/websocket/conn_test.go | 3 +- vendor/github.com/gorilla/websocket/doc.go | 56 +- .../gorilla/websocket/examples/chat/README.md | 2 +- .../gorilla/websocket/examples/chat/client.go | 4 +- .../gorilla/websocket/examples/echo/server.go | 1 + vendor/github.com/gorilla/websocket/json.go | 11 +- vendor/github.com/gorilla/websocket/mask.go | 1 - vendor/github.com/gorilla/websocket/proxy.go | 77 + vendor/github.com/gorilla/websocket/server.go | 39 +- vendor/github.com/gorilla/websocket/server_test.go | 18 + vendor/github.com/gorilla/websocket/util.go | 33 +- vendor/github.com/gorilla/websocket/util_test.go | 49 +- vendor/github.com/gorilla/websocket/x_net_proxy.go | 473 ++ .../hashicorp/go-immutable-radix/iradix_test.go | 12 +- vendor/github.com/lib/pq/conn.go | 10 + vendor/github.com/lib/pq/conn_test.go | 58 +- vendor/github.com/lib/pq/error.go | 1 + vendor/github.com/lib/pq/notify.go | 4 +- vendor/github.com/mailru/easyjson/.gitignore | 4 + vendor/github.com/mailru/easyjson/.travis.yml | 9 + vendor/github.com/mailru/easyjson/LICENSE | 7 + vendor/github.com/mailru/easyjson/Makefile | 56 + vendor/github.com/mailru/easyjson/README.md | 331 + .../mailru/easyjson/benchmark/codec_test.go | 279 + .../github.com/mailru/easyjson/benchmark/data.go | 148 + .../mailru/easyjson/benchmark/data_codec.go | 6914 ++++++++++++++++++ .../mailru/easyjson/benchmark/data_ffjson.go | 6723 +++++++++++++++++ .../mailru/easyjson/benchmark/data_var.go | 350 + .../mailru/easyjson/benchmark/default_test.go | 118 + .../mailru/easyjson/benchmark/dummy_test.go | 11 + .../mailru/easyjson/benchmark/easyjson_test.go | 184 + .../mailru/easyjson/benchmark/example.json | 415 ++ .../mailru/easyjson/benchmark/ffjson_test.go | 190 + .../mailru/easyjson/benchmark/jsoniter_test.go | 119 + .../github.com/mailru/easyjson/benchmark/ujson.sh | 7 + .../mailru/easyjson/bootstrap/bootstrap.go | 188 + vendor/github.com/mailru/easyjson/buffer/pool.go | 270 + .../github.com/mailru/easyjson/buffer/pool_test.go | 107 + vendor/github.com/mailru/easyjson/easyjson/main.go | 106 + vendor/github.com/mailru/easyjson/gen/decoder.go | 489 ++ vendor/github.com/mailru/easyjson/gen/encoder.go | 382 + vendor/github.com/mailru/easyjson/gen/generator.go | 523 ++ .../mailru/easyjson/gen/generator_test.go | 87 + vendor/github.com/mailru/easyjson/helpers.go | 78 + .../mailru/easyjson/jlexer/bytestostr.go | 24 + .../mailru/easyjson/jlexer/bytestostr_nounsafe.go | 13 + vendor/github.com/mailru/easyjson/jlexer/error.go | 15 + vendor/github.com/mailru/easyjson/jlexer/lexer.go | 1141 +++ .../mailru/easyjson/jlexer/lexer_test.go | 311 + .../github.com/mailru/easyjson/jwriter/writer.go | 377 + .../mailru/easyjson/opt/gotemplate_Bool.go | 79 + .../mailru/easyjson/opt/gotemplate_Float32.go | 79 + .../mailru/easyjson/opt/gotemplate_Float64.go | 79 + .../mailru/easyjson/opt/gotemplate_Int.go | 79 + .../mailru/easyjson/opt/gotemplate_Int16.go | 79 + .../mailru/easyjson/opt/gotemplate_Int32.go | 79 + .../mailru/easyjson/opt/gotemplate_Int64.go | 79 + .../mailru/easyjson/opt/gotemplate_Int8.go | 79 + .../mailru/easyjson/opt/gotemplate_String.go | 79 + .../mailru/easyjson/opt/gotemplate_Uint.go | 79 + .../mailru/easyjson/opt/gotemplate_Uint16.go | 79 + .../mailru/easyjson/opt/gotemplate_Uint32.go | 79 + .../mailru/easyjson/opt/gotemplate_Uint64.go | 79 + .../mailru/easyjson/opt/gotemplate_Uint8.go | 79 + .../github.com/mailru/easyjson/opt/optional/opt.go | 80 + vendor/github.com/mailru/easyjson/opt/opts.go | 22 + vendor/github.com/mailru/easyjson/parser/parser.go | 97 + .../mailru/easyjson/parser/parser_unix.go | 42 + .../mailru/easyjson/parser/parser_windows.go | 49 + vendor/github.com/mailru/easyjson/raw.go | 45 + .../github.com/mailru/easyjson/tests/basic_test.go | 231 + vendor/github.com/mailru/easyjson/tests/data.go | 759 ++ vendor/github.com/mailru/easyjson/tests/errors.go | 26 + .../mailru/easyjson/tests/errors_test.go | 285 + .../github.com/mailru/easyjson/tests/named_type.go | 22 + .../mailru/easyjson/tests/nested_easy.go | 25 + vendor/github.com/mailru/easyjson/tests/nothing.go | 3 + .../github.com/mailru/easyjson/tests/omitempty.go | 12 + .../github.com/mailru/easyjson/tests/opt_test.go | 70 + .../mailru/easyjson/tests/required_test.go | 28 + vendor/github.com/mailru/easyjson/tests/snake.go | 10 + .../golang_protobuf_extensions/.travis.yml | 6 + .../golang_protobuf_extensions/Makefile.TRAVIS | 15 + .../golang_protobuf_extensions/pbutil/.gitignore | 1 + .../golang_protobuf_extensions/pbutil/Makefile | 7 + .../golang_protobuf_extensions/pbutil/all_test.go | 25 +- .../pbutil/fixtures_test.go | 103 - .../testdata/README.THIRD_PARTY | 4 + .../golang_protobuf_extensions/testdata/test.pb.go | 4029 ++++++++++ .../golang_protobuf_extensions/testdata/test.proto | 540 ++ vendor/github.com/miekg/dns/README.md | 2 + vendor/github.com/miekg/dns/server.go | 13 +- vendor/github.com/miekg/dns/version.go | 2 +- vendor/github.com/minio/go-homedir/LICENSE | 21 - vendor/github.com/minio/go-homedir/README.md | 16 - vendor/github.com/minio/go-homedir/dir_posix.go | 61 - vendor/github.com/minio/go-homedir/dir_windows.go | 25 - vendor/github.com/minio/go-homedir/homedir.go | 67 - vendor/github.com/minio/go-homedir/homedir_test.go | 114 - vendor/github.com/minio/minio-go/.gitignore | 3 +- vendor/github.com/minio/minio-go/.travis.yml | 26 +- vendor/github.com/minio/minio-go/MAINTAINERS.md | 27 +- vendor/github.com/minio/minio-go/Makefile | 15 + vendor/github.com/minio/minio-go/NOTICE | 2 + vendor/github.com/minio/minio-go/README.md | 28 +- vendor/github.com/minio/minio-go/README_zh_CN.md | 246 + .../minio/minio-go/api-compose-object.go | 139 +- .../minio/minio-go/api-compose-object_test.go | 3 +- vendor/github.com/minio/minio-go/api-datatypes.go | 5 +- .../minio/minio-go/api-error-response.go | 71 +- .../minio/minio-go/api-error-response_test.go | 108 +- .../minio/minio-go/api-get-object-context.go | 26 + .../minio/minio-go/api-get-object-file.go | 35 +- vendor/github.com/minio/minio-go/api-get-object.go | 101 +- .../github.com/minio/minio-go/api-get-options.go | 126 + vendor/github.com/minio/minio-go/api-get-policy.go | 12 +- vendor/github.com/minio/minio-go/api-list.go | 40 +- .../github.com/minio/minio-go/api-notification.go | 29 +- vendor/github.com/minio/minio-go/api-presigned.go | 58 +- vendor/github.com/minio/minio-go/api-put-bucket.go | 45 +- .../minio/minio-go/api-put-object-common.go | 34 +- .../minio/minio-go/api-put-object-context.go | 39 + .../minio/minio-go/api-put-object-copy.go | 3 +- .../minio/minio-go/api-put-object-encrypted.go | 20 +- .../minio/minio-go/api-put-object-file-context.go | 64 + .../minio/minio-go/api-put-object-file.go | 51 +- .../minio/minio-go/api-put-object-multipart.go | 97 +- .../minio/minio-go/api-put-object-streaming.go | 115 +- vendor/github.com/minio/minio-go/api-put-object.go | 240 +- .../minio/minio-go/api-put-object_test.go | 62 + vendor/github.com/minio/minio-go/api-remove.go | 46 +- .../github.com/minio/minio-go/api-s3-datatypes.go | 5 +- vendor/github.com/minio/minio-go/api-stat.go | 32 +- vendor/github.com/minio/minio-go/api.go | 185 +- vendor/github.com/minio/minio-go/api_unit_test.go | 176 +- vendor/github.com/minio/minio-go/appveyor.yml | 4 +- vendor/github.com/minio/minio-go/bucket-cache.go | 7 +- .../github.com/minio/minio-go/bucket-cache_test.go | 9 +- .../minio/minio-go/bucket-notification.go | 3 +- vendor/github.com/minio/minio-go/constants.go | 8 +- vendor/github.com/minio/minio-go/core.go | 67 +- vendor/github.com/minio/minio-go/core_test.go | 334 +- vendor/github.com/minio/minio-go/docs/API.md | 740 +- .../minio/minio-go/docs/checker.go.template | 21 + vendor/github.com/minio/minio-go/docs/validator.go | 227 + vendor/github.com/minio/minio-go/docs/zh_CN/API.md | 1820 +++++ .../minio/minio-go/docs/zh_CN/CONTRIBUTING.md | 22 + .../examples/minio/listenbucketnotification.go | 3 +- .../minio/minio-go/examples/s3/bucketexists.go | 3 +- .../minio/minio-go/examples/s3/composeobject.go | 3 +- .../minio/minio-go/examples/s3/copyobject.go | 3 +- .../minio-go/examples/s3/fgetobject-context.go | 54 + .../minio/minio-go/examples/s3/fgetobject.go | 5 +- .../minio-go/examples/s3/fputencrypted-object.go | 80 + .../minio-go/examples/s3/fputobject-context.go | 53 + .../minio/minio-go/examples/s3/fputobject.go | 7 +- .../minio-go/examples/s3/get-encrypted-object.go | 3 +- .../minio-go/examples/s3/getbucketnotification.go | 3 +- .../minio/minio-go/examples/s3/getbucketpolicy.go | 3 +- .../minio-go/examples/s3/getobject-context.go | 73 + .../minio/minio-go/examples/s3/getobject.go | 5 +- .../minio-go/examples/s3/listbucketpolicies.go | 3 +- .../minio/minio-go/examples/s3/listbuckets.go | 3 +- .../minio-go/examples/s3/listincompleteuploads.go | 3 +- .../minio/minio-go/examples/s3/listobjects-N.go | 3 +- .../minio/minio-go/examples/s3/listobjects.go | 3 +- .../minio/minio-go/examples/s3/listobjectsV2.go | 3 +- .../minio/minio-go/examples/s3/makebucket.go | 3 +- .../minio-go/examples/s3/presignedgetobject.go | 3 +- .../minio-go/examples/s3/presignedheadobject.go | 3 +- .../minio-go/examples/s3/presignedpostpolicy.go | 3 +- .../minio-go/examples/s3/presignedputobject.go | 3 +- .../minio-go/examples/s3/put-encrypted-object.go | 5 +- .../minio-go/examples/s3/putobject-context.go | 68 + .../examples/s3/putobject-getobject-sse.go | 20 +- .../minio-go/examples/s3/putobject-progress.go | 9 +- .../examples/s3/putobject-s3-accelerate.go | 10 +- .../minio-go/examples/s3/putobject-streaming.go | 5 +- .../minio/minio-go/examples/s3/putobject.go | 9 +- .../examples/s3/removeallbucketnotification.go | 3 +- .../minio/minio-go/examples/s3/removebucket.go | 3 +- .../minio-go/examples/s3/removeincompleteupload.go | 3 +- .../minio/minio-go/examples/s3/removeobject.go | 3 +- .../minio/minio-go/examples/s3/removeobjects.go | 12 +- .../minio-go/examples/s3/setbucketnotification.go | 3 +- .../minio/minio-go/examples/s3/setbucketpolicy.go | 3 +- .../minio/minio-go/examples/s3/statobject.go | 5 +- .../github.com/minio/minio-go/functional_tests.go | 4635 ++++++++---- .../github.com/minio/minio-go/get-options_test.go | 57 + vendor/github.com/minio/minio-go/hook-reader.go | 3 +- .../minio/minio-go/pkg/credentials/chain.go | 34 +- .../minio/minio-go/pkg/credentials/chain_test.go | 11 +- .../minio/minio-go/pkg/credentials/credentials.go | 2 +- .../minio-go/pkg/credentials/credentials_test.go | 2 +- .../minio/minio-go/pkg/credentials/doc.go | 17 + .../minio/minio-go/pkg/credentials/env_aws.go | 2 +- .../minio/minio-go/pkg/credentials/env_minio.go | 2 +- .../minio/minio-go/pkg/credentials/env_test.go | 2 +- .../pkg/credentials/file_aws_credentials.go | 4 +- .../minio-go/pkg/credentials/file_minio_client.go | 4 +- .../minio/minio-go/pkg/credentials/file_test.go | 2 +- .../minio/minio-go/pkg/credentials/iam_aws.go | 17 +- .../minio/minio-go/pkg/credentials/iam_aws_test.go | 17 + .../minio-go/pkg/credentials/signature-type.go | 3 +- .../minio/minio-go/pkg/credentials/static.go | 2 +- .../minio/minio-go/pkg/credentials/static_test.go | 2 +- .../github.com/minio/minio-go/pkg/encrypt/cbc.go | 3 +- .../minio/minio-go/pkg/encrypt/interface.go | 3 +- .../github.com/minio/minio-go/pkg/encrypt/keys.go | 3 +- .../minio-go/pkg/policy/bucket-policy-condition.go | 3 +- .../pkg/policy/bucket-policy-condition_test.go | 3 +- .../minio/minio-go/pkg/policy/bucket-policy.go | 3 +- .../minio-go/pkg/policy/bucket-policy_test.go | 3 +- .../pkg/s3signer/request-signature-streaming.go | 7 +- .../s3signer/request-signature-streaming_test.go | 11 +- .../minio-go/pkg/s3signer/request-signature-v2.go | 65 +- .../pkg/s3signer/request-signature-v2_test.go | 3 +- .../minio-go/pkg/s3signer/request-signature-v4.go | 5 +- .../pkg/s3signer/request-signature-v4_test.go | 50 + .../pkg/s3signer/request-signature_test.go | 3 +- .../minio/minio-go/pkg/s3signer/test-utils_test.go | 3 +- .../minio/minio-go/pkg/s3signer/utils.go | 12 +- .../minio/minio-go/pkg/s3signer/utils_test.go | 6 +- .../github.com/minio/minio-go/pkg/s3utils/utils.go | 68 +- .../minio/minio-go/pkg/s3utils/utils_test.go | 107 +- .../github.com/minio/minio-go/pkg/set/stringset.go | 3 +- .../minio/minio-go/pkg/set/stringset_test.go | 3 +- vendor/github.com/minio/minio-go/post-policy.go | 39 + .../github.com/minio/minio-go/request-headers.go | 111 - .../minio/minio-go/request-headers_test.go | 56 - .../github.com/minio/minio-go/retry-continous.go | 17 + vendor/github.com/minio/minio-go/retry.go | 5 +- vendor/github.com/minio/minio-go/s3-endpoints.go | 8 +- vendor/github.com/minio/minio-go/s3-error.go | 3 +- .../github.com/minio/minio-go/test-utils_test.go | 3 +- vendor/github.com/minio/minio-go/transport.go | 2 +- vendor/github.com/minio/minio-go/transport_1_5.go | 39 - vendor/github.com/minio/minio-go/transport_1_6.go | 40 - vendor/github.com/minio/minio-go/utils.go | 107 +- vendor/github.com/minio/minio-go/utils_test.go | 116 +- vendor/github.com/mitchellh/go-homedir/LICENSE | 21 + vendor/github.com/mitchellh/go-homedir/README.md | 14 + vendor/github.com/mitchellh/go-homedir/homedir.go | 137 + .../mitchellh/go-homedir/homedir_test.go | 112 + .../github.com/mitchellh/mapstructure/.travis.yml | 11 +- vendor/github.com/mitchellh/mapstructure/README.md | 2 +- .../mitchellh/mapstructure/mapstructure.go | 89 +- .../mapstructure/mapstructure_bugs_test.go | 18 + .../mitchellh/mapstructure/mapstructure_test.go | 175 + vendor/github.com/olivere/elastic/.gitignore | 33 + vendor/github.com/olivere/elastic/.travis.yml | 15 + vendor/github.com/olivere/elastic/CHANGELOG-3.0.md | 363 + vendor/github.com/olivere/elastic/CHANGELOG-5.0.md | 195 + vendor/github.com/olivere/elastic/CHANGELOG-6.0.md | 18 + .../github.com/olivere/elastic/CODE_OF_CONDUCT.md | 46 + vendor/github.com/olivere/elastic/CONTRIBUTING.md | 40 + vendor/github.com/olivere/elastic/CONTRIBUTORS | 123 + .../github.com/olivere/elastic/ISSUE_TEMPLATE.md | 18 + vendor/github.com/olivere/elastic/LICENSE | 20 + vendor/github.com/olivere/elastic/README.md | 391 + .../olivere/elastic/acknowledged_response.go | 13 + vendor/github.com/olivere/elastic/backoff.go | 148 + vendor/github.com/olivere/elastic/backoff_test.go | 140 + vendor/github.com/olivere/elastic/bulk.go | 417 ++ .../olivere/elastic/bulk_delete_request.go | 166 + .../elastic/bulk_delete_request_easyjson.go | 230 + .../olivere/elastic/bulk_delete_request_test.go | 79 + .../olivere/elastic/bulk_index_request.go | 239 + .../olivere/elastic/bulk_index_request_easyjson.go | 262 + .../olivere/elastic/bulk_index_request_test.go | 116 + .../github.com/olivere/elastic/bulk_processor.go | 547 ++ .../olivere/elastic/bulk_processor_test.go | 425 ++ vendor/github.com/olivere/elastic/bulk_request.go | 17 + vendor/github.com/olivere/elastic/bulk_test.go | 600 ++ .../olivere/elastic/bulk_update_request.go | 298 + .../elastic/bulk_update_request_easyjson.go | 461 ++ .../olivere/elastic/bulk_update_request_test.go | 149 + vendor/github.com/olivere/elastic/canonicalize.go | 34 + .../olivere/elastic/canonicalize_test.go | 72 + vendor/github.com/olivere/elastic/clear_scroll.go | 108 + .../olivere/elastic/clear_scroll_test.go | 87 + vendor/github.com/olivere/elastic/client.go | 1786 +++++ vendor/github.com/olivere/elastic/client_test.go | 1319 ++++ .../olivere/elastic/cluster-test/Makefile | 16 + .../olivere/elastic/cluster-test/README.md | 63 + .../olivere/elastic/cluster-test/cluster-test.go | 361 + .../github.com/olivere/elastic/cluster_health.go | 248 + .../olivere/elastic/cluster_health_test.go | 119 + vendor/github.com/olivere/elastic/cluster_state.go | 288 + .../olivere/elastic/cluster_state_test.go | 93 + vendor/github.com/olivere/elastic/cluster_stats.go | 352 + .../olivere/elastic/cluster_stats_test.go | 92 + vendor/github.com/olivere/elastic/config/config.go | 90 + .../olivere/elastic/config/config_test.go | 45 + vendor/github.com/olivere/elastic/config/doc.go | 9 + vendor/github.com/olivere/elastic/connection.go | 90 + vendor/github.com/olivere/elastic/count.go | 315 + vendor/github.com/olivere/elastic/count_test.go | 127 + vendor/github.com/olivere/elastic/decoder.go | 26 + vendor/github.com/olivere/elastic/decoder_test.go | 50 + vendor/github.com/olivere/elastic/delete.go | 226 + .../github.com/olivere/elastic/delete_by_query.go | 654 ++ .../olivere/elastic/delete_by_query_test.go | 146 + vendor/github.com/olivere/elastic/delete_test.go | 134 + vendor/github.com/olivere/elastic/doc.go | 51 + vendor/github.com/olivere/elastic/errors.go | 147 + vendor/github.com/olivere/elastic/errors_test.go | 295 + .../olivere/elastic/etc/elasticsearch.yml | 15 + .../olivere/elastic/etc/ingest-geoip/.gitkeep | 0 vendor/github.com/olivere/elastic/etc/jvm.options | 100 + .../olivere/elastic/etc/log4j2.properties | 74 + .../olivere/elastic/etc/scripts/.gitkeep | 0 vendor/github.com/olivere/elastic/example_test.go | 530 ++ vendor/github.com/olivere/elastic/exists.go | 181 + vendor/github.com/olivere/elastic/exists_test.go | 53 + vendor/github.com/olivere/elastic/explain.go | 326 + vendor/github.com/olivere/elastic/explain_test.go | 44 + .../olivere/elastic/fetch_source_context.go | 90 + .../olivere/elastic/fetch_source_context_test.go | 125 + vendor/github.com/olivere/elastic/field_caps.go | 202 + .../github.com/olivere/elastic/field_caps_test.go | 146 + vendor/github.com/olivere/elastic/geo_point.go | 48 + .../github.com/olivere/elastic/geo_point_test.go | 24 + vendor/github.com/olivere/elastic/get.go | 260 + vendor/github.com/olivere/elastic/get_test.go | 166 + vendor/github.com/olivere/elastic/highlight.go | 469 ++ .../github.com/olivere/elastic/highlight_test.go | 211 + vendor/github.com/olivere/elastic/index.go | 297 + vendor/github.com/olivere/elastic/index_test.go | 280 + .../github.com/olivere/elastic/indices_analyze.go | 284 + .../olivere/elastic/indices_analyze_test.go | 85 + vendor/github.com/olivere/elastic/indices_close.go | 159 + .../olivere/elastic/indices_close_test.go | 84 + .../github.com/olivere/elastic/indices_create.go | 136 + .../olivere/elastic/indices_create_test.go | 63 + .../github.com/olivere/elastic/indices_delete.go | 133 + .../olivere/elastic/indices_delete_template.go | 128 + .../olivere/elastic/indices_delete_test.go | 23 + .../github.com/olivere/elastic/indices_exists.go | 155 + .../olivere/elastic/indices_exists_template.go | 118 + .../elastic/indices_exists_template_test.go | 68 + .../olivere/elastic/indices_exists_test.go | 23 + .../olivere/elastic/indices_exists_type.go | 165 + .../olivere/elastic/indices_exists_type_test.go | 135 + vendor/github.com/olivere/elastic/indices_flush.go | 173 + .../olivere/elastic/indices_flush_test.go | 70 + .../olivere/elastic/indices_forcemerge.go | 193 + .../olivere/elastic/indices_forcemerge_test.go | 57 + vendor/github.com/olivere/elastic/indices_get.go | 206 + .../olivere/elastic/indices_get_aliases.go | 161 + .../olivere/elastic/indices_get_aliases_test.go | 181 + .../olivere/elastic/indices_get_field_mapping.go | 187 + .../elastic/indices_get_field_mapping_test.go | 55 + .../olivere/elastic/indices_get_mapping.go | 174 + .../olivere/elastic/indices_get_mapping_test.go | 50 + .../olivere/elastic/indices_get_settings.go | 187 + .../olivere/elastic/indices_get_settings_test.go | 82 + .../olivere/elastic/indices_get_template.go | 133 + .../olivere/elastic/indices_get_template_test.go | 41 + .../github.com/olivere/elastic/indices_get_test.go | 98 + vendor/github.com/olivere/elastic/indices_open.go | 163 + .../olivere/elastic/indices_open_test.go | 23 + .../olivere/elastic/indices_put_alias.go | 302 + .../olivere/elastic/indices_put_alias_test.go | 222 + .../olivere/elastic/indices_put_mapping.go | 228 + .../olivere/elastic/indices_put_mapping_test.go | 95 + .../olivere/elastic/indices_put_settings.go | 191 + .../olivere/elastic/indices_put_settings_test.go | 95 + .../olivere/elastic/indices_put_template.go | 207 + .../github.com/olivere/elastic/indices_refresh.go | 98 + .../olivere/elastic/indices_refresh_test.go | 81 + .../github.com/olivere/elastic/indices_rollover.go | 272 + .../olivere/elastic/indices_rollover_test.go | 116 + .../github.com/olivere/elastic/indices_segments.go | 237 + .../olivere/elastic/indices_segments_test.go | 86 + .../github.com/olivere/elastic/indices_shrink.go | 179 + .../olivere/elastic/indices_shrink_test.go | 34 + vendor/github.com/olivere/elastic/indices_stats.go | 384 + .../olivere/elastic/indices_stats_test.go | 86 + .../olivere/elastic/ingest_delete_pipeline.go | 129 + .../olivere/elastic/ingest_delete_pipeline_test.go | 31 + .../olivere/elastic/ingest_get_pipeline.go | 121 + .../olivere/elastic/ingest_get_pipeline_test.go | 121 + .../olivere/elastic/ingest_put_pipeline.go | 158 + .../olivere/elastic/ingest_put_pipeline_test.go | 31 + .../olivere/elastic/ingest_simulate_pipeline.go | 161 + .../elastic/ingest_simulate_pipeline_test.go | 35 + vendor/github.com/olivere/elastic/inner_hit.go | 160 + .../github.com/olivere/elastic/inner_hit_test.go | 44 + vendor/github.com/olivere/elastic/logger.go | 10 + vendor/github.com/olivere/elastic/mget.go | 257 + vendor/github.com/olivere/elastic/mget_test.go | 96 + vendor/github.com/olivere/elastic/msearch.go | 101 + vendor/github.com/olivere/elastic/msearch_test.go | 198 + vendor/github.com/olivere/elastic/mtermvectors.go | 475 ++ .../olivere/elastic/mtermvectors_test.go | 134 + vendor/github.com/olivere/elastic/nodes_info.go | 313 + .../github.com/olivere/elastic/nodes_info_test.go | 43 + vendor/github.com/olivere/elastic/nodes_stats.go | 703 ++ .../github.com/olivere/elastic/nodes_stats_test.go | 138 + .../github.com/olivere/elastic/percolate_test.go | 68 + vendor/github.com/olivere/elastic/ping.go | 127 + vendor/github.com/olivere/elastic/ping_test.go | 65 + vendor/github.com/olivere/elastic/plugins.go | 40 + vendor/github.com/olivere/elastic/plugins_test.go | 32 + vendor/github.com/olivere/elastic/query.go | 13 + .../elastic/recipes/bulk_insert/bulk_insert.go | 173 + .../olivere/elastic/recipes/connect/connect.go | 43 + .../elastic/recipes/sliced_scroll/sliced_scroll.go | 161 + vendor/github.com/olivere/elastic/reindex.go | 685 ++ vendor/github.com/olivere/elastic/reindex_test.go | 401 + vendor/github.com/olivere/elastic/request.go | 79 + vendor/github.com/olivere/elastic/request_test.go | 72 + vendor/github.com/olivere/elastic/rescore.go | 44 + vendor/github.com/olivere/elastic/rescorer.go | 64 + vendor/github.com/olivere/elastic/response.go | 41 + vendor/github.com/olivere/elastic/response_test.go | 48 + vendor/github.com/olivere/elastic/retrier.go | 61 + vendor/github.com/olivere/elastic/retrier_test.go | 174 + vendor/github.com/olivere/elastic/retry.go | 56 + vendor/github.com/olivere/elastic/retry_test.go | 44 + vendor/github.com/olivere/elastic/run-es.sh | 3 + vendor/github.com/olivere/elastic/script.go | 127 + vendor/github.com/olivere/elastic/script_test.go | 61 + vendor/github.com/olivere/elastic/scroll.go | 470 ++ vendor/github.com/olivere/elastic/scroll_test.go | 387 + vendor/github.com/olivere/elastic/search.go | 581 ++ vendor/github.com/olivere/elastic/search_aggs.go | 1450 ++++ .../olivere/elastic/search_aggs_bucket_children.go | 76 + .../elastic/search_aggs_bucket_children_test.go | 46 + .../elastic/search_aggs_bucket_count_thresholds.go | 13 + .../elastic/search_aggs_bucket_date_histogram.go | 285 + .../search_aggs_bucket_date_histogram_test.go | 49 + .../elastic/search_aggs_bucket_date_range.go | 246 + .../elastic/search_aggs_bucket_date_range_test.go | 155 + .../olivere/elastic/search_aggs_bucket_filter.go | 77 + .../elastic/search_aggs_bucket_filter_test.go | 66 + .../olivere/elastic/search_aggs_bucket_filters.go | 138 + .../elastic/search_aggs_bucket_filters_test.go | 99 + .../elastic/search_aggs_bucket_geo_distance.go | 198 + .../search_aggs_bucket_geo_distance_test.go | 93 + .../elastic/search_aggs_bucket_geohash_grid.go | 102 + .../search_aggs_bucket_geohash_grid_test.go | 84 + .../olivere/elastic/search_aggs_bucket_global.go | 71 + .../elastic/search_aggs_bucket_global_test.go | 44 + .../elastic/search_aggs_bucket_histogram.go | 265 + .../elastic/search_aggs_bucket_histogram_test.go | 61 + .../olivere/elastic/search_aggs_bucket_ip_range.go | 195 + .../elastic/search_aggs_bucket_ip_range_test.go | 90 + .../olivere/elastic/search_aggs_bucket_missing.go | 81 + .../elastic/search_aggs_bucket_missing_test.go | 44 + .../olivere/elastic/search_aggs_bucket_nested.go | 82 + .../elastic/search_aggs_bucket_nested_test.go | 62 + .../olivere/elastic/search_aggs_bucket_range.go | 244 + .../elastic/search_aggs_bucket_range_test.go | 178 + .../elastic/search_aggs_bucket_reverse_nested.go | 86 + .../search_aggs_bucket_reverse_nested_test.go | 83 + .../olivere/elastic/search_aggs_bucket_sampler.go | 111 + .../elastic/search_aggs_bucket_sampler_test.go | 30 + .../search_aggs_bucket_significant_terms.go | 389 + .../search_aggs_bucket_significant_terms_test.go | 211 + .../elastic/search_aggs_bucket_significant_text.go | 245 + .../search_aggs_bucket_significant_text_test.go | 66 + .../olivere/elastic/search_aggs_bucket_terms.go | 368 + .../elastic/search_aggs_bucket_terms_test.go | 155 + .../olivere/elastic/search_aggs_matrix_stats.go | 120 + .../elastic/search_aggs_matrix_stats_test.go | 53 + .../olivere/elastic/search_aggs_metrics_avg.go | 101 + .../elastic/search_aggs_metrics_avg_test.go | 61 + .../elastic/search_aggs_metrics_cardinality.go | 120 + .../search_aggs_metrics_cardinality_test.go | 78 + .../elastic/search_aggs_metrics_extended_stats.go | 99 + .../search_aggs_metrics_extended_stats_test.go | 44 + .../elastic/search_aggs_metrics_geo_bounds.go | 105 + .../elastic/search_aggs_metrics_geo_bounds_test.go | 61 + .../olivere/elastic/search_aggs_metrics_max.go | 99 + .../elastic/search_aggs_metrics_max_test.go | 61 + .../olivere/elastic/search_aggs_metrics_min.go | 100 + .../elastic/search_aggs_metrics_min_test.go | 61 + .../search_aggs_metrics_percentile_ranks.go | 131 + .../search_aggs_metrics_percentile_ranks_test.go | 78 + .../elastic/search_aggs_metrics_percentiles.go | 130 + .../search_aggs_metrics_percentiles_test.go | 78 + .../olivere/elastic/search_aggs_metrics_stats.go | 99 + .../elastic/search_aggs_metrics_stats_test.go | 61 + .../olivere/elastic/search_aggs_metrics_sum.go | 99 + .../elastic/search_aggs_metrics_sum_test.go | 61 + .../elastic/search_aggs_metrics_top_hits.go | 143 + .../elastic/search_aggs_metrics_top_hits_test.go | 31 + .../elastic/search_aggs_metrics_value_count.go | 102 + .../search_aggs_metrics_value_count_test.go | 63 + .../elastic/search_aggs_pipeline_avg_bucket.go | 113 + .../search_aggs_pipeline_avg_bucket_test.go | 27 + .../elastic/search_aggs_pipeline_bucket_script.go | 132 + .../search_aggs_pipeline_bucket_script_test.go | 30 + .../search_aggs_pipeline_bucket_selector.go | 134 + .../search_aggs_pipeline_bucket_selector_test.go | 29 + .../elastic/search_aggs_pipeline_cumulative_sum.go | 90 + .../search_aggs_pipeline_cumulative_sum_test.go | 27 + .../elastic/search_aggs_pipeline_derivative.go | 124 + .../search_aggs_pipeline_derivative_test.go | 27 + .../elastic/search_aggs_pipeline_max_bucket.go | 114 + .../search_aggs_pipeline_max_bucket_test.go | 27 + .../elastic/search_aggs_pipeline_min_bucket.go | 114 + .../search_aggs_pipeline_min_bucket_test.go | 27 + .../elastic/search_aggs_pipeline_mov_avg.go | 393 + .../elastic/search_aggs_pipeline_mov_avg_test.go | 132 + .../search_aggs_pipeline_percentiles_bucket.go | 125 + ...search_aggs_pipeline_percentiles_bucket_test.go | 44 + .../elastic/search_aggs_pipeline_serial_diff.go | 124 + .../search_aggs_pipeline_serial_diff_test.go | 27 + .../elastic/search_aggs_pipeline_stats_bucket.go | 113 + .../search_aggs_pipeline_stats_bucket_test.go | 27 + .../elastic/search_aggs_pipeline_sum_bucket.go | 113 + .../search_aggs_pipeline_sum_bucket_test.go | 27 + .../olivere/elastic/search_aggs_pipeline_test.go | 903 +++ .../github.com/olivere/elastic/search_aggs_test.go | 3233 ++++++++ .../olivere/elastic/search_collapse_builder.go | 68 + .../elastic/search_collapse_builder_test.go | 29 + .../olivere/elastic/search_queries_bool.go | 203 + .../olivere/elastic/search_queries_bool_test.go | 33 + .../olivere/elastic/search_queries_boosting.go | 97 + .../elastic/search_queries_boosting_test.go | 30 + .../olivere/elastic/search_queries_common_terms.go | 137 + .../elastic/search_queries_common_terms_test.go | 85 + .../elastic/search_queries_constant_score.go | 59 + .../elastic/search_queries_constant_score_test.go | 27 + .../olivere/elastic/search_queries_dis_max.go | 104 + .../olivere/elastic/search_queries_dis_max_test.go | 28 + .../olivere/elastic/search_queries_exists.go | 49 + .../olivere/elastic/search_queries_exists_test.go | 27 + .../olivere/elastic/search_queries_fsq.go | 171 + .../elastic/search_queries_fsq_score_funcs.go | 567 ++ .../olivere/elastic/search_queries_fsq_test.go | 166 + .../olivere/elastic/search_queries_fuzzy.go | 120 + .../olivere/elastic/search_queries_fuzzy_test.go | 27 + .../elastic/search_queries_geo_bounding_box.go | 121 + .../search_queries_geo_bounding_box_test.go | 63 + .../olivere/elastic/search_queries_geo_distance.go | 107 + .../elastic/search_queries_geo_distance_test.go | 69 + .../olivere/elastic/search_queries_geo_polygon.go | 72 + .../elastic/search_queries_geo_polygon_test.go | 58 + .../olivere/elastic/search_queries_has_child.go | 131 + .../elastic/search_queries_has_child_test.go | 45 + .../olivere/elastic/search_queries_has_parent.go | 97 + .../elastic/search_queries_has_parent_test.go | 27 + .../olivere/elastic/search_queries_ids.go | 76 + .../olivere/elastic/search_queries_ids_test.go | 27 + .../olivere/elastic/search_queries_match.go | 189 + .../olivere/elastic/search_queries_match_all.go | 51 + .../elastic/search_queries_match_all_test.go | 61 + .../olivere/elastic/search_queries_match_none.go | 39 + .../elastic/search_queries_match_none_test.go | 44 + .../olivere/elastic/search_queries_match_phrase.go | 79 + .../elastic/search_queries_match_phrase_prefix.go | 89 + .../search_queries_match_phrase_prefix_test.go | 27 + .../elastic/search_queries_match_phrase_test.go | 29 + .../olivere/elastic/search_queries_match_test.go | 44 + .../elastic/search_queries_more_like_this.go | 412 ++ .../elastic/search_queries_more_like_this_test.go | 92 + .../olivere/elastic/search_queries_multi_match.go | 275 + .../elastic/search_queries_multi_match_test.go | 131 + .../olivere/elastic/search_queries_nested.go | 96 + .../olivere/elastic/search_queries_nested_test.go | 86 + .../olivere/elastic/search_queries_parent_id.go | 99 + .../elastic/search_queries_parent_id_test.go | 52 + .../olivere/elastic/search_queries_percolator.go | 115 + .../elastic/search_queries_percolator_test.go | 65 + .../olivere/elastic/search_queries_prefix.go | 67 + .../elastic/search_queries_prefix_example_test.go | 35 + .../olivere/elastic/search_queries_prefix_test.go | 45 + .../olivere/elastic/search_queries_query_string.go | 350 + .../elastic/search_queries_query_string_test.go | 46 + .../olivere/elastic/search_queries_range.go | 144 + .../olivere/elastic/search_queries_range_test.go | 68 + .../olivere/elastic/search_queries_raw_string.go | 26 + .../elastic/search_queries_raw_string_test.go | 44 + .../olivere/elastic/search_queries_regexp.go | 82 + .../olivere/elastic/search_queries_regexp_test.go | 47 + .../olivere/elastic/search_queries_script.go | 51 + .../olivere/elastic/search_queries_script_test.go | 45 + .../elastic/search_queries_simple_query_string.go | 185 + .../search_queries_simple_query_string_test.go | 87 + .../olivere/elastic/search_queries_slice.go | 53 + .../olivere/elastic/search_queries_slice_test.go | 27 + .../olivere/elastic/search_queries_term.go | 58 + .../olivere/elastic/search_queries_term_test.go | 46 + .../olivere/elastic/search_queries_terms.go | 75 + .../olivere/elastic/search_queries_terms_test.go | 82 + .../olivere/elastic/search_queries_type.go | 26 + .../olivere/elastic/search_queries_type_test.go | 27 + .../olivere/elastic/search_queries_wildcard.go | 81 + .../elastic/search_queries_wildcard_test.go | 68 + .../github.com/olivere/elastic/search_request.go | 205 + .../olivere/elastic/search_request_test.go | 61 + vendor/github.com/olivere/elastic/search_source.go | 546 ++ .../olivere/elastic/search_source_test.go | 295 + .../olivere/elastic/search_suggester_test.go | 355 + .../olivere/elastic/search_terms_lookup.go | 74 + .../olivere/elastic/search_terms_lookup_test.go | 27 + vendor/github.com/olivere/elastic/search_test.go | 1265 ++++ vendor/github.com/olivere/elastic/setup_test.go | 445 ++ .../github.com/olivere/elastic/snapshot_create.go | 191 + .../olivere/elastic/snapshot_create_repository.go | 205 + .../elastic/snapshot_create_repository_test.go | 61 + .../olivere/elastic/snapshot_create_test.go | 63 + .../olivere/elastic/snapshot_delete_repository.go | 132 + .../elastic/snapshot_delete_repository_test.go | 35 + .../olivere/elastic/snapshot_get_repository.go | 134 + .../elastic/snapshot_get_repository_test.go | 39 + .../olivere/elastic/snapshot_verify_repository.go | 132 + .../elastic/snapshot_verify_repository_test.go | 31 + vendor/github.com/olivere/elastic/sort.go | 614 ++ vendor/github.com/olivere/elastic/sort_test.go | 278 + vendor/github.com/olivere/elastic/suggest_field.go | 90 + .../olivere/elastic/suggest_field_test.go | 29 + vendor/github.com/olivere/elastic/suggester.go | 15 + .../olivere/elastic/suggester_completion.go | 352 + .../olivere/elastic/suggester_completion_test.go | 110 + .../olivere/elastic/suggester_context.go | 124 + .../olivere/elastic/suggester_context_category.go | 119 + .../elastic/suggester_context_category_test.go | 163 + .../olivere/elastic/suggester_context_geo.go | 130 + .../olivere/elastic/suggester_context_geo_test.go | 48 + .../olivere/elastic/suggester_context_test.go | 55 + .../github.com/olivere/elastic/suggester_phrase.go | 546 ++ .../olivere/elastic/suggester_phrase_test.go | 169 + .../github.com/olivere/elastic/suggester_term.go | 233 + .../olivere/elastic/suggester_term_test.go | 49 + vendor/github.com/olivere/elastic/tasks_cancel.go | 149 + .../olivere/elastic/tasks_cancel_test.go | 51 + .../github.com/olivere/elastic/tasks_get_task.go | 108 + .../olivere/elastic/tasks_get_task_test.go | 43 + vendor/github.com/olivere/elastic/tasks_list.go | 231 + .../github.com/olivere/elastic/tasks_list_test.go | 65 + vendor/github.com/olivere/elastic/termvectors.go | 464 ++ .../github.com/olivere/elastic/termvectors_test.go | 157 + vendor/github.com/olivere/elastic/update.go | 327 + .../github.com/olivere/elastic/update_by_query.go | 655 ++ .../olivere/elastic/update_by_query_test.go | 147 + .../olivere/elastic/update_integration_test.go | 58 + vendor/github.com/olivere/elastic/update_test.go | 262 + .../olivere/elastic/uritemplates/LICENSE | 18 + .../olivere/elastic/uritemplates/uritemplates.go | 359 + .../olivere/elastic/uritemplates/utils.go | 13 + .../olivere/elastic/uritemplates/utils_test.go | 105 + vendor/github.com/pelletier/go-toml/.travis.yml | 4 +- vendor/github.com/pelletier/go-toml/keysparsing.go | 104 +- .../pelletier/go-toml/keysparsing_test.go | 13 +- vendor/github.com/pelletier/go-toml/lexer.go | 42 +- vendor/github.com/pelletier/go-toml/lexer_test.go | 2 +- vendor/github.com/pelletier/go-toml/marshal.go | 127 +- vendor/github.com/pelletier/go-toml/parser.go | 19 +- vendor/github.com/pelletier/go-toml/parser_test.go | 63 +- vendor/github.com/pelletier/go-toml/test.sh | 1 + vendor/github.com/pelletier/go-toml/token.go | 4 + vendor/github.com/pelletier/go-toml/toml.go | 27 +- .../github.com/pelletier/go-toml/tomltree_write.go | 4 +- .../pelletier/go-toml/tomltree_write_test.go | 18 + vendor/github.com/pkg/errors/.travis.yml | 10 +- vendor/github.com/pkg/errors/README.md | 4 +- vendor/github.com/pkg/errors/bench_test.go | 8 +- vendor/github.com/pkg/errors/errors_test.go | 1 + vendor/github.com/pkg/errors/format_test.go | 2 +- vendor/github.com/pkg/errors/stack.go | 11 +- .../pmezard/go-difflib/difflib/difflib.go | 54 +- .../pmezard/go-difflib/difflib/difflib_test.go | 82 +- .../github.com/prometheus/client_golang/.gitignore | 4 + .../prometheus/client_golang/.travis.yml | 7 +- .../github.com/prometheus/client_golang/AUTHORS.md | 18 - .../prometheus/client_golang/CONTRIBUTING.md | 6 +- .../prometheus/client_golang/MAINTAINERS.md | 1 + .../github.com/prometheus/client_golang/README.md | 6 +- .../prometheus/client_golang/api/client.go | 131 + .../prometheus/client_golang/api/client_test.go | 115 + .../prometheus/client_golang/api/prometheus/api.go | 345 - .../client_golang/api/prometheus/api_test.go | 453 -- .../client_golang/api/prometheus/v1/api.go | 293 + .../client_golang/api/prometheus/v1/api_test.go | 424 ++ .../client_golang/examples/random/Dockerfile | 20 + .../client_golang/examples/random/main.go | 21 +- .../client_golang/examples/simple/Dockerfile | 20 + .../client_golang/examples/simple/main.go | 7 +- .../client_golang/prometheus/benchmark_test.go | 24 +- .../prometheus/client_golang/prometheus/counter.go | 191 +- .../client_golang/prometheus/counter_test.go | 160 +- .../prometheus/client_golang/prometheus/desc.go | 39 +- .../client_golang/prometheus/desc_test.go | 17 + .../prometheus/client_golang/prometheus/doc.go | 69 +- .../prometheus/example_timer_complex_test.go | 71 + .../prometheus/example_timer_gauge_test.go | 48 + .../client_golang/prometheus/example_timer_test.go | 40 + .../client_golang/prometheus/examples_test.go | 17 +- .../prometheus/expvar_collector_test.go | 2 +- .../prometheus/client_golang/prometheus/gauge.go | 204 +- .../client_golang/prometheus/gauge_test.go | 24 +- .../client_golang/prometheus/go_collector.go | 51 +- .../client_golang/prometheus/go_collector_test.go | 106 +- .../client_golang/prometheus/graphite/bridge.go | 280 + .../prometheus/graphite/bridge_test.go | 309 + .../client_golang/prometheus/histogram.go | 147 +- .../client_golang/prometheus/histogram_test.go | 24 +- .../prometheus/client_golang/prometheus/http.go | 110 +- .../client_golang/prometheus/http_test.go | 45 +- .../prometheus/client_golang/prometheus/labels.go | 57 + .../prometheus/client_golang/prometheus/metric.go | 20 +- .../client_golang/prometheus/observer.go | 52 + .../client_golang/prometheus/process_collector.go | 104 +- .../prometheus/process_collector_test.go | 24 +- .../client_golang/prometheus/promhttp/delegator.go | 199 + .../prometheus/promhttp/delegator_1_8.go | 181 + .../prometheus/promhttp/delegator_pre_1_8.go | 44 + .../client_golang/prometheus/promhttp/http.go | 31 +- .../client_golang/prometheus/promhttp/http_test.go | 6 - .../prometheus/promhttp/instrument_client.go | 97 + .../prometheus/promhttp/instrument_client_1_8.go | 144 + .../promhttp/instrument_client_1_8_test.go | 195 + .../prometheus/promhttp/instrument_server.go | 447 ++ .../prometheus/promhttp/instrument_server_test.go | 375 + .../push/example_add_from_gatherer_test.go | 84 + .../client_golang/prometheus/push/examples_test.go | 24 +- .../client_golang/prometheus/push/push.go | 2 +- .../client_golang/prometheus/registry.go | 68 +- .../client_golang/prometheus/registry_test.go | 67 +- .../prometheus/client_golang/prometheus/summary.go | 173 +- .../client_golang/prometheus/summary_test.go | 53 +- .../prometheus/client_golang/prometheus/timer.go | 51 + .../client_golang/prometheus/timer_test.go | 152 + .../prometheus/client_golang/prometheus/untyped.go | 102 +- .../prometheus/client_golang/prometheus/value.go | 78 +- .../client_golang/prometheus/value_test.go | 43 + .../prometheus/client_golang/prometheus/vec.go | 491 +- .../client_golang/prometheus/vec_test.go | 281 +- .../python/prometheus/client/__init__.py | 12 - .../python/prometheus/client/model/__init__.py | 14 - .../python/prometheus/client/model/metrics_pb2.py | 575 -- .../ruby/lib/prometheus/client/model.rb | 2 - .../ruby/lib/prometheus/client/model/metrics.pb.rb | 111 - .../ruby/lib/prometheus/client/model/version.rb | 7 - .../main/java/io/prometheus/client/Metrics.java | 7683 -------------------- .../prometheus/procfs/fixtures/net/rpc/nfs | 5 + .../prometheus/procfs/fixtures/net/rpc/nfsd | 11 + vendor/github.com/prometheus/procfs/fs.go | 23 + .../prometheus/procfs/internal/util/parse.go | 46 + vendor/github.com/prometheus/procfs/nfs/nfs.go | 263 + vendor/github.com/prometheus/procfs/nfs/parse.go | 308 + .../github.com/prometheus/procfs/nfs/parse_nfs.go | 67 + .../prometheus/procfs/nfs/parse_nfs_test.go | 180 + .../github.com/prometheus/procfs/nfs/parse_nfsd.go | 89 + .../prometheus/procfs/nfs/parse_nfsd_test.go | 196 + vendor/github.com/prometheus/procfs/xfs/parse.go | 37 +- vendor/github.com/spf13/afero/util.go | 3 +- vendor/github.com/spf13/cobra/bash_completions.md | 4 +- vendor/github.com/spf13/cobra/cobra/cmd/helpers.go | 3 - vendor/github.com/spf13/cobra/cobra/cmd/project.go | 39 +- vendor/github.com/spf13/pflag/count.go | 12 +- vendor/github.com/spf13/pflag/count_test.go | 6 +- vendor/github.com/spf13/pflag/flag.go | 57 +- vendor/github.com/spf13/pflag/flag_test.go | 83 +- vendor/github.com/spf13/pflag/int16.go | 88 + vendor/github.com/stretchr/objx/.codeclimate.yml | 13 + .../stretchr/objx/.github/CODE_OF_CONDUCT.md | 46 + vendor/github.com/stretchr/objx/.gitignore | 27 +- vendor/github.com/stretchr/objx/.travis.yml | 25 + vendor/github.com/stretchr/objx/Gopkg.lock | 30 + vendor/github.com/stretchr/objx/Gopkg.toml | 8 + vendor/github.com/stretchr/objx/LICENSE | 22 + vendor/github.com/stretchr/objx/LICENSE.md | 23 - vendor/github.com/stretchr/objx/README.md | 81 +- vendor/github.com/stretchr/objx/Taskfile.yml | 32 + vendor/github.com/stretchr/objx/accessors.go | 43 +- vendor/github.com/stretchr/objx/accessors_test.go | 271 +- .../github.com/stretchr/objx/codegen/template.txt | 166 +- .../stretchr/objx/codegen/template_test.txt | 121 + vendor/github.com/stretchr/objx/conversions.go | 19 +- .../github.com/stretchr/objx/conversions_test.go | 64 +- vendor/github.com/stretchr/objx/doc.go | 136 +- vendor/github.com/stretchr/objx/fixture_test.go | 14 +- vendor/github.com/stretchr/objx/map.go | 54 +- vendor/github.com/stretchr/objx/map_for_test.go | 10 - vendor/github.com/stretchr/objx/map_test.go | 169 +- vendor/github.com/stretchr/objx/mutations.go | 42 +- vendor/github.com/stretchr/objx/mutations_test.go | 133 +- vendor/github.com/stretchr/objx/security.go | 8 +- vendor/github.com/stretchr/objx/security_test.go | 10 +- .../stretchr/objx/simple_example_test.go | 13 +- vendor/github.com/stretchr/objx/tests_test.go | 11 +- .../stretchr/objx/type_specific_codegen.go | 460 +- .../stretchr/objx/type_specific_codegen_test.go | 863 +-- vendor/github.com/stretchr/objx/value.go | 40 + vendor/github.com/stretchr/objx/value_test.go | 75 +- .../objx/vendor/github.com/davecgh/go-spew/LICENSE | 15 + .../github.com/davecgh/go-spew/spew/bypass.go | 152 + .../github.com/davecgh/go-spew/spew/bypasssafe.go | 38 + .../github.com/davecgh/go-spew/spew/common.go | 341 + .../github.com/davecgh/go-spew/spew/config.go | 306 + .../vendor/github.com/davecgh/go-spew/spew/doc.go | 211 + .../vendor/github.com/davecgh/go-spew/spew/dump.go | 509 ++ .../github.com/davecgh/go-spew/spew/format.go | 419 ++ .../vendor/github.com/davecgh/go-spew/spew/spew.go | 148 + .../vendor/github.com/pmezard/go-difflib/LICENSE | 27 + .../pmezard/go-difflib/difflib/difflib.go | 772 ++ .../vendor/github.com/stretchr/testify/LICENSE | 22 + .../stretchr/testify/assert/assertion_format.go | 405 ++ .../stretchr/testify/assert/assertion_forward.go | 798 ++ .../stretchr/testify/assert/assertions.go | 1312 ++++ .../github.com/stretchr/testify/assert/doc.go | 45 + .../github.com/stretchr/testify/assert/errors.go | 10 + .../stretchr/testify/assert/forward_assertions.go | 16 + .../stretchr/testify/assert/http_assertions.go | 127 + .../github.com/stretchr/testify/require/doc.go | 28 + .../testify/require/forward_requirements.go | 16 + .../github.com/stretchr/testify/require/require.go | 979 +++ .../stretchr/testify/require/require_forward.go | 799 ++ .../stretchr/testify/require/requirements.go | 9 + .../github.com/stretchr/testify/.travis.gofmt.sh | 7 + .../stretchr/testify/.travis.gogenerate.sh | 13 + .../github.com/stretchr/testify/.travis.govet.sh | 10 + vendor/github.com/stretchr/testify/.travis.yml | 13 +- .../github.com/stretchr/testify/Godeps/Godeps.json | 23 - vendor/github.com/stretchr/testify/Godeps/Readme | 5 - vendor/github.com/stretchr/testify/Gopkg.lock | 25 + vendor/github.com/stretchr/testify/Gopkg.toml | 26 + vendor/github.com/stretchr/testify/LICENCE.txt | 22 - .../github.com/stretchr/testify/_codegen/main.go | 37 +- .../stretchr/testify/assert/assertion_format.go | 405 ++ .../testify/assert/assertion_format.go.tmpl | 4 + .../stretchr/testify/assert/assertion_forward.go | 623 +- .../stretchr/testify/assert/assertions.go | 556 +- .../stretchr/testify/assert/assertions_test.go | 379 +- .../stretchr/testify/assert/forward_assertions.go | 2 +- .../stretchr/testify/assert/http_assertions.go | 59 +- .../testify/assert/http_assertions_test.go | 53 +- vendor/github.com/stretchr/testify/mock/mock.go | 141 +- .../github.com/stretchr/testify/mock/mock_test.go | 236 +- .../testify/require/forward_requirements.go | 2 +- .../github.com/stretchr/testify/require/require.go | 943 ++- .../stretchr/testify/require/require.go.tmpl | 6 +- .../stretchr/testify/require/require_forward.go | 623 +- .../stretchr/testify/require/requirements.go | 2 +- .../stretchr/testify/suite/interfaces.go | 12 + vendor/github.com/stretchr/testify/suite/suite.go | 27 +- .../stretchr/testify/suite/suite_test.go | 69 +- .../vendor/github.com/davecgh/go-spew/.gitignore | 22 + .../vendor/github.com/davecgh/go-spew/.travis.yml | 14 + .../vendor/github.com/davecgh/go-spew/LICENSE | 2 +- .../vendor/github.com/davecgh/go-spew/README.md | 205 + .../github.com/davecgh/go-spew/cov_report.sh | 22 + .../github.com/davecgh/go-spew/spew/bypass.go | 2 +- .../github.com/davecgh/go-spew/spew/bypasssafe.go | 2 +- .../github.com/davecgh/go-spew/spew/common.go | 2 +- .../github.com/davecgh/go-spew/spew/common_test.go | 298 + .../github.com/davecgh/go-spew/spew/config.go | 11 +- .../vendor/github.com/davecgh/go-spew/spew/doc.go | 11 +- .../vendor/github.com/davecgh/go-spew/spew/dump.go | 8 +- .../github.com/davecgh/go-spew/spew/dump_test.go | 1042 +++ .../davecgh/go-spew/spew/dumpcgo_test.go | 99 + .../davecgh/go-spew/spew/dumpnocgo_test.go | 26 + .../davecgh/go-spew/spew/example_test.go | 226 + .../github.com/davecgh/go-spew/spew/format.go | 2 +- .../github.com/davecgh/go-spew/spew/format_test.go | 1558 ++++ .../davecgh/go-spew/spew/internal_test.go | 87 + .../davecgh/go-spew/spew/internalunsafe_test.go | 102 + .../vendor/github.com/davecgh/go-spew/spew/spew.go | 2 +- .../github.com/davecgh/go-spew/spew/spew_test.go | 320 + .../davecgh/go-spew/spew/testdata/dumpcgo.go | 82 + .../github.com/davecgh/go-spew/test_coverage.txt | 61 + .../github.com/pmezard/go-difflib/.travis.yml | 5 + .../vendor/github.com/pmezard/go-difflib/README.md | 50 + .../pmezard/go-difflib/difflib/difflib_test.go | 352 + .../github.com/stretchr/objx/accessors_test.go | 145 + .../github.com/stretchr/objx/conversions_test.go | 94 + .../github.com/stretchr/objx/fixture_test.go | 98 + .../github.com/stretchr/objx/map_for_test.go | 10 + .../vendor/github.com/stretchr/objx/map_test.go | 147 + .../github.com/stretchr/objx/mutations_test.go | 77 + .../github.com/stretchr/objx/security_test.go | 12 + .../stretchr/objx/simple_example_test.go | 41 + .../vendor/github.com/stretchr/objx/tests_test.go | 24 + .../stretchr/objx/type_specific_codegen_test.go | 2867 ++++++++ .../vendor/github.com/stretchr/objx/value_test.go | 1 + vendor/github.com/tylerb/graceful/README.md | 5 + vendor/github.com/xenolf/lego/README.md | 2 +- vendor/github.com/xenolf/lego/acme/http.go | 1 + vendor/github.com/xenolf/lego/cli.go | 2 +- .../xenolf/lego/providers/dns/exoscale/exoscale.go | 26 +- .../golang.org/x/crypto/acme/autocert/autocert.go | 316 +- .../x/crypto/acme/autocert/autocert_test.go | 151 + .../x/crypto/acme/autocert/example_test.go | 3 +- vendor/golang.org/x/crypto/argon2/blamka_amd64.go | 2 + vendor/golang.org/x/crypto/ssh/cipher.go | 240 +- vendor/golang.org/x/crypto/ssh/cipher_test.go | 11 +- vendor/golang.org/x/crypto/ssh/client_test.go | 92 +- vendor/golang.org/x/crypto/ssh/common.go | 16 +- .../golang.org/x/crypto/ssh/test/session_test.go | 61 +- vendor/golang.org/x/crypto/ssh/transport.go | 56 +- vendor/golang.org/x/crypto/ssh/transport_test.go | 14 +- vendor/golang.org/x/net/html/token.go | 4 +- vendor/golang.org/x/net/http2/ciphers.go | 2 +- .../golang.org/x/net/http2/configure_transport.go | 2 +- vendor/golang.org/x/net/http2/transport.go | 21 +- vendor/golang.org/x/net/internal/iana/gen.go | 6 +- vendor/golang.org/x/net/ipv4/gen.go | 2 +- vendor/golang.org/x/net/ipv6/gen.go | 2 +- vendor/golang.org/x/sys/plan9/asm_plan9_arm.s | 25 + .../golang.org/x/sys/plan9/zsyscall_plan9_arm.go | 284 + vendor/golang.org/x/sys/unix/dirent.go | 89 +- vendor/golang.org/x/sys/unix/linux/types.go | 61 +- vendor/golang.org/x/sys/unix/mkerrors.sh | 2 + vendor/golang.org/x/sys/unix/mkpost.go | 14 +- vendor/golang.org/x/sys/unix/syscall_darwin.go | 13 +- vendor/golang.org/x/sys/unix/syscall_dragonfly.go | 17 +- vendor/golang.org/x/sys/unix/syscall_freebsd.go | 13 +- vendor/golang.org/x/sys/unix/syscall_linux.go | 46 +- vendor/golang.org/x/sys/unix/syscall_linux_test.go | 102 +- vendor/golang.org/x/sys/unix/syscall_netbsd.go | 13 +- vendor/golang.org/x/sys/unix/syscall_openbsd.go | 13 +- vendor/golang.org/x/sys/unix/syscall_solaris.go | 17 +- vendor/golang.org/x/sys/unix/syscall_unix.go | 4 + vendor/golang.org/x/sys/unix/zerrors_linux_386.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_amd64.go | 21 + vendor/golang.org/x/sys/unix/zerrors_linux_arm.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_arm64.go | 21 + vendor/golang.org/x/sys/unix/zerrors_linux_mips.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_mips64.go | 21 + .../x/sys/unix/zerrors_linux_mips64le.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_mipsle.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_ppc64.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_ppc64le.go | 21 + .../golang.org/x/sys/unix/zerrors_linux_s390x.go | 21 + vendor/golang.org/x/sys/unix/zsyscall_linux_386.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_amd64.go | 15 + vendor/golang.org/x/sys/unix/zsyscall_linux_arm.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_arm64.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_mips.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_mips64.go | 15 + .../x/sys/unix/zsyscall_linux_mips64le.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_mipsle.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_ppc64.go | 15 + .../x/sys/unix/zsyscall_linux_ppc64le.go | 15 + .../golang.org/x/sys/unix/zsyscall_linux_s390x.go | 15 + vendor/golang.org/x/sys/unix/ztypes_linux_386.go | 100 +- vendor/golang.org/x/sys/unix/ztypes_linux_amd64.go | 136 +- vendor/golang.org/x/sys/unix/ztypes_linux_arm.go | 142 +- vendor/golang.org/x/sys/unix/ztypes_linux_arm64.go | 136 +- vendor/golang.org/x/sys/unix/ztypes_linux_mips.go | 138 +- .../golang.org/x/sys/unix/ztypes_linux_mips64.go | 136 +- .../golang.org/x/sys/unix/ztypes_linux_mips64le.go | 136 +- .../golang.org/x/sys/unix/ztypes_linux_mipsle.go | 138 +- vendor/golang.org/x/sys/unix/ztypes_linux_ppc64.go | 136 +- .../golang.org/x/sys/unix/ztypes_linux_ppc64le.go | 136 +- vendor/golang.org/x/sys/unix/ztypes_linux_s390x.go | 58 +- vendor/google.golang.org/appengine/.travis.yml | 24 + vendor/google.golang.org/appengine/CONTRIBUTING.md | 90 + vendor/google.golang.org/appengine/LICENSE | 202 + vendor/google.golang.org/appengine/README.md | 73 + vendor/google.golang.org/appengine/aetest/doc.go | 42 + .../google.golang.org/appengine/aetest/instance.go | 55 + .../appengine/aetest/instance_classic.go | 21 + .../appengine/aetest/instance_test.go | 119 + .../appengine/aetest/instance_vm.go | 282 + vendor/google.golang.org/appengine/aetest/user.go | 36 + vendor/google.golang.org/appengine/appengine.go | 113 + .../google.golang.org/appengine/appengine_test.go | 49 + vendor/google.golang.org/appengine/appengine_vm.go | 20 + .../appengine/blobstore/blobstore.go | 276 + .../appengine/blobstore/blobstore_test.go | 183 + .../google.golang.org/appengine/blobstore/read.go | 160 + .../appengine/capability/capability.go | 52 + .../google.golang.org/appengine/channel/channel.go | 87 + .../appengine/channel/channel_test.go | 21 + .../appengine/cloudsql/cloudsql.go | 62 + .../appengine/cloudsql/cloudsql_classic.go | 17 + .../appengine/cloudsql/cloudsql_vm.go | 16 + .../appengine/cmd/aebundler/aebundler.go | 342 + .../appengine/cmd/aedeploy/aedeploy.go | 72 + vendor/google.golang.org/appengine/cmd/aefix/ae.go | 185 + .../appengine/cmd/aefix/ae_test.go | 144 + .../google.golang.org/appengine/cmd/aefix/fix.go | 848 +++ .../google.golang.org/appengine/cmd/aefix/main.go | 258 + .../appengine/cmd/aefix/main_test.go | 129 + .../appengine/cmd/aefix/typecheck.go | 673 ++ .../appengine/datastore/datastore.go | 407 ++ .../appengine/datastore/datastore_test.go | 1744 +++++ .../google.golang.org/appengine/datastore/doc.go | 361 + .../google.golang.org/appengine/datastore/key.go | 309 + .../appengine/datastore/key_test.go | 204 + .../google.golang.org/appengine/datastore/load.go | 429 ++ .../appengine/datastore/load_test.go | 656 ++ .../appengine/datastore/metadata.go | 78 + .../google.golang.org/appengine/datastore/prop.go | 330 + .../appengine/datastore/prop_test.go | 547 ++ .../google.golang.org/appengine/datastore/query.go | 724 ++ .../appengine/datastore/query_test.go | 583 ++ .../google.golang.org/appengine/datastore/save.go | 327 + .../appengine/datastore/time_test.go | 65 + .../appengine/datastore/transaction.go | 87 + vendor/google.golang.org/appengine/delay/delay.go | 295 + .../appengine/delay/delay_go17.go | 23 + .../appengine/delay/delay_go17_test.go | 55 + .../appengine/delay/delay_pre17.go | 19 + .../appengine/delay/delay_test.go | 428 ++ .../appengine/demos/guestbook/app.yaml | 14 + .../appengine/demos/guestbook/favicon.ico | Bin 0 -> 1150 bytes .../appengine/demos/guestbook/guestbook.go | 109 + .../appengine/demos/guestbook/index.yaml | 7 + .../demos/guestbook/templates/guestbook.html | 26 + .../appengine/demos/helloworld/app.yaml | 10 + .../appengine/demos/helloworld/favicon.ico | Bin 0 -> 1150 bytes .../appengine/demos/helloworld/helloworld.go | 50 + vendor/google.golang.org/appengine/errors.go | 46 + vendor/google.golang.org/appengine/file/file.go | 28 + vendor/google.golang.org/appengine/identity.go | 142 + vendor/google.golang.org/appengine/image/image.go | 67 + .../appengine/internal/aetesting/fake.go | 81 + vendor/google.golang.org/appengine/internal/api.go | 660 ++ .../appengine/internal/api_classic.go | 169 + .../appengine/internal/api_common.go | 123 + .../appengine/internal/api_pre17.go | 682 ++ .../appengine/internal/api_race_test.go | 9 + .../appengine/internal/api_test.go | 466 ++ .../google.golang.org/appengine/internal/app_id.go | 28 + .../appengine/internal/app_id_test.go | 34 + .../app_identity/app_identity_service.pb.go | 296 + .../app_identity/app_identity_service.proto | 64 + .../appengine/internal/base/api_base.pb.go | 133 + .../appengine/internal/base/api_base.proto | 33 + .../internal/blobstore/blobstore_service.pb.go | 347 + .../internal/blobstore/blobstore_service.proto | 71 + .../internal/capability/capability_service.pb.go | 125 + .../internal/capability/capability_service.proto | 28 + .../internal/channel/channel_service.pb.go | 154 + .../internal/channel/channel_service.proto | 30 + .../internal/datastore/datastore_v3.pb.go | 2778 +++++++ .../internal/datastore/datastore_v3.proto | 541 ++ .../appengine/internal/identity.go | 14 + .../appengine/internal/identity_classic.go | 57 + .../appengine/internal/identity_vm.go | 101 + .../appengine/internal/image/images_service.pb.go | 845 +++ .../appengine/internal/image/images_service.proto | 162 + .../appengine/internal/internal.go | 110 + .../appengine/internal/internal_vm_test.go | 60 + .../appengine/internal/log/log_service.pb.go | 899 +++ .../appengine/internal/log/log_service.proto | 150 + .../appengine/internal/mail/mail_service.pb.go | 229 + .../appengine/internal/mail/mail_service.proto | 45 + .../google.golang.org/appengine/internal/main.go | 15 + .../appengine/internal/main_vm.go | 48 + .../internal/memcache/memcache_service.pb.go | 938 +++ .../internal/memcache/memcache_service.proto | 165 + .../appengine/internal/metadata.go | 61 + .../internal/modules/modules_service.pb.go | 375 + .../internal/modules/modules_service.proto | 80 + vendor/google.golang.org/appengine/internal/net.go | 56 + .../appengine/internal/net_test.go | 58 + .../google.golang.org/appengine/internal/regen.sh | 40 + .../appengine/internal/remote_api/remote_api.pb.go | 231 + .../appengine/internal/remote_api/remote_api.proto | 44 + .../appengine/internal/search/search.pb.go | 2488 +++++++ .../appengine/internal/search/search.proto | 394 + .../appengine/internal/socket/socket_service.pb.go | 1858 +++++ .../appengine/internal/socket/socket_service.proto | 460 ++ .../appengine/internal/system/system_service.pb.go | 198 + .../appengine/internal/system/system_service.proto | 49 + .../internal/taskqueue/taskqueue_service.pb.go | 1888 +++++ .../internal/taskqueue/taskqueue_service.proto | 342 + .../appengine/internal/transaction.go | 107 + .../internal/urlfetch/urlfetch_service.pb.go | 355 + .../internal/urlfetch/urlfetch_service.proto | 64 + .../appengine/internal/user/user_service.pb.go | 289 + .../appengine/internal/user/user_service.proto | 58 + .../appengine/internal/xmpp/xmpp_service.pb.go | 427 ++ .../appengine/internal/xmpp/xmpp_service.proto | 83 + vendor/google.golang.org/appengine/log/api.go | 40 + vendor/google.golang.org/appengine/log/log.go | 323 + vendor/google.golang.org/appengine/log/log_test.go | 112 + vendor/google.golang.org/appengine/mail/mail.go | 123 + .../google.golang.org/appengine/mail/mail_test.go | 65 + .../appengine/memcache/memcache.go | 526 ++ .../appengine/memcache/memcache_test.go | 263 + .../google.golang.org/appengine/module/module.go | 113 + .../appengine/module/module_test.go | 124 + vendor/google.golang.org/appengine/namespace.go | 25 + .../google.golang.org/appengine/namespace_test.go | 39 + .../appengine/remote_api/client.go | 194 + .../appengine/remote_api/client_test.go | 43 + .../appengine/remote_api/remote_api.go | 152 + .../google.golang.org/appengine/runtime/runtime.go | 148 + .../appengine/runtime/runtime_test.go | 101 + vendor/google.golang.org/appengine/search/doc.go | 209 + vendor/google.golang.org/appengine/search/field.go | 82 + .../google.golang.org/appengine/search/search.go | 1189 +++ .../appengine/search/search_test.go | 1270 ++++ .../google.golang.org/appengine/search/struct.go | 251 + .../appengine/search/struct_test.go | 213 + vendor/google.golang.org/appengine/socket/doc.go | 10 + .../appengine/socket/socket_classic.go | 290 + .../appengine/socket/socket_vm.go | 64 + .../appengine/taskqueue/taskqueue.go | 541 ++ .../appengine/taskqueue/taskqueue_test.go | 173 + vendor/google.golang.org/appengine/timeout.go | 20 + .../appengine/urlfetch/urlfetch.go | 210 + vendor/google.golang.org/appengine/user/oauth.go | 52 + vendor/google.golang.org/appengine/user/user.go | 84 + .../appengine/user/user_classic.go | 44 + .../google.golang.org/appengine/user/user_test.go | 99 + vendor/google.golang.org/appengine/user/user_vm.go | 38 + vendor/google.golang.org/appengine/xmpp/xmpp.go | 253 + .../google.golang.org/appengine/xmpp/xmpp_test.go | 173 + vendor/gopkg.in/olivere/elastic.v5/.gitignore | 1 + vendor/gopkg.in/olivere/elastic.v5/.travis.yml | 3 +- .../gopkg.in/olivere/elastic.v5/CHANGELOG-6.0.md | 18 + vendor/gopkg.in/olivere/elastic.v5/CONTRIBUTORS | 4 + .../gopkg.in/olivere/elastic.v5/ISSUE_TEMPLATE.md | 1 + vendor/gopkg.in/olivere/elastic.v5/README.md | 59 +- .../olivere/elastic.v5/acknowledged_response.go | 4 +- vendor/gopkg.in/olivere/elastic.v5/bulk.go | 33 +- .../olivere/elastic.v5/bulk_delete_request.go | 81 +- .../elastic.v5/bulk_delete_request_easyjson.go | 230 + .../olivere/elastic.v5/bulk_delete_request_test.go | 25 +- .../olivere/elastic.v5/bulk_index_request.go | 102 +- .../elastic.v5/bulk_index_request_easyjson.go | 262 + .../olivere/elastic.v5/bulk_index_request_test.go | 41 +- .../gopkg.in/olivere/elastic.v5/bulk_processor.go | 104 +- .../olivere/elastic.v5/bulk_processor_test.go | 11 +- vendor/gopkg.in/olivere/elastic.v5/bulk_test.go | 188 +- .../olivere/elastic.v5/bulk_update_request.go | 172 +- .../elastic.v5/bulk_update_request_easyjson.go | 461 ++ .../olivere/elastic.v5/bulk_update_request_test.go | 60 +- vendor/gopkg.in/olivere/elastic.v5/clear_scroll.go | 11 +- .../olivere/elastic.v5/clear_scroll_test.go | 6 +- vendor/gopkg.in/olivere/elastic.v5/client.go | 123 +- vendor/gopkg.in/olivere/elastic.v5/client_test.go | 64 +- .../elastic.v5/cluster-test/cluster-test.go | 2 +- .../gopkg.in/olivere/elastic.v5/cluster_health.go | 10 +- .../gopkg.in/olivere/elastic.v5/cluster_state.go | 20 +- .../gopkg.in/olivere/elastic.v5/cluster_stats.go | 18 +- vendor/gopkg.in/olivere/elastic.v5/count.go | 11 +- vendor/gopkg.in/olivere/elastic.v5/count_test.go | 10 +- vendor/gopkg.in/olivere/elastic.v5/decoder_test.go | 2 +- vendor/gopkg.in/olivere/elastic.v5/delete.go | 30 +- .../gopkg.in/olivere/elastic.v5/delete_by_query.go | 11 +- .../olivere/elastic.v5/delete_by_query_test.go | 8 +- .../gopkg.in/olivere/elastic.v5/delete_template.go | 109 - .../olivere/elastic.v5/delete_template_test.go | 23 - vendor/gopkg.in/olivere/elastic.v5/delete_test.go | 25 +- .../gopkg.in/olivere/elastic.v5/docker-compose.yml | 23 - vendor/gopkg.in/olivere/elastic.v5/example_test.go | 69 +- vendor/gopkg.in/olivere/elastic.v5/exists.go | 13 +- vendor/gopkg.in/olivere/elastic.v5/exists_test.go | 6 +- vendor/gopkg.in/olivere/elastic.v5/explain.go | 13 +- vendor/gopkg.in/olivere/elastic.v5/explain_test.go | 4 +- .../olivere/elastic.v5/fetch_source_context.go | 2 +- vendor/gopkg.in/olivere/elastic.v5/field_caps.go | 202 + .../gopkg.in/olivere/elastic.v5/field_caps_test.go | 146 + vendor/gopkg.in/olivere/elastic.v5/field_stats.go | 259 - .../olivere/elastic.v5/field_stats_test.go | 282 - vendor/gopkg.in/olivere/elastic.v5/get.go | 12 +- vendor/gopkg.in/olivere/elastic.v5/get_template.go | 113 - .../olivere/elastic.v5/get_template_test.go | 52 - vendor/gopkg.in/olivere/elastic.v5/get_test.go | 22 +- vendor/gopkg.in/olivere/elastic.v5/highlight.go | 20 +- .../gopkg.in/olivere/elastic.v5/highlight_test.go | 14 +- vendor/gopkg.in/olivere/elastic.v5/index.go | 31 +- vendor/gopkg.in/olivere/elastic.v5/index_test.go | 30 +- .../gopkg.in/olivere/elastic.v5/indices_analyze.go | 15 +- .../gopkg.in/olivere/elastic.v5/indices_close.go | 14 +- .../gopkg.in/olivere/elastic.v5/indices_create.go | 18 +- .../gopkg.in/olivere/elastic.v5/indices_delete.go | 12 +- .../olivere/elastic.v5/indices_delete_template.go | 16 +- .../gopkg.in/olivere/elastic.v5/indices_exists.go | 13 +- .../olivere/elastic.v5/indices_exists_template.go | 11 +- .../elastic.v5/indices_exists_template_test.go | 4 +- .../olivere/elastic.v5/indices_exists_type.go | 13 +- .../olivere/elastic.v5/indices_exists_type_test.go | 8 +- .../gopkg.in/olivere/elastic.v5/indices_flush.go | 12 +- .../olivere/elastic.v5/indices_forcemerge.go | 10 +- vendor/gopkg.in/olivere/elastic.v5/indices_get.go | 12 +- .../olivere/elastic.v5/indices_get_aliases.go | 12 +- .../olivere/elastic.v5/indices_get_aliases_test.go | 15 +- .../elastic.v5/indices_get_field_mapping.go | 12 +- .../olivere/elastic.v5/indices_get_mapping.go | 12 +- .../olivere/elastic.v5/indices_get_settings.go | 12 +- .../olivere/elastic.v5/indices_get_template.go | 12 +- vendor/gopkg.in/olivere/elastic.v5/indices_open.go | 16 +- .../olivere/elastic.v5/indices_put_alias.go | 13 +- .../olivere/elastic.v5/indices_put_alias_test.go | 6 +- .../olivere/elastic.v5/indices_put_mapping.go | 17 +- .../olivere/elastic.v5/indices_put_mapping_test.go | 30 +- .../olivere/elastic.v5/indices_put_settings.go | 17 +- .../olivere/elastic.v5/indices_put_template.go | 17 +- .../gopkg.in/olivere/elastic.v5/indices_refresh.go | 10 +- .../olivere/elastic.v5/indices_refresh_test.go | 6 +- .../olivere/elastic.v5/indices_rollover.go | 15 +- .../olivere/elastic.v5/indices_rollover_test.go | 4 +- .../olivere/elastic.v5/indices_segments.go | 237 + .../olivere/elastic.v5/indices_segments_test.go | 86 + .../gopkg.in/olivere/elastic.v5/indices_shrink.go | 18 +- .../gopkg.in/olivere/elastic.v5/indices_stats.go | 39 +- .../olivere/elastic.v5/ingest_delete_pipeline.go | 16 +- .../olivere/elastic.v5/ingest_get_pipeline.go | 12 +- .../olivere/elastic.v5/ingest_put_pipeline.go | 17 +- .../olivere/elastic.v5/ingest_simulate_pipeline.go | 13 +- vendor/gopkg.in/olivere/elastic.v5/mget.go | 13 +- vendor/gopkg.in/olivere/elastic.v5/mget_test.go | 10 +- vendor/gopkg.in/olivere/elastic.v5/msearch.go | 7 +- vendor/gopkg.in/olivere/elastic.v5/msearch_test.go | 14 +- vendor/gopkg.in/olivere/elastic.v5/mtermvectors.go | 13 +- .../olivere/elastic.v5/mtermvectors_test.go | 18 +- vendor/gopkg.in/olivere/elastic.v5/nodes_info.go | 12 +- vendor/gopkg.in/olivere/elastic.v5/nodes_stats.go | 45 +- .../gopkg.in/olivere/elastic.v5/percolate_test.go | 27 +- vendor/gopkg.in/olivere/elastic.v5/ping.go | 2 +- vendor/gopkg.in/olivere/elastic.v5/put_template.go | 145 - .../olivere/elastic.v5/put_template_test.go | 53 - .../elastic.v5/recipes/bulk_insert/bulk_insert.go | 4 +- .../olivere/elastic.v5/recipes/connect/connect.go | 2 +- .../recipes/sliced_scroll/sliced_scroll.go | 4 +- vendor/gopkg.in/olivere/elastic.v5/reindex.go | 22 +- vendor/gopkg.in/olivere/elastic.v5/reindex_test.go | 10 +- vendor/gopkg.in/olivere/elastic.v5/request.go | 53 +- vendor/gopkg.in/olivere/elastic.v5/request_test.go | 55 +- vendor/gopkg.in/olivere/elastic.v5/retrier_test.go | 55 +- vendor/gopkg.in/olivere/elastic.v5/run-es-5.0.0.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.0.1.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.1.1.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.1.2.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.0.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.1.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.2.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.3.0.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.4.0.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.4.1.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.5.0.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.5.1.sh | 1 - vendor/gopkg.in/olivere/elastic.v5/run-es-5.6.3.sh | 2 - vendor/gopkg.in/olivere/elastic.v5/run-es.sh | 3 + vendor/gopkg.in/olivere/elastic.v5/script.go | 26 +- vendor/gopkg.in/olivere/elastic.v5/script_test.go | 25 +- vendor/gopkg.in/olivere/elastic.v5/scroll.go | 44 +- vendor/gopkg.in/olivere/elastic.v5/scroll_test.go | 18 +- vendor/gopkg.in/olivere/elastic.v5/search.go | 39 +- vendor/gopkg.in/olivere/elastic.v5/search_aggs.go | 90 +- .../elastic.v5/search_aggs_bucket_children.go | 2 +- .../search_aggs_bucket_count_thresholds.go | 13 + .../search_aggs_bucket_date_histogram.go | 2 +- .../elastic.v5/search_aggs_bucket_date_range.go | 2 +- .../elastic.v5/search_aggs_bucket_filter.go | 2 +- .../elastic.v5/search_aggs_bucket_filters.go | 2 +- .../elastic.v5/search_aggs_bucket_geo_distance.go | 2 +- .../elastic.v5/search_aggs_bucket_global.go | 2 +- .../elastic.v5/search_aggs_bucket_histogram.go | 2 +- .../elastic.v5/search_aggs_bucket_ip_range.go | 195 + .../elastic.v5/search_aggs_bucket_ip_range_test.go | 90 + .../elastic.v5/search_aggs_bucket_missing.go | 2 +- .../elastic.v5/search_aggs_bucket_nested.go | 2 +- .../olivere/elastic.v5/search_aggs_bucket_range.go | 2 +- .../search_aggs_bucket_reverse_nested.go | 2 +- .../elastic.v5/search_aggs_bucket_sampler.go | 2 +- .../search_aggs_bucket_significant_terms.go | 18 +- .../search_aggs_bucket_significant_terms_test.go | 2 +- .../search_aggs_bucket_significant_text.go | 245 + .../search_aggs_bucket_significant_text_test.go | 66 + .../olivere/elastic.v5/search_aggs_matrix_stats.go | 2 +- .../olivere/elastic.v5/search_aggs_metrics_avg.go | 2 +- .../elastic.v5/search_aggs_metrics_cardinality.go | 2 +- .../search_aggs_metrics_extended_stats.go | 2 +- .../elastic.v5/search_aggs_metrics_geo_bounds.go | 2 +- .../olivere/elastic.v5/search_aggs_metrics_max.go | 2 +- .../olivere/elastic.v5/search_aggs_metrics_min.go | 2 +- .../search_aggs_metrics_percentile_ranks.go | 2 +- .../elastic.v5/search_aggs_metrics_percentiles.go | 2 +- .../elastic.v5/search_aggs_metrics_stats.go | 2 +- .../olivere/elastic.v5/search_aggs_metrics_sum.go | 2 +- .../elastic.v5/search_aggs_metrics_top_hits.go | 2 +- .../elastic.v5/search_aggs_metrics_value_count.go | 2 +- .../elastic.v5/search_aggs_pipeline_avg_bucket.go | 2 +- .../search_aggs_pipeline_bucket_script.go | 2 +- .../search_aggs_pipeline_bucket_script_test.go | 2 +- .../search_aggs_pipeline_bucket_selector.go | 2 +- .../search_aggs_pipeline_bucket_selector_test.go | 2 +- .../search_aggs_pipeline_cumulative_sum.go | 2 +- .../elastic.v5/search_aggs_pipeline_derivative.go | 2 +- .../elastic.v5/search_aggs_pipeline_max_bucket.go | 2 +- .../elastic.v5/search_aggs_pipeline_min_bucket.go | 2 +- .../elastic.v5/search_aggs_pipeline_mov_avg.go | 14 +- .../search_aggs_pipeline_percentiles_bucket.go | 2 +- .../elastic.v5/search_aggs_pipeline_serial_diff.go | 2 +- .../search_aggs_pipeline_stats_bucket.go | 2 +- .../elastic.v5/search_aggs_pipeline_sum_bucket.go | 2 +- .../elastic.v5/search_aggs_pipeline_test.go | 143 +- .../olivere/elastic.v5/search_aggs_test.go | 12 +- .../olivere/elastic.v5/search_collapse_builder.go | 2 +- .../olivere/elastic.v5/search_queries_bool.go | 13 +- .../olivere/elastic.v5/search_queries_bool_test.go | 3 +- .../olivere/elastic.v5/search_queries_boosting.go | 2 +- .../elastic.v5/search_queries_common_terms.go | 11 +- .../elastic.v5/search_queries_common_terms_test.go | 6 +- .../elastic.v5/search_queries_constant_score.go | 2 +- .../olivere/elastic.v5/search_queries_dis_max.go | 2 +- .../olivere/elastic.v5/search_queries_exists.go | 2 +- .../olivere/elastic.v5/search_queries_fsq.go | 2 +- .../elastic.v5/search_queries_fsq_score_funcs.go | 28 +- .../olivere/elastic.v5/search_queries_fsq_test.go | 2 +- .../olivere/elastic.v5/search_queries_fuzzy.go | 2 +- .../elastic.v5/search_queries_geo_bounding_box.go | 2 +- .../elastic.v5/search_queries_geo_distance.go | 11 +- .../elastic.v5/search_queries_geo_distance_test.go | 3 +- .../elastic.v5/search_queries_geo_polygon.go | 2 +- .../olivere/elastic.v5/search_queries_has_child.go | 2 +- .../elastic.v5/search_queries_has_parent.go | 2 +- .../olivere/elastic.v5/search_queries_ids.go | 2 +- .../olivere/elastic.v5/search_queries_indices.go | 89 - .../elastic.v5/search_queries_indices_test.go | 46 - .../olivere/elastic.v5/search_queries_match.go | 2 +- .../olivere/elastic.v5/search_queries_match_all.go | 2 +- .../elastic.v5/search_queries_match_none.go | 2 +- .../elastic.v5/search_queries_match_phrase.go | 2 +- .../search_queries_match_phrase_prefix.go | 2 +- .../elastic.v5/search_queries_more_like_this.go | 24 +- .../search_queries_more_like_this_test.go | 6 +- .../elastic.v5/search_queries_multi_match.go | 2 +- .../olivere/elastic.v5/search_queries_nested.go | 2 +- .../olivere/elastic.v5/search_queries_parent_id.go | 2 +- .../elastic.v5/search_queries_percolator.go | 12 +- .../elastic.v5/search_queries_percolator_test.go | 7 +- .../olivere/elastic.v5/search_queries_prefix.go | 2 +- .../search_queries_prefix_example_test.go | 2 +- .../elastic.v5/search_queries_query_string.go | 97 +- .../olivere/elastic.v5/search_queries_range.go | 2 +- .../olivere/elastic.v5/search_queries_regexp.go | 2 +- .../olivere/elastic.v5/search_queries_script.go | 2 +- .../elastic.v5/search_queries_script_test.go | 4 +- .../search_queries_simple_query_string.go | 2 +- .../search_queries_simple_query_string_test.go | 6 +- .../olivere/elastic.v5/search_queries_slice.go | 2 +- .../olivere/elastic.v5/search_queries_term.go | 2 +- .../olivere/elastic.v5/search_queries_terms.go | 2 +- .../olivere/elastic.v5/search_queries_type.go | 2 +- .../olivere/elastic.v5/search_queries_wildcard.go | 2 +- .../elastic.v5/search_queries_wildcard_test.go | 2 +- .../gopkg.in/olivere/elastic.v5/search_request.go | 4 +- .../gopkg.in/olivere/elastic.v5/search_source.go | 4 +- .../olivere/elastic.v5/search_source_test.go | 4 +- .../olivere/elastic.v5/search_suggester_test.go | 31 +- .../olivere/elastic.v5/search_terms_lookup.go | 2 +- vendor/gopkg.in/olivere/elastic.v5/search_test.go | 381 +- vendor/gopkg.in/olivere/elastic.v5/setup_test.go | 235 +- .../gopkg.in/olivere/elastic.v5/snapshot_create.go | 13 +- .../elastic.v5/snapshot_create_repository.go | 17 +- .../olivere/elastic.v5/snapshot_create_test.go | 2 +- .../elastic.v5/snapshot_delete_repository.go | 16 +- .../olivere/elastic.v5/snapshot_get_repository.go | 12 +- .../elastic.v5/snapshot_verify_repository.go | 12 +- vendor/gopkg.in/olivere/elastic.v5/sort.go | 177 +- vendor/gopkg.in/olivere/elastic.v5/sort_test.go | 52 +- vendor/gopkg.in/olivere/elastic.v5/suggest.go | 158 - .../gopkg.in/olivere/elastic.v5/suggest_field.go | 4 +- .../olivere/elastic.v5/suggest_field_test.go | 2 +- vendor/gopkg.in/olivere/elastic.v5/suggest_test.go | 162 - .../olivere/elastic.v5/suggester_completion.go | 226 +- .../elastic.v5/suggester_completion_fuzzy.go | 179 - .../elastic.v5/suggester_completion_fuzzy_test.go | 50 - .../elastic.v5/suggester_completion_test.go | 58 + .../olivere/elastic.v5/suggester_context.go | 4 +- .../elastic.v5/suggester_context_category.go | 4 +- .../olivere/elastic.v5/suggester_context_geo.go | 4 +- .../olivere/elastic.v5/suggester_context_test.go | 4 +- .../olivere/elastic.v5/suggester_phrase.go | 14 +- .../olivere/elastic.v5/suggester_phrase_test.go | 2 +- .../gopkg.in/olivere/elastic.v5/suggester_term.go | 6 +- vendor/gopkg.in/olivere/elastic.v5/tasks_cancel.go | 10 +- .../gopkg.in/olivere/elastic.v5/tasks_get_task.go | 8 +- vendor/gopkg.in/olivere/elastic.v5/tasks_list.go | 56 +- .../gopkg.in/olivere/elastic.v5/tasks_list_test.go | 8 +- vendor/gopkg.in/olivere/elastic.v5/termvectors.go | 17 +- .../olivere/elastic.v5/termvectors_test.go | 16 +- vendor/gopkg.in/olivere/elastic.v5/update.go | 26 +- .../gopkg.in/olivere/elastic.v5/update_by_query.go | 11 +- .../olivere/elastic.v5/update_by_query_test.go | 2 +- .../olivere/elastic.v5/update_integration_test.go | 58 + vendor/gopkg.in/olivere/elastic.v5/update_test.go | 71 +- 1520 files changed, 183007 insertions(+), 25609 deletions(-) delete mode 100644 vendor/github.com/avct/uasurfer/.gitignore delete mode 100644 vendor/github.com/avct/uasurfer/.travis.yml delete mode 100644 vendor/github.com/avct/uasurfer/LICENSE delete mode 100644 vendor/github.com/avct/uasurfer/README.md delete mode 100644 vendor/github.com/avct/uasurfer/browser.go delete mode 100644 vendor/github.com/avct/uasurfer/const_string.go delete mode 100644 vendor/github.com/avct/uasurfer/device.go delete mode 100644 vendor/github.com/avct/uasurfer/system.go delete mode 100644 vendor/github.com/avct/uasurfer/uasurfer.go delete mode 100644 vendor/github.com/avct/uasurfer/uasurfer_test.go delete mode 100644 vendor/github.com/cpanato/html2text/.gitignore delete mode 100644 vendor/github.com/cpanato/html2text/.travis.yml delete mode 100644 vendor/github.com/cpanato/html2text/LICENSE delete mode 100644 vendor/github.com/cpanato/html2text/README.md delete mode 100644 vendor/github.com/cpanato/html2text/html2text.go delete mode 100644 vendor/github.com/cpanato/html2text/html2text_test.go delete mode 100755 vendor/github.com/cpanato/html2text/testdata/utf8.html delete mode 100755 vendor/github.com/cpanato/html2text/testdata/utf8_with_bom.xhtml create mode 100644 vendor/github.com/go-ldap/ldap/atomic_value.go create mode 100644 vendor/github.com/go-ldap/ldap/atomic_value_go13.go create mode 100644 vendor/github.com/go-sql-driver/mysql/.travis/docker.cnf create mode 100755 vendor/github.com/go-sql-driver/mysql/.travis/wait_mysql.sh create mode 100644 vendor/github.com/go-sql-driver/mysql/benchmark_go18_test.go create mode 100644 vendor/github.com/go-sql-driver/mysql/connection_go18.go create mode 100644 vendor/github.com/go-sql-driver/mysql/connection_go18_test.go create mode 100644 vendor/github.com/go-sql-driver/mysql/driver_go18_test.go create mode 100644 vendor/github.com/go-sql-driver/mysql/fields.go create mode 100644 vendor/github.com/go-sql-driver/mysql/statement_test.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils_go17.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils_go18.go create mode 100644 vendor/github.com/go-sql-driver/mysql/utils_go18_test.go create mode 100644 vendor/github.com/golang/protobuf/proto/discard.go create mode 100644 vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md create mode 100644 vendor/github.com/gorilla/mux/example_route_test.go create mode 100644 vendor/github.com/gorilla/mux/middleware.go create mode 100644 vendor/github.com/gorilla/mux/middleware_test.go create mode 100644 vendor/github.com/gorilla/mux/test_helpers.go create mode 100644 vendor/github.com/gorilla/websocket/proxy.go create mode 100644 vendor/github.com/gorilla/websocket/x_net_proxy.go create mode 100644 vendor/github.com/mailru/easyjson/.gitignore create mode 100644 vendor/github.com/mailru/easyjson/.travis.yml create mode 100644 vendor/github.com/mailru/easyjson/LICENSE create mode 100644 vendor/github.com/mailru/easyjson/Makefile create mode 100644 vendor/github.com/mailru/easyjson/README.md create mode 100644 vendor/github.com/mailru/easyjson/benchmark/codec_test.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/data.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/data_codec.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/data_ffjson.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/data_var.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/default_test.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/dummy_test.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/easyjson_test.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/example.json create mode 100644 vendor/github.com/mailru/easyjson/benchmark/ffjson_test.go create mode 100644 vendor/github.com/mailru/easyjson/benchmark/jsoniter_test.go create mode 100755 vendor/github.com/mailru/easyjson/benchmark/ujson.sh create mode 100644 vendor/github.com/mailru/easyjson/bootstrap/bootstrap.go create mode 100644 vendor/github.com/mailru/easyjson/buffer/pool.go create mode 100644 vendor/github.com/mailru/easyjson/buffer/pool_test.go create mode 100644 vendor/github.com/mailru/easyjson/easyjson/main.go create mode 100644 vendor/github.com/mailru/easyjson/gen/decoder.go create mode 100644 vendor/github.com/mailru/easyjson/gen/encoder.go create mode 100644 vendor/github.com/mailru/easyjson/gen/generator.go create mode 100644 vendor/github.com/mailru/easyjson/gen/generator_test.go create mode 100644 vendor/github.com/mailru/easyjson/helpers.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/bytestostr.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/bytestostr_nounsafe.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/error.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/lexer.go create mode 100644 vendor/github.com/mailru/easyjson/jlexer/lexer_test.go create mode 100644 vendor/github.com/mailru/easyjson/jwriter/writer.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Bool.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Float32.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Float64.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Int.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Int16.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Int32.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Int64.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Int8.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_String.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Uint.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Uint16.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Uint32.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Uint64.go create mode 100644 vendor/github.com/mailru/easyjson/opt/gotemplate_Uint8.go create mode 100644 vendor/github.com/mailru/easyjson/opt/optional/opt.go create mode 100644 vendor/github.com/mailru/easyjson/opt/opts.go create mode 100644 vendor/github.com/mailru/easyjson/parser/parser.go create mode 100644 vendor/github.com/mailru/easyjson/parser/parser_unix.go create mode 100644 vendor/github.com/mailru/easyjson/parser/parser_windows.go create mode 100644 vendor/github.com/mailru/easyjson/raw.go create mode 100644 vendor/github.com/mailru/easyjson/tests/basic_test.go create mode 100644 vendor/github.com/mailru/easyjson/tests/data.go create mode 100644 vendor/github.com/mailru/easyjson/tests/errors.go create mode 100644 vendor/github.com/mailru/easyjson/tests/errors_test.go create mode 100644 vendor/github.com/mailru/easyjson/tests/named_type.go create mode 100644 vendor/github.com/mailru/easyjson/tests/nested_easy.go create mode 100644 vendor/github.com/mailru/easyjson/tests/nothing.go create mode 100644 vendor/github.com/mailru/easyjson/tests/omitempty.go create mode 100644 vendor/github.com/mailru/easyjson/tests/opt_test.go create mode 100644 vendor/github.com/mailru/easyjson/tests/required_test.go create mode 100644 vendor/github.com/mailru/easyjson/tests/snake.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/Makefile.TRAVIS create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/.gitignore create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/Makefile delete mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/pbutil/fixtures_test.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/testdata/README.THIRD_PARTY create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/testdata/test.pb.go create mode 100644 vendor/github.com/matttproud/golang_protobuf_extensions/testdata/test.proto delete mode 100644 vendor/github.com/minio/go-homedir/LICENSE delete mode 100644 vendor/github.com/minio/go-homedir/README.md delete mode 100644 vendor/github.com/minio/go-homedir/dir_posix.go delete mode 100644 vendor/github.com/minio/go-homedir/dir_windows.go delete mode 100644 vendor/github.com/minio/go-homedir/homedir.go delete mode 100644 vendor/github.com/minio/go-homedir/homedir_test.go create mode 100644 vendor/github.com/minio/minio-go/Makefile create mode 100644 vendor/github.com/minio/minio-go/NOTICE create mode 100644 vendor/github.com/minio/minio-go/README_zh_CN.md create mode 100644 vendor/github.com/minio/minio-go/api-get-object-context.go create mode 100644 vendor/github.com/minio/minio-go/api-get-options.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-context.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object-file-context.go create mode 100644 vendor/github.com/minio/minio-go/api-put-object_test.go create mode 100644 vendor/github.com/minio/minio-go/docs/checker.go.template create mode 100644 vendor/github.com/minio/minio-go/docs/validator.go create mode 100644 vendor/github.com/minio/minio-go/docs/zh_CN/API.md create mode 100644 vendor/github.com/minio/minio-go/docs/zh_CN/CONTRIBUTING.md create mode 100644 vendor/github.com/minio/minio-go/examples/s3/fgetobject-context.go create mode 100644 vendor/github.com/minio/minio-go/examples/s3/fputencrypted-object.go create mode 100644 vendor/github.com/minio/minio-go/examples/s3/fputobject-context.go create mode 100644 vendor/github.com/minio/minio-go/examples/s3/getobject-context.go create mode 100644 vendor/github.com/minio/minio-go/examples/s3/putobject-context.go create mode 100644 vendor/github.com/minio/minio-go/get-options_test.go create mode 100644 vendor/github.com/minio/minio-go/pkg/s3signer/request-signature-v4_test.go delete mode 100644 vendor/github.com/minio/minio-go/request-headers.go delete mode 100644 vendor/github.com/minio/minio-go/request-headers_test.go delete mode 100644 vendor/github.com/minio/minio-go/transport_1_5.go delete mode 100644 vendor/github.com/minio/minio-go/transport_1_6.go create mode 100644 vendor/github.com/mitchellh/go-homedir/LICENSE create mode 100644 vendor/github.com/mitchellh/go-homedir/README.md create mode 100644 vendor/github.com/mitchellh/go-homedir/homedir.go create mode 100644 vendor/github.com/mitchellh/go-homedir/homedir_test.go create mode 100644 vendor/github.com/olivere/elastic/.gitignore create mode 100644 vendor/github.com/olivere/elastic/.travis.yml create mode 100644 vendor/github.com/olivere/elastic/CHANGELOG-3.0.md create mode 100644 vendor/github.com/olivere/elastic/CHANGELOG-5.0.md create mode 100644 vendor/github.com/olivere/elastic/CHANGELOG-6.0.md create mode 100644 vendor/github.com/olivere/elastic/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/olivere/elastic/CONTRIBUTING.md create mode 100644 vendor/github.com/olivere/elastic/CONTRIBUTORS create mode 100644 vendor/github.com/olivere/elastic/ISSUE_TEMPLATE.md create mode 100644 vendor/github.com/olivere/elastic/LICENSE create mode 100644 vendor/github.com/olivere/elastic/README.md create mode 100644 vendor/github.com/olivere/elastic/acknowledged_response.go create mode 100644 vendor/github.com/olivere/elastic/backoff.go create mode 100644 vendor/github.com/olivere/elastic/backoff_test.go create mode 100644 vendor/github.com/olivere/elastic/bulk.go create mode 100644 vendor/github.com/olivere/elastic/bulk_delete_request.go create mode 100644 vendor/github.com/olivere/elastic/bulk_delete_request_easyjson.go create mode 100644 vendor/github.com/olivere/elastic/bulk_delete_request_test.go create mode 100644 vendor/github.com/olivere/elastic/bulk_index_request.go create mode 100644 vendor/github.com/olivere/elastic/bulk_index_request_easyjson.go create mode 100644 vendor/github.com/olivere/elastic/bulk_index_request_test.go create mode 100644 vendor/github.com/olivere/elastic/bulk_processor.go create mode 100644 vendor/github.com/olivere/elastic/bulk_processor_test.go create mode 100644 vendor/github.com/olivere/elastic/bulk_request.go create mode 100644 vendor/github.com/olivere/elastic/bulk_test.go create mode 100644 vendor/github.com/olivere/elastic/bulk_update_request.go create mode 100644 vendor/github.com/olivere/elastic/bulk_update_request_easyjson.go create mode 100644 vendor/github.com/olivere/elastic/bulk_update_request_test.go create mode 100644 vendor/github.com/olivere/elastic/canonicalize.go create mode 100644 vendor/github.com/olivere/elastic/canonicalize_test.go create mode 100644 vendor/github.com/olivere/elastic/clear_scroll.go create mode 100644 vendor/github.com/olivere/elastic/clear_scroll_test.go create mode 100644 vendor/github.com/olivere/elastic/client.go create mode 100644 vendor/github.com/olivere/elastic/client_test.go create mode 100644 vendor/github.com/olivere/elastic/cluster-test/Makefile create mode 100644 vendor/github.com/olivere/elastic/cluster-test/README.md create mode 100644 vendor/github.com/olivere/elastic/cluster-test/cluster-test.go create mode 100644 vendor/github.com/olivere/elastic/cluster_health.go create mode 100644 vendor/github.com/olivere/elastic/cluster_health_test.go create mode 100644 vendor/github.com/olivere/elastic/cluster_state.go create mode 100644 vendor/github.com/olivere/elastic/cluster_state_test.go create mode 100644 vendor/github.com/olivere/elastic/cluster_stats.go create mode 100644 vendor/github.com/olivere/elastic/cluster_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/config/config.go create mode 100644 vendor/github.com/olivere/elastic/config/config_test.go create mode 100644 vendor/github.com/olivere/elastic/config/doc.go create mode 100644 vendor/github.com/olivere/elastic/connection.go create mode 100644 vendor/github.com/olivere/elastic/count.go create mode 100644 vendor/github.com/olivere/elastic/count_test.go create mode 100644 vendor/github.com/olivere/elastic/decoder.go create mode 100644 vendor/github.com/olivere/elastic/decoder_test.go create mode 100644 vendor/github.com/olivere/elastic/delete.go create mode 100644 vendor/github.com/olivere/elastic/delete_by_query.go create mode 100644 vendor/github.com/olivere/elastic/delete_by_query_test.go create mode 100644 vendor/github.com/olivere/elastic/delete_test.go create mode 100644 vendor/github.com/olivere/elastic/doc.go create mode 100644 vendor/github.com/olivere/elastic/errors.go create mode 100644 vendor/github.com/olivere/elastic/errors_test.go create mode 100644 vendor/github.com/olivere/elastic/etc/elasticsearch.yml create mode 100644 vendor/github.com/olivere/elastic/etc/ingest-geoip/.gitkeep create mode 100644 vendor/github.com/olivere/elastic/etc/jvm.options create mode 100644 vendor/github.com/olivere/elastic/etc/log4j2.properties create mode 100644 vendor/github.com/olivere/elastic/etc/scripts/.gitkeep create mode 100644 vendor/github.com/olivere/elastic/example_test.go create mode 100644 vendor/github.com/olivere/elastic/exists.go create mode 100644 vendor/github.com/olivere/elastic/exists_test.go create mode 100644 vendor/github.com/olivere/elastic/explain.go create mode 100644 vendor/github.com/olivere/elastic/explain_test.go create mode 100644 vendor/github.com/olivere/elastic/fetch_source_context.go create mode 100644 vendor/github.com/olivere/elastic/fetch_source_context_test.go create mode 100644 vendor/github.com/olivere/elastic/field_caps.go create mode 100644 vendor/github.com/olivere/elastic/field_caps_test.go create mode 100644 vendor/github.com/olivere/elastic/geo_point.go create mode 100644 vendor/github.com/olivere/elastic/geo_point_test.go create mode 100644 vendor/github.com/olivere/elastic/get.go create mode 100644 vendor/github.com/olivere/elastic/get_test.go create mode 100644 vendor/github.com/olivere/elastic/highlight.go create mode 100644 vendor/github.com/olivere/elastic/highlight_test.go create mode 100644 vendor/github.com/olivere/elastic/index.go create mode 100644 vendor/github.com/olivere/elastic/index_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_analyze.go create mode 100644 vendor/github.com/olivere/elastic/indices_analyze_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_close.go create mode 100644 vendor/github.com/olivere/elastic/indices_close_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_create.go create mode 100644 vendor/github.com/olivere/elastic/indices_create_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_delete.go create mode 100644 vendor/github.com/olivere/elastic/indices_delete_template.go create mode 100644 vendor/github.com/olivere/elastic/indices_delete_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists_template.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists_template_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists_type.go create mode 100644 vendor/github.com/olivere/elastic/indices_exists_type_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_flush.go create mode 100644 vendor/github.com/olivere/elastic/indices_flush_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_forcemerge.go create mode 100644 vendor/github.com/olivere/elastic/indices_forcemerge_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_aliases.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_aliases_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_field_mapping.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_field_mapping_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_mapping.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_mapping_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_settings.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_settings_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_template.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_template_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_get_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_open.go create mode 100644 vendor/github.com/olivere/elastic/indices_open_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_alias.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_alias_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_mapping.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_mapping_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_settings.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_settings_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_put_template.go create mode 100644 vendor/github.com/olivere/elastic/indices_refresh.go create mode 100644 vendor/github.com/olivere/elastic/indices_refresh_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_rollover.go create mode 100644 vendor/github.com/olivere/elastic/indices_rollover_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_segments.go create mode 100644 vendor/github.com/olivere/elastic/indices_segments_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_shrink.go create mode 100644 vendor/github.com/olivere/elastic/indices_shrink_test.go create mode 100644 vendor/github.com/olivere/elastic/indices_stats.go create mode 100644 vendor/github.com/olivere/elastic/indices_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/ingest_delete_pipeline.go create mode 100644 vendor/github.com/olivere/elastic/ingest_delete_pipeline_test.go create mode 100644 vendor/github.com/olivere/elastic/ingest_get_pipeline.go create mode 100644 vendor/github.com/olivere/elastic/ingest_get_pipeline_test.go create mode 100644 vendor/github.com/olivere/elastic/ingest_put_pipeline.go create mode 100644 vendor/github.com/olivere/elastic/ingest_put_pipeline_test.go create mode 100644 vendor/github.com/olivere/elastic/ingest_simulate_pipeline.go create mode 100644 vendor/github.com/olivere/elastic/ingest_simulate_pipeline_test.go create mode 100644 vendor/github.com/olivere/elastic/inner_hit.go create mode 100644 vendor/github.com/olivere/elastic/inner_hit_test.go create mode 100644 vendor/github.com/olivere/elastic/logger.go create mode 100644 vendor/github.com/olivere/elastic/mget.go create mode 100644 vendor/github.com/olivere/elastic/mget_test.go create mode 100644 vendor/github.com/olivere/elastic/msearch.go create mode 100644 vendor/github.com/olivere/elastic/msearch_test.go create mode 100644 vendor/github.com/olivere/elastic/mtermvectors.go create mode 100644 vendor/github.com/olivere/elastic/mtermvectors_test.go create mode 100644 vendor/github.com/olivere/elastic/nodes_info.go create mode 100644 vendor/github.com/olivere/elastic/nodes_info_test.go create mode 100644 vendor/github.com/olivere/elastic/nodes_stats.go create mode 100644 vendor/github.com/olivere/elastic/nodes_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/percolate_test.go create mode 100644 vendor/github.com/olivere/elastic/ping.go create mode 100644 vendor/github.com/olivere/elastic/ping_test.go create mode 100644 vendor/github.com/olivere/elastic/plugins.go create mode 100644 vendor/github.com/olivere/elastic/plugins_test.go create mode 100644 vendor/github.com/olivere/elastic/query.go create mode 100644 vendor/github.com/olivere/elastic/recipes/bulk_insert/bulk_insert.go create mode 100644 vendor/github.com/olivere/elastic/recipes/connect/connect.go create mode 100644 vendor/github.com/olivere/elastic/recipes/sliced_scroll/sliced_scroll.go create mode 100644 vendor/github.com/olivere/elastic/reindex.go create mode 100644 vendor/github.com/olivere/elastic/reindex_test.go create mode 100644 vendor/github.com/olivere/elastic/request.go create mode 100644 vendor/github.com/olivere/elastic/request_test.go create mode 100644 vendor/github.com/olivere/elastic/rescore.go create mode 100644 vendor/github.com/olivere/elastic/rescorer.go create mode 100644 vendor/github.com/olivere/elastic/response.go create mode 100644 vendor/github.com/olivere/elastic/response_test.go create mode 100644 vendor/github.com/olivere/elastic/retrier.go create mode 100644 vendor/github.com/olivere/elastic/retrier_test.go create mode 100644 vendor/github.com/olivere/elastic/retry.go create mode 100644 vendor/github.com/olivere/elastic/retry_test.go create mode 100755 vendor/github.com/olivere/elastic/run-es.sh create mode 100644 vendor/github.com/olivere/elastic/script.go create mode 100644 vendor/github.com/olivere/elastic/script_test.go create mode 100644 vendor/github.com/olivere/elastic/scroll.go create mode 100644 vendor/github.com/olivere/elastic/scroll_test.go create mode 100644 vendor/github.com/olivere/elastic/search.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_children.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_children_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_count_thresholds.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_date_histogram.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_date_histogram_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_date_range.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_date_range_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_filter.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_filter_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_filters.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_filters_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_geo_distance.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_geo_distance_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_geohash_grid.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_geohash_grid_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_global.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_global_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_histogram.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_histogram_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_ip_range.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_ip_range_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_missing.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_missing_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_nested.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_nested_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_range.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_range_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_reverse_nested.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_reverse_nested_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_sampler.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_sampler_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_significant_terms.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_significant_terms_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_significant_text.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_significant_text_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_terms.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_bucket_terms_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_matrix_stats.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_matrix_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_avg.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_avg_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_cardinality.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_cardinality_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_extended_stats.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_extended_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_geo_bounds.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_geo_bounds_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_max.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_max_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_min.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_min_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_percentile_ranks.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_percentile_ranks_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_percentiles.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_percentiles_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_stats.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_stats_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_sum.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_sum_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_top_hits.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_top_hits_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_value_count.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_metrics_value_count_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_avg_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_avg_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_bucket_script.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_bucket_script_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_bucket_selector.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_bucket_selector_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_cumulative_sum.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_cumulative_sum_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_derivative.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_derivative_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_max_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_max_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_min_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_min_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_mov_avg.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_mov_avg_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_percentiles_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_percentiles_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_serial_diff.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_serial_diff_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_stats_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_stats_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_sum_bucket.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_sum_bucket_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_pipeline_test.go create mode 100644 vendor/github.com/olivere/elastic/search_aggs_test.go create mode 100644 vendor/github.com/olivere/elastic/search_collapse_builder.go create mode 100644 vendor/github.com/olivere/elastic/search_collapse_builder_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_bool.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_bool_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_boosting.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_boosting_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_common_terms.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_common_terms_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_constant_score.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_constant_score_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_dis_max.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_dis_max_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_exists.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_exists_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_fsq.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_fsq_score_funcs.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_fsq_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_fuzzy.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_fuzzy_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_bounding_box.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_bounding_box_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_distance.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_distance_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_polygon.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_geo_polygon_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_has_child.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_has_child_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_has_parent.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_has_parent_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_ids.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_ids_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_all.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_all_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_none.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_none_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_phrase.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_phrase_prefix.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_phrase_prefix_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_phrase_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_match_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_more_like_this.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_more_like_this_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_multi_match.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_multi_match_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_nested.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_nested_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_parent_id.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_parent_id_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_percolator.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_percolator_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_prefix.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_prefix_example_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_prefix_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_query_string.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_query_string_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_range.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_range_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_raw_string.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_raw_string_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_regexp.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_regexp_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_script.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_script_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_simple_query_string.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_simple_query_string_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_slice.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_slice_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_term.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_term_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_terms.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_terms_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_type.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_type_test.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_wildcard.go create mode 100644 vendor/github.com/olivere/elastic/search_queries_wildcard_test.go create mode 100644 vendor/github.com/olivere/elastic/search_request.go create mode 100644 vendor/github.com/olivere/elastic/search_request_test.go create mode 100644 vendor/github.com/olivere/elastic/search_source.go create mode 100644 vendor/github.com/olivere/elastic/search_source_test.go create mode 100644 vendor/github.com/olivere/elastic/search_suggester_test.go create mode 100644 vendor/github.com/olivere/elastic/search_terms_lookup.go create mode 100644 vendor/github.com/olivere/elastic/search_terms_lookup_test.go create mode 100644 vendor/github.com/olivere/elastic/search_test.go create mode 100644 vendor/github.com/olivere/elastic/setup_test.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_create.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_create_repository.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_create_repository_test.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_create_test.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_delete_repository.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_delete_repository_test.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_get_repository.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_get_repository_test.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_verify_repository.go create mode 100644 vendor/github.com/olivere/elastic/snapshot_verify_repository_test.go create mode 100644 vendor/github.com/olivere/elastic/sort.go create mode 100644 vendor/github.com/olivere/elastic/sort_test.go create mode 100644 vendor/github.com/olivere/elastic/suggest_field.go create mode 100644 vendor/github.com/olivere/elastic/suggest_field_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester.go create mode 100644 vendor/github.com/olivere/elastic/suggester_completion.go create mode 100644 vendor/github.com/olivere/elastic/suggester_completion_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context_category.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context_category_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context_geo.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context_geo_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester_context_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester_phrase.go create mode 100644 vendor/github.com/olivere/elastic/suggester_phrase_test.go create mode 100644 vendor/github.com/olivere/elastic/suggester_term.go create mode 100644 vendor/github.com/olivere/elastic/suggester_term_test.go create mode 100644 vendor/github.com/olivere/elastic/tasks_cancel.go create mode 100644 vendor/github.com/olivere/elastic/tasks_cancel_test.go create mode 100644 vendor/github.com/olivere/elastic/tasks_get_task.go create mode 100644 vendor/github.com/olivere/elastic/tasks_get_task_test.go create mode 100644 vendor/github.com/olivere/elastic/tasks_list.go create mode 100644 vendor/github.com/olivere/elastic/tasks_list_test.go create mode 100644 vendor/github.com/olivere/elastic/termvectors.go create mode 100644 vendor/github.com/olivere/elastic/termvectors_test.go create mode 100644 vendor/github.com/olivere/elastic/update.go create mode 100644 vendor/github.com/olivere/elastic/update_by_query.go create mode 100644 vendor/github.com/olivere/elastic/update_by_query_test.go create mode 100644 vendor/github.com/olivere/elastic/update_integration_test.go create mode 100644 vendor/github.com/olivere/elastic/update_test.go create mode 100644 vendor/github.com/olivere/elastic/uritemplates/LICENSE create mode 100644 vendor/github.com/olivere/elastic/uritemplates/uritemplates.go create mode 100644 vendor/github.com/olivere/elastic/uritemplates/utils.go create mode 100644 vendor/github.com/olivere/elastic/uritemplates/utils_test.go delete mode 100644 vendor/github.com/prometheus/client_golang/AUTHORS.md create mode 100644 vendor/github.com/prometheus/client_golang/MAINTAINERS.md create mode 100644 vendor/github.com/prometheus/client_golang/api/client.go create mode 100644 vendor/github.com/prometheus/client_golang/api/client_test.go delete mode 100644 vendor/github.com/prometheus/client_golang/api/prometheus/api.go delete mode 100644 vendor/github.com/prometheus/client_golang/api/prometheus/api_test.go create mode 100644 vendor/github.com/prometheus/client_golang/api/prometheus/v1/api.go create mode 100644 vendor/github.com/prometheus/client_golang/api/prometheus/v1/api_test.go create mode 100644 vendor/github.com/prometheus/client_golang/examples/random/Dockerfile create mode 100644 vendor/github.com/prometheus/client_golang/examples/simple/Dockerfile create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/desc_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_complex_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_gauge_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/example_timer_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/graphite/bridge_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/labels.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/observer.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/delegator_pre_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_client_1_8_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/promhttp/instrument_server_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/push/example_add_from_gatherer_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/timer.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/timer_test.go create mode 100644 vendor/github.com/prometheus/client_golang/prometheus/value_test.go delete mode 100644 vendor/github.com/prometheus/client_model/python/prometheus/client/__init__.py delete mode 100644 vendor/github.com/prometheus/client_model/python/prometheus/client/model/__init__.py delete mode 100644 vendor/github.com/prometheus/client_model/python/prometheus/client/model/metrics_pb2.py delete mode 100644 vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model.rb delete mode 100644 vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/metrics.pb.rb delete mode 100644 vendor/github.com/prometheus/client_model/ruby/lib/prometheus/client/model/version.rb delete mode 100644 vendor/github.com/prometheus/client_model/src/main/java/io/prometheus/client/Metrics.java create mode 100644 vendor/github.com/prometheus/procfs/fixtures/net/rpc/nfs create mode 100644 vendor/github.com/prometheus/procfs/fixtures/net/rpc/nfsd create mode 100644 vendor/github.com/prometheus/procfs/internal/util/parse.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/nfs.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfs.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfs_test.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfsd.go create mode 100644 vendor/github.com/prometheus/procfs/nfs/parse_nfsd_test.go create mode 100644 vendor/github.com/spf13/pflag/int16.go create mode 100644 vendor/github.com/stretchr/objx/.codeclimate.yml create mode 100644 vendor/github.com/stretchr/objx/.github/CODE_OF_CONDUCT.md create mode 100644 vendor/github.com/stretchr/objx/.travis.yml create mode 100644 vendor/github.com/stretchr/objx/Gopkg.lock create mode 100644 vendor/github.com/stretchr/objx/Gopkg.toml create mode 100644 vendor/github.com/stretchr/objx/LICENSE delete mode 100644 vendor/github.com/stretchr/objx/LICENSE.md create mode 100644 vendor/github.com/stretchr/objx/Taskfile.yml create mode 100644 vendor/github.com/stretchr/objx/codegen/template_test.txt delete mode 100644 vendor/github.com/stretchr/objx/map_for_test.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/LICENSE create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/bypass.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/common.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/config.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/doc.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/dump.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/format.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/davecgh/go-spew/spew/spew.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/pmezard/go-difflib/LICENSE create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/pmezard/go-difflib/difflib/difflib.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/LICENSE create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/assertion_format.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/assertion_forward.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/assertions.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/doc.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/errors.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/forward_assertions.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/assert/http_assertions.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/require/doc.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/require/forward_requirements.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/require/require.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/require/require_forward.go create mode 100644 vendor/github.com/stretchr/objx/vendor/github.com/stretchr/testify/require/requirements.go create mode 100755 vendor/github.com/stretchr/testify/.travis.gofmt.sh create mode 100755 vendor/github.com/stretchr/testify/.travis.gogenerate.sh create mode 100755 vendor/github.com/stretchr/testify/.travis.govet.sh delete mode 100644 vendor/github.com/stretchr/testify/Godeps/Godeps.json delete mode 100644 vendor/github.com/stretchr/testify/Godeps/Readme create mode 100644 vendor/github.com/stretchr/testify/Gopkg.lock create mode 100644 vendor/github.com/stretchr/testify/Gopkg.toml delete mode 100644 vendor/github.com/stretchr/testify/LICENCE.txt create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go create mode 100644 vendor/github.com/stretchr/testify/assert/assertion_format.go.tmpl create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/.gitignore create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/.travis.yml create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/README.md create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/cov_report.sh create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/common_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dump_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/dumpnocgo_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/example_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/format_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/internal_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/spew_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/spew/testdata/dumpcgo.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/davecgh/go-spew/test_coverage.txt create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/.travis.yml create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/README.md create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib/difflib_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/accessors_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/conversions_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/fixture_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/map_for_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/map_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/mutations_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/security_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/simple_example_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/tests_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/type_specific_codegen_test.go create mode 100644 vendor/github.com/stretchr/testify/vendor/github.com/stretchr/objx/value_test.go create mode 100644 vendor/golang.org/x/sys/plan9/asm_plan9_arm.s create mode 100644 vendor/golang.org/x/sys/plan9/zsyscall_plan9_arm.go create mode 100644 vendor/google.golang.org/appengine/.travis.yml create mode 100644 vendor/google.golang.org/appengine/CONTRIBUTING.md create mode 100644 vendor/google.golang.org/appengine/LICENSE create mode 100644 vendor/google.golang.org/appengine/README.md create mode 100644 vendor/google.golang.org/appengine/aetest/doc.go create mode 100644 vendor/google.golang.org/appengine/aetest/instance.go create mode 100644 vendor/google.golang.org/appengine/aetest/instance_classic.go create mode 100644 vendor/google.golang.org/appengine/aetest/instance_test.go create mode 100644 vendor/google.golang.org/appengine/aetest/instance_vm.go create mode 100644 vendor/google.golang.org/appengine/aetest/user.go create mode 100644 vendor/google.golang.org/appengine/appengine.go create mode 100644 vendor/google.golang.org/appengine/appengine_test.go create mode 100644 vendor/google.golang.org/appengine/appengine_vm.go create mode 100644 vendor/google.golang.org/appengine/blobstore/blobstore.go create mode 100644 vendor/google.golang.org/appengine/blobstore/blobstore_test.go create mode 100644 vendor/google.golang.org/appengine/blobstore/read.go create mode 100644 vendor/google.golang.org/appengine/capability/capability.go create mode 100644 vendor/google.golang.org/appengine/channel/channel.go create mode 100644 vendor/google.golang.org/appengine/channel/channel_test.go create mode 100644 vendor/google.golang.org/appengine/cloudsql/cloudsql.go create mode 100644 vendor/google.golang.org/appengine/cloudsql/cloudsql_classic.go create mode 100644 vendor/google.golang.org/appengine/cloudsql/cloudsql_vm.go create mode 100644 vendor/google.golang.org/appengine/cmd/aebundler/aebundler.go create mode 100644 vendor/google.golang.org/appengine/cmd/aedeploy/aedeploy.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/ae.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/ae_test.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/fix.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/main.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/main_test.go create mode 100644 vendor/google.golang.org/appengine/cmd/aefix/typecheck.go create mode 100644 vendor/google.golang.org/appengine/datastore/datastore.go create mode 100644 vendor/google.golang.org/appengine/datastore/datastore_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/doc.go create mode 100644 vendor/google.golang.org/appengine/datastore/key.go create mode 100644 vendor/google.golang.org/appengine/datastore/key_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/load.go create mode 100644 vendor/google.golang.org/appengine/datastore/load_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/metadata.go create mode 100644 vendor/google.golang.org/appengine/datastore/prop.go create mode 100644 vendor/google.golang.org/appengine/datastore/prop_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/query.go create mode 100644 vendor/google.golang.org/appengine/datastore/query_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/save.go create mode 100644 vendor/google.golang.org/appengine/datastore/time_test.go create mode 100644 vendor/google.golang.org/appengine/datastore/transaction.go create mode 100644 vendor/google.golang.org/appengine/delay/delay.go create mode 100644 vendor/google.golang.org/appengine/delay/delay_go17.go create mode 100644 vendor/google.golang.org/appengine/delay/delay_go17_test.go create mode 100644 vendor/google.golang.org/appengine/delay/delay_pre17.go create mode 100644 vendor/google.golang.org/appengine/delay/delay_test.go create mode 100644 vendor/google.golang.org/appengine/demos/guestbook/app.yaml create mode 100644 vendor/google.golang.org/appengine/demos/guestbook/favicon.ico create mode 100644 vendor/google.golang.org/appengine/demos/guestbook/guestbook.go create mode 100644 vendor/google.golang.org/appengine/demos/guestbook/index.yaml create mode 100644 vendor/google.golang.org/appengine/demos/guestbook/templates/guestbook.html create mode 100644 vendor/google.golang.org/appengine/demos/helloworld/app.yaml create mode 100644 vendor/google.golang.org/appengine/demos/helloworld/favicon.ico create mode 100644 vendor/google.golang.org/appengine/demos/helloworld/helloworld.go create mode 100644 vendor/google.golang.org/appengine/errors.go create mode 100644 vendor/google.golang.org/appengine/file/file.go create mode 100644 vendor/google.golang.org/appengine/identity.go create mode 100644 vendor/google.golang.org/appengine/image/image.go create mode 100644 vendor/google.golang.org/appengine/internal/aetesting/fake.go create mode 100644 vendor/google.golang.org/appengine/internal/api.go create mode 100644 vendor/google.golang.org/appengine/internal/api_classic.go create mode 100644 vendor/google.golang.org/appengine/internal/api_common.go create mode 100644 vendor/google.golang.org/appengine/internal/api_pre17.go create mode 100644 vendor/google.golang.org/appengine/internal/api_race_test.go create mode 100644 vendor/google.golang.org/appengine/internal/api_test.go create mode 100644 vendor/google.golang.org/appengine/internal/app_id.go create mode 100644 vendor/google.golang.org/appengine/internal/app_id_test.go create mode 100644 vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/base/api_base.proto create mode 100644 vendor/google.golang.org/appengine/internal/blobstore/blobstore_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/blobstore/blobstore_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/capability/capability_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/capability/capability_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/channel/channel_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/channel/channel_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go create mode 100755 vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto create mode 100644 vendor/google.golang.org/appengine/internal/identity.go create mode 100644 vendor/google.golang.org/appengine/internal/identity_classic.go create mode 100644 vendor/google.golang.org/appengine/internal/identity_vm.go create mode 100644 vendor/google.golang.org/appengine/internal/image/images_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/image/images_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/internal.go create mode 100644 vendor/google.golang.org/appengine/internal/internal_vm_test.go create mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/log/log_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/mail/mail_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/mail/mail_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/main.go create mode 100644 vendor/google.golang.org/appengine/internal/main_vm.go create mode 100644 vendor/google.golang.org/appengine/internal/memcache/memcache_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/memcache/memcache_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/metadata.go create mode 100644 vendor/google.golang.org/appengine/internal/modules/modules_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/modules/modules_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/net.go create mode 100644 vendor/google.golang.org/appengine/internal/net_test.go create mode 100755 vendor/google.golang.org/appengine/internal/regen.sh create mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/remote_api/remote_api.proto create mode 100644 vendor/google.golang.org/appengine/internal/search/search.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/search/search.proto create mode 100644 vendor/google.golang.org/appengine/internal/socket/socket_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/socket/socket_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/system/system_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/system/system_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/taskqueue/taskqueue_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/taskqueue/taskqueue_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/transaction.go create mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/urlfetch/urlfetch_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/user/user_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/user/user_service.proto create mode 100644 vendor/google.golang.org/appengine/internal/xmpp/xmpp_service.pb.go create mode 100644 vendor/google.golang.org/appengine/internal/xmpp/xmpp_service.proto create mode 100644 vendor/google.golang.org/appengine/log/api.go create mode 100644 vendor/google.golang.org/appengine/log/log.go create mode 100644 vendor/google.golang.org/appengine/log/log_test.go create mode 100644 vendor/google.golang.org/appengine/mail/mail.go create mode 100644 vendor/google.golang.org/appengine/mail/mail_test.go create mode 100644 vendor/google.golang.org/appengine/memcache/memcache.go create mode 100644 vendor/google.golang.org/appengine/memcache/memcache_test.go create mode 100644 vendor/google.golang.org/appengine/module/module.go create mode 100644 vendor/google.golang.org/appengine/module/module_test.go create mode 100644 vendor/google.golang.org/appengine/namespace.go create mode 100644 vendor/google.golang.org/appengine/namespace_test.go create mode 100644 vendor/google.golang.org/appengine/remote_api/client.go create mode 100644 vendor/google.golang.org/appengine/remote_api/client_test.go create mode 100644 vendor/google.golang.org/appengine/remote_api/remote_api.go create mode 100644 vendor/google.golang.org/appengine/runtime/runtime.go create mode 100644 vendor/google.golang.org/appengine/runtime/runtime_test.go create mode 100644 vendor/google.golang.org/appengine/search/doc.go create mode 100644 vendor/google.golang.org/appengine/search/field.go create mode 100644 vendor/google.golang.org/appengine/search/search.go create mode 100644 vendor/google.golang.org/appengine/search/search_test.go create mode 100644 vendor/google.golang.org/appengine/search/struct.go create mode 100644 vendor/google.golang.org/appengine/search/struct_test.go create mode 100644 vendor/google.golang.org/appengine/socket/doc.go create mode 100644 vendor/google.golang.org/appengine/socket/socket_classic.go create mode 100644 vendor/google.golang.org/appengine/socket/socket_vm.go create mode 100644 vendor/google.golang.org/appengine/taskqueue/taskqueue.go create mode 100644 vendor/google.golang.org/appengine/taskqueue/taskqueue_test.go create mode 100644 vendor/google.golang.org/appengine/timeout.go create mode 100644 vendor/google.golang.org/appengine/urlfetch/urlfetch.go create mode 100644 vendor/google.golang.org/appengine/user/oauth.go create mode 100644 vendor/google.golang.org/appengine/user/user.go create mode 100644 vendor/google.golang.org/appengine/user/user_classic.go create mode 100644 vendor/google.golang.org/appengine/user/user_test.go create mode 100644 vendor/google.golang.org/appengine/user/user_vm.go create mode 100644 vendor/google.golang.org/appengine/xmpp/xmpp.go create mode 100644 vendor/google.golang.org/appengine/xmpp/xmpp_test.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/CHANGELOG-6.0.md create mode 100644 vendor/gopkg.in/olivere/elastic.v5/bulk_delete_request_easyjson.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/bulk_index_request_easyjson.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/bulk_update_request_easyjson.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/delete_template.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/delete_template_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/docker-compose.yml create mode 100644 vendor/gopkg.in/olivere/elastic.v5/field_caps.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/field_caps_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/field_stats.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/field_stats_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/get_template.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/get_template_test.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/indices_segments.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/indices_segments_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/put_template.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/put_template_test.go delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.0.0.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.0.1.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.1.1.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.1.2.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.0.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.1.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.2.2.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.3.0.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.4.0.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.4.1.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.5.0.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.5.1.sh delete mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es-5.6.3.sh create mode 100755 vendor/gopkg.in/olivere/elastic.v5/run-es.sh create mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_aggs_bucket_count_thresholds.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_aggs_bucket_ip_range.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_aggs_bucket_ip_range_test.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_aggs_bucket_significant_text.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_aggs_bucket_significant_text_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_queries_indices.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/search_queries_indices_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/suggest.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/suggest_test.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/suggester_completion_fuzzy.go delete mode 100644 vendor/gopkg.in/olivere/elastic.v5/suggester_completion_fuzzy_test.go create mode 100644 vendor/gopkg.in/olivere/elastic.v5/update_integration_test.go (limited to 'vendor') diff --git a/vendor/github.com/NYTimes/gziphandler/gzip.go b/vendor/github.com/NYTimes/gziphandler/gzip.go index b3cb8315b..ae1ebe4bf 100644 --- a/vendor/github.com/NYTimes/gziphandler/gzip.go +++ b/vendor/github.com/NYTimes/gziphandler/gzip.go @@ -88,7 +88,7 @@ type GzipResponseWriterWithCloseNotify struct { *GzipResponseWriter } -func (w *GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool { +func (w GzipResponseWriterWithCloseNotify) CloseNotify() <-chan bool { return w.ResponseWriter.(http.CloseNotifier).CloseNotify() } diff --git a/vendor/github.com/NYTimes/gziphandler/gzip_test.go b/vendor/github.com/NYTimes/gziphandler/gzip_test.go index ec1543372..ba5048921 100644 --- a/vendor/github.com/NYTimes/gziphandler/gzip_test.go +++ b/vendor/github.com/NYTimes/gziphandler/gzip_test.go @@ -325,17 +325,32 @@ func TestFlushBeforeWrite(t *testing.T) { } func TestImplementCloseNotifier(t *testing.T) { + request := httptest.NewRequest(http.MethodGet, "/", nil) + request.Header.Set(acceptEncoding, "gzip") GzipHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request){ _, ok := rw.(http.CloseNotifier) assert.True(t, ok, "response writer must implement http.CloseNotifier") - })).ServeHTTP(&mockRWCloseNotify{}, &http.Request{}) + })).ServeHTTP(&mockRWCloseNotify{}, request) +} + +func TestImplementFlusherAndCloseNotifier(t *testing.T) { + request := httptest.NewRequest(http.MethodGet, "/", nil) + request.Header.Set(acceptEncoding, "gzip") + GzipHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request){ + _, okCloseNotifier := rw.(http.CloseNotifier) + assert.True(t, okCloseNotifier, "response writer must implement http.CloseNotifier") + _, okFlusher := rw.(http.Flusher) + assert.True(t, okFlusher, "response writer must implement http.Flusher") + })).ServeHTTP(&mockRWCloseNotify{}, request) } func TestNotImplementCloseNotifier(t *testing.T) { + request := httptest.NewRequest(http.MethodGet, "/", nil) + request.Header.Set(acceptEncoding, "gzip") GzipHandler(http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request){ _, ok := rw.(http.CloseNotifier) assert.False(t, ok, "response writer must not implement http.CloseNotifier") - })).ServeHTTP(httptest.NewRecorder(), &http.Request{}) + })).ServeHTTP(httptest.NewRecorder(), request) } diff --git a/vendor/github.com/avct/uasurfer/.gitignore b/vendor/github.com/avct/uasurfer/.gitignore deleted file mode 100644 index 35ba52a16..000000000 --- a/vendor/github.com/avct/uasurfer/.gitignore +++ /dev/null @@ -1,56 +0,0 @@ -# Compiled bin # -################### - - -# Compiled source # -################### -*.dll -*.exe -*.o -*.so - -# Packages # -############ -# it's better to unpack these files and commit the raw source -# git has its own built in compression methods -*.7z -*.dmg -*.gz -*.iso -*.jar -*.rar -*.tar -*.zip - -# Configuration Files # -####################### -*.cfg - -# Logs and databases # -###################### -*.log -*.sql -*.sqlite -logs -coverage.html -coverage.out - -# Test Files # -####################### -*.test - -# OS generated files # -###################### -.DS_Store -.DS_Store? -.Spotlight-V100 -.Trashes -ehthumbs.db -Thumbs.db - -# go.rice generated files -*.rice-box.go - -# Dev Tools # -###################### -.vagrant \ No newline at end of file diff --git a/vendor/github.com/avct/uasurfer/.travis.yml b/vendor/github.com/avct/uasurfer/.travis.yml deleted file mode 100644 index 77b64e6f2..000000000 --- a/vendor/github.com/avct/uasurfer/.travis.yml +++ /dev/null @@ -1,11 +0,0 @@ -sudo: false - -language: go - -go: - - 1.9.x - - 1.8.x - - 1.7.x - -script: - - go test diff --git a/vendor/github.com/avct/uasurfer/LICENSE b/vendor/github.com/avct/uasurfer/LICENSE deleted file mode 100644 index a092343b2..000000000 --- a/vendor/github.com/avct/uasurfer/LICENSE +++ /dev/null @@ -1,192 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - Copyright 2015 Avocet Systems Ltd. - http://avocet.io/opensource - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - Copyright 2015 Avocet Systems Ltd. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. \ No newline at end of file diff --git a/vendor/github.com/avct/uasurfer/README.md b/vendor/github.com/avct/uasurfer/README.md deleted file mode 100644 index 2a4ab608d..000000000 --- a/vendor/github.com/avct/uasurfer/README.md +++ /dev/null @@ -1,169 +0,0 @@ -[![Build Status](https://travis-ci.org/avct/uasurfer.svg?branch=master)](https://travis-ci.org/avct/uasurfer) [![GoDoc](https://godoc.org/github.com/avct/uasurfer?status.svg)](https://godoc.org/github.com/avct/uasurfer) [![Go Report Card](https://goreportcard.com/badge/github.com/avct/uasurfer)](https://goreportcard.com/report/github.com/avct/uasurfer) - -# uasurfer - -![uasurfer-100px](https://cloud.githubusercontent.com/assets/597902/16172506/9debc136-357a-11e6-90fb-c7c46f50dff0.png) - -**User Agent Surfer** (uasurfer) is a lightweight Golang package that parses and abstracts [HTTP User-Agent strings](https://en.wikipedia.org/wiki/User_agent) with particular attention to device type. - -The following information is returned by uasurfer from a raw HTTP User-Agent string: - -| Name | Example | Coverage in 192,792 parses | -|----------------|---------|--------------------------------| -| Browser name | `chrome` | 99.85% | -| Browser version | `53` | 99.17% | -| Platform | `ipad` | 99.97% | -| OS name | `ios` | 99.96% | -| OS version | `10` | 98.81% | -| Device type | `tablet` | 99.98% | - -Layout engine, browser language, and other esoteric attributes are not parsed. - -Coverage is estimated from a random sample of real UA strings collected across thousands of sources in US and EU mid-2016. - -## Usage - -### Parse(ua string) Function - -The `Parse()` function accepts a user agent `string` and returns UserAgent struct with named constants and integers for versions (minor, major and patch separately), and the full UA string that was parsed (lowercase). A string can be retrieved by adding `.String()` to a variable, such as `uasurfer.BrowserName.String()`. - -``` -// Define a user agent string -myUA := "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36" - -// Parse() returns all attributes, including returning the full UA string last -ua, uaString := uasurfer.Parse(myUA) -``` - -where example UserAgent is: -``` -{ - Browser { - BrowserName: BrowserChrome, - Version: { - Major: 45, - Minor: 0, - Patch: 2454, - }, - }, - OS { - Platform: PlatformMac, - Name: OSMacOSX, - Version: { - Major: 10, - Minor: 10, - Patch: 5, - }, - }, - DeviceType: DeviceComputer, -} -``` - -**Usage note:** There are some OSes that do not return a version, see docs below. Linux is typically not reported with a specific Linux distro name or version. - -#### Browser Name -* `BrowserChrome` - Google [Chrome](https://en.wikipedia.org/wiki/Google_Chrome), [Chromium](https://en.wikipedia.org/wiki/Chromium_(web_browser)) -* `BrowserSafari` - Apple [Safari](https://en.wikipedia.org/wiki/Safari_(web_browser)), Google Search ([GSA](https://itunes.apple.com/us/app/google/id284815942)) -* `BrowserIE` - Microsoft [Internet Explorer](https://en.wikipedia.org/wiki/Internet_Explorer), [Edge](https://en.wikipedia.org/wiki/Microsoft_Edge) -* `BrowserFirefox` - Mozilla [Firefox](https://en.wikipedia.org/wiki/Firefox), GNU [IceCat](https://en.wikipedia.org/wiki/GNU_IceCat), [Iceweasel](https://en.wikipedia.org/wiki/Mozilla_Corporation_software_rebranded_by_the_Debian_project#Iceweasel), [Seamonkey](https://en.wikipedia.org/wiki/SeaMonkey) -* `BrowserAndroid` - Android [WebView](https://developer.chrome.com/multidevice/webview/overview) (Android OS <4.4 only) -* `BrowserOpera` - [Opera](https://en.wikipedia.org/wiki/Opera_(web_browser)) -* `BrowserUCBrowser` - [UC Browser](https://en.wikipedia.org/wiki/UC_Browser) -* `BrowserSilk` - Amazon [Silk](https://en.wikipedia.org/wiki/Amazon_Silk) -* `BrowserSpotify` - [Spotify](https://en.wikipedia.org/wiki/Spotify#Clients) desktop client -* `BrowserBlackberry` - RIM [BlackBerry](https://en.wikipedia.org/wiki/BlackBerry) -* `BrowserUnknown` - Unknown - -#### Browser Version - -Browser version returns an `unint8` of the major version attribute of the User-Agent String. For example Chrome 45.0.23423 would return `45`. The intention is to support math operators with versions, such as "do XYZ for Chrome version >23". - -Unknown version is returned as `0`. - -#### Platform -* `PlatformWindows` - Microsoft Windows -* `PlatformMac` - Apple Macintosh -* `PlatformLinux` - Linux, including Android and other OSes -* `PlatformiPad` - Apple iPad -* `PlatformiPhone` - Apple iPhone -* `PlatformBlackberry` - RIM Blackberry -* `PlatformWindowsPhone` Microsoft Windows Phone & Mobile -* `PlatformKindle` - Amazon Kindle & Kindle Fire -* `PlatformPlaystation` - Sony Playstation, Vita, PSP -* `PlatformXbox` - Microsoft Xbox - `PlatformXbox` -* `PlatformNintendo` - Nintendo DS, Wii, etc. -* `PlatformUnknown` - Unknown - -#### OS Name -* `OSWindows` -* `OSMacOSX` - includes "macOS Sierra" -* `OSiOS` -* `OSAndroid` -* `OSChromeOS` -* `OSWebOS` -* `OSLinux` -* `OSPlaystation` -* `OSXbox` -* `OSNintendo` -* `OSUnknown` - -#### OS Version - -OS X major version is alway 10 with consecutive minor versions indicating release releases (10 - Yosemite, 11 - El Capitain, 12 Sierra, etc). Windows version is NT version. `Version{0, 0, 0}` indicated version is unknown or not evaluated. -Versions can be compared using `Less` function: `if ver1.Less(ver2) {}` - -Here are some examples across the platform, os.name, and os.version: - -* For Windows XP (Windows NT 5.1), "`PlatformWindows`" is the platform, "`OSWindows`" is the name, and `{5, 1, 0}` the version. -* For OS X 10.5.1, "`PlatformMac`" is the platform, "`OSMacOSX`" the name, and `{10, 5, 1}` the version. -* For Android 5.1, "`PlatformLinux`" is the platform, "`OSAndroid`" is the name, and `{5, 1, 0}` the version. -* For iOS 5.1, "`PlatformiPhone`" or "`PlatformiPad`" is the platform, "`OSiOS`" is the name, and `{5, 1, 0}` the version. - -###### Windows Version Guide - -* Windows 10 - `{10, 0, 0}` -* Windows 8.1 - `{6, 3, 0}` -* Windows 8 - `{6, 2, 0}` -* Windows 7 - `{6, 1, 0}` -* Windows Vista - `{6, 0, 0}` -* Windows XP - `{5, 1, 0}` or `{5, 2, 0}` -* Windows 2000 - `{5, 0, 0}` - -Windows 95, 98, and ME represent 0.01% of traffic worldwide and are not available through this package at this time. - -#### DeviceType -DeviceType is typically quite accurate, though determining between phones and tablets on Android is not always possible due to how some vendors design their UA strings. A mobile Android device without tablet indicator defaults to being classified as a phone. DeviceTV supports major brands such as Philips, Sharp, Vizio and steaming boxes such as Apple, Google, Roku, Amazon. - -* `DeviceComputer` -* `DevicePhone` -* `DeviceTablet` -* `DeviceTV` -* `DeviceConsole` -* `DeviceWearable` -* `DeviceUnknown` - -## Example Combinations of Attributes -* Surface RT -> `OSWindows8`, `DeviceTablet`, OSVersion >= `6` -* Android Tablet -> `OSAndroid`, `DeviceTablet` -* Microsoft Edge -> `BrowserIE`, BrowserVersion >= `12.0.0` - -## To do - -* Remove compiled regexp in favor of string.Contains wherever possible (lowers mem/alloc) -* Better version support on Firefox derivatives (e.g. SeaMonkey) -* Potential additional browser support: - * "NetFront" (1% share in India) - * "QQ Browser" (6.5% share in China) - * "Sogou Explorer" (5% share in China) - * "Maxthon" (1.5% share in China) - * "Nokia" -* Potential additional OS support: - * "Nokia" (5% share in India) - * "Series 40" (5.5% share in India) - * Windows 2003 Server -* iOS safari browser identification based on iOS version -* Add android version to browser identification -* old Macs - * "opera/9.64 (macintosh; ppc mac os x; u; en) presto/2.1.1" -* old Windows - * "mozilla/5.0 (windows nt 4.0; wow64) applewebkit/537.36 (khtml, like gecko) chrome/37.0.2049.0 safari/537.36" diff --git a/vendor/github.com/avct/uasurfer/browser.go b/vendor/github.com/avct/uasurfer/browser.go deleted file mode 100644 index e156818ab..000000000 --- a/vendor/github.com/avct/uasurfer/browser.go +++ /dev/null @@ -1,192 +0,0 @@ -package uasurfer - -import ( - "strings" -) - -// Browser struct contains the lowercase name of the browser, along -// with its browser version number. Browser are grouped together without -// consideration for device. For example, Chrome (Chrome/43.0) and Chrome for iOS -// (CriOS/43.0) would both return as "chrome" (name) and 43.0 (version). Similarly -// Internet Explorer 11 and Edge 12 would return as "ie" and "11" or "12", respectively. -// type Browser struct { -// Name BrowserName -// Version struct { -// Major int -// Minor int -// Patch int -// } -// } - -// Retrieve browser name from UA strings -func (u *UserAgent) evalBrowserName(ua string) bool { - // Blackberry goes first because it reads as MSIE & Safari - if strings.Contains(ua, "blackberry") || strings.Contains(ua, "playbook") || strings.Contains(ua, "bb10") || strings.Contains(ua, "rim ") { - u.Browser.Name = BrowserBlackberry - return u.isBot() - } - - if strings.Contains(ua, "applewebkit") { - switch { - case strings.Contains(ua, "opr/") || strings.Contains(ua, "opios/"): - u.Browser.Name = BrowserOpera - - case strings.Contains(ua, "silk/"): - u.Browser.Name = BrowserSilk - - case strings.Contains(ua, "edge/") || strings.Contains(ua, "iemobile/") || strings.Contains(ua, "msie "): - u.Browser.Name = BrowserIE - - case strings.Contains(ua, "ucbrowser/") || strings.Contains(ua, "ucweb/"): - u.Browser.Name = BrowserUCBrowser - - // Edge, Silk and other chrome-identifying browsers must evaluate before chrome, unless we want to add more overhead - case strings.Contains(ua, "chrome/") || strings.Contains(ua, "crios/") || strings.Contains(ua, "chromium/") || strings.Contains(ua, "crmo/"): - u.Browser.Name = BrowserChrome - - case strings.Contains(ua, "android") && !strings.Contains(ua, "chrome/") && strings.Contains(ua, "version/") && !strings.Contains(ua, "like android"): - // Android WebView on Android >= 4.4 is purposefully being identified as Chrome above -- https://developer.chrome.com/multidevice/webview/overview - u.Browser.Name = BrowserAndroid - - case strings.Contains(ua, "fxios"): - u.Browser.Name = BrowserFirefox - - case strings.Contains(ua, " spotify/"): - u.Browser.Name = BrowserSpotify - - // AppleBot uses webkit signature as well - case strings.Contains(ua, "applebot"): - u.Browser.Name = BrowserAppleBot - - // presume it's safari unless an esoteric browser is being specified (webOSBrowser, SamsungBrowser, etc.) - case strings.Contains(ua, "like gecko") && strings.Contains(ua, "mozilla/") && strings.Contains(ua, "safari/") && !strings.Contains(ua, "linux") && !strings.Contains(ua, "android") && !strings.Contains(ua, "browser/") && !strings.Contains(ua, "os/"): - u.Browser.Name = BrowserSafari - - // if we got this far and the device is iPhone or iPad, assume safari. Some agents don't actually contain the word "safari" - case strings.Contains(ua, "iphone") || strings.Contains(ua, "ipad"): - u.Browser.Name = BrowserSafari - - // Google's search app on iPhone, leverages native Safari rather than Chrome - case strings.Contains(ua, " gsa/"): - u.Browser.Name = BrowserSafari - - default: - goto notwebkit - - } - return u.isBot() - } - -notwebkit: - switch { - case strings.Contains(ua, "msie") || strings.Contains(ua, "trident"): - u.Browser.Name = BrowserIE - - case strings.Contains(ua, "gecko") && (strings.Contains(ua, "firefox") || strings.Contains(ua, "iceweasel") || strings.Contains(ua, "seamonkey") || strings.Contains(ua, "icecat")): - u.Browser.Name = BrowserFirefox - - case strings.Contains(ua, "presto") || strings.Contains(ua, "opera"): - u.Browser.Name = BrowserOpera - - case strings.Contains(ua, "ucbrowser"): - u.Browser.Name = BrowserUCBrowser - - case strings.Contains(ua, "applebot"): - u.Browser.Name = BrowserAppleBot - - case strings.Contains(ua, "baiduspider"): - u.Browser.Name = BrowserBaiduBot - - case strings.Contains(ua, "adidxbot") || strings.Contains(ua, "bingbot") || strings.Contains(ua, "bingpreview"): - u.Browser.Name = BrowserBingBot - - case strings.Contains(ua, "duckduckbot"): - u.Browser.Name = BrowserDuckDuckGoBot - - case strings.Contains(ua, "facebot") || strings.Contains(ua, "facebookexternalhit"): - u.Browser.Name = BrowserFacebookBot - - case strings.Contains(ua, "googlebot"): - u.Browser.Name = BrowserGoogleBot - - case strings.Contains(ua, "linkedinbot"): - u.Browser.Name = BrowserLinkedInBot - - case strings.Contains(ua, "msnbot"): - u.Browser.Name = BrowserMsnBot - - case strings.Contains(ua, "pingdom.com_bot"): - u.Browser.Name = BrowserPingdomBot - - case strings.Contains(ua, "twitterbot"): - u.Browser.Name = BrowserTwitterBot - - case strings.Contains(ua, "yandex") || strings.Contains(ua, "yadirectfetcher"): - u.Browser.Name = BrowserYandexBot - - case strings.Contains(ua, "yahoo"): - u.Browser.Name = BrowserYahooBot - - case strings.Contains(ua, "phantomjs"): - u.Browser.Name = BrowserBot - - default: - u.Browser.Name = BrowserUnknown - - } - - return u.isBot() -} - -// Retrieve browser version -// Methods used in order: -// 1st: look for generic version/# -// 2nd: look for browser-specific instructions (e.g. chrome/34) -// 3rd: infer from OS (iOS only) -func (u *UserAgent) evalBrowserVersion(ua string) { - // if there is a 'version/#' attribute with numeric version, use it -- except for Chrome since Android vendors sometimes hijack version/# - if u.Browser.Name != BrowserChrome && u.Browser.Version.findVersionNumber(ua, "version/") { - return - } - - switch u.Browser.Name { - case BrowserChrome: - // match both chrome and crios - _ = u.Browser.Version.findVersionNumber(ua, "chrome/") || u.Browser.Version.findVersionNumber(ua, "crios/") || u.Browser.Version.findVersionNumber(ua, "crmo/") - - case BrowserIE: - if u.Browser.Version.findVersionNumber(ua, "msie ") || u.Browser.Version.findVersionNumber(ua, "edge/") { - return - } - - // get MSIE version from trident version https://en.wikipedia.org/wiki/Trident_(layout_engine) - if u.Browser.Version.findVersionNumber(ua, "trident/") { - // convert trident versions 3-7 to MSIE version - if (u.Browser.Version.Major >= 3) && (u.Browser.Version.Major <= 7) { - u.Browser.Version.Major += 4 - } - } - - case BrowserFirefox: - _ = u.Browser.Version.findVersionNumber(ua, "firefox/") || u.Browser.Version.findVersionNumber(ua, "fxios/") - - case BrowserSafari: // executes typically if we're on iOS and not using a familiar browser - u.Browser.Version = u.OS.Version - // early Safari used a version number +1 to OS version - if (u.Browser.Version.Major <= 3) && (u.Browser.Version.Major >= 1) { - u.Browser.Version.Major++ - } - - case BrowserUCBrowser: - _ = u.Browser.Version.findVersionNumber(ua, "ucbrowser/") - - case BrowserOpera: - _ = u.Browser.Version.findVersionNumber(ua, "opr/") || u.Browser.Version.findVersionNumber(ua, "opios/") || u.Browser.Version.findVersionNumber(ua, "opera/") - - case BrowserSilk: - _ = u.Browser.Version.findVersionNumber(ua, "silk/") - - case BrowserSpotify: - _ = u.Browser.Version.findVersionNumber(ua, "spotify/") - } -} diff --git a/vendor/github.com/avct/uasurfer/const_string.go b/vendor/github.com/avct/uasurfer/const_string.go deleted file mode 100644 index 2fa21d86d..000000000 --- a/vendor/github.com/avct/uasurfer/const_string.go +++ /dev/null @@ -1,49 +0,0 @@ -// Code generated by "stringer -type=DeviceType,BrowserName,OSName,Platform -output=const_string.go"; DO NOT EDIT. - -package uasurfer - -import "fmt" - -const _DeviceType_name = "DeviceUnknownDeviceComputerDeviceTabletDevicePhoneDeviceConsoleDeviceWearableDeviceTV" - -var _DeviceType_index = [...]uint8{0, 13, 27, 39, 50, 63, 77, 85} - -func (i DeviceType) String() string { - if i < 0 || i >= DeviceType(len(_DeviceType_index)-1) { - return fmt.Sprintf("DeviceType(%d)", i) - } - return _DeviceType_name[_DeviceType_index[i]:_DeviceType_index[i+1]] -} - -const _BrowserName_name = "BrowserUnknownBrowserChromeBrowserIEBrowserSafariBrowserFirefoxBrowserAndroidBrowserOperaBrowserBlackberryBrowserUCBrowserBrowserSilkBrowserNokiaBrowserNetFrontBrowserQQBrowserMaxthonBrowserSogouExplorerBrowserSpotifyBrowserBotBrowserAppleBotBrowserBaiduBotBrowserBingBotBrowserDuckDuckGoBotBrowserFacebookBotBrowserGoogleBotBrowserLinkedInBotBrowserMsnBotBrowserPingdomBotBrowserTwitterBotBrowserYandexBotBrowserYahooBot" - -var _BrowserName_index = [...]uint16{0, 14, 27, 36, 49, 63, 77, 89, 106, 122, 133, 145, 160, 169, 183, 203, 217, 227, 242, 257, 271, 291, 309, 325, 343, 356, 373, 390, 406, 421} - -func (i BrowserName) String() string { - if i < 0 || i >= BrowserName(len(_BrowserName_index)-1) { - return fmt.Sprintf("BrowserName(%d)", i) - } - return _BrowserName_name[_BrowserName_index[i]:_BrowserName_index[i+1]] -} - -const _OSName_name = "OSUnknownOSWindowsPhoneOSWindowsOSMacOSXOSiOSOSAndroidOSBlackberryOSChromeOSOSKindleOSWebOSOSLinuxOSPlaystationOSXboxOSNintendoOSBot" - -var _OSName_index = [...]uint8{0, 9, 23, 32, 40, 45, 54, 66, 76, 84, 91, 98, 111, 117, 127, 132} - -func (i OSName) String() string { - if i < 0 || i >= OSName(len(_OSName_index)-1) { - return fmt.Sprintf("OSName(%d)", i) - } - return _OSName_name[_OSName_index[i]:_OSName_index[i+1]] -} - -const _Platform_name = "PlatformUnknownPlatformWindowsPlatformMacPlatformLinuxPlatformiPadPlatformiPhonePlatformiPodPlatformBlackberryPlatformWindowsPhonePlatformPlaystationPlatformXboxPlatformNintendoPlatformBot" - -var _Platform_index = [...]uint8{0, 15, 30, 41, 54, 66, 80, 92, 110, 130, 149, 161, 177, 188} - -func (i Platform) String() string { - if i < 0 || i >= Platform(len(_Platform_index)-1) { - return fmt.Sprintf("Platform(%d)", i) - } - return _Platform_name[_Platform_index[i]:_Platform_index[i+1]] -} diff --git a/vendor/github.com/avct/uasurfer/device.go b/vendor/github.com/avct/uasurfer/device.go deleted file mode 100644 index 70c00b112..000000000 --- a/vendor/github.com/avct/uasurfer/device.go +++ /dev/null @@ -1,60 +0,0 @@ -package uasurfer - -import ( - "strings" -) - -func (u *UserAgent) evalDevice(ua string) { - switch { - - case u.OS.Platform == PlatformWindows || u.OS.Platform == PlatformMac || u.OS.Name == OSChromeOS: - if strings.Contains(ua, "mobile") || strings.Contains(ua, "touch") { - u.DeviceType = DeviceTablet // windows rt, linux haxor tablets - return - } - u.DeviceType = DeviceComputer - - case u.OS.Platform == PlatformiPad || u.OS.Platform == PlatformiPod || strings.Contains(ua, "tablet") || strings.Contains(ua, "kindle/") || strings.Contains(ua, "playbook"): - u.DeviceType = DeviceTablet - - case u.OS.Platform == PlatformiPhone || u.OS.Platform == PlatformBlackberry || strings.Contains(ua, "phone"): - u.DeviceType = DevicePhone - - // long list of smarttv and tv dongle identifiers - case strings.Contains(ua, "tv") || strings.Contains(ua, "crkey") || strings.Contains(ua, "googletv") || strings.Contains(ua, "aftb") || strings.Contains(ua, "adt-") || strings.Contains(ua, "roku") || strings.Contains(ua, "viera") || strings.Contains(ua, "aquos") || strings.Contains(ua, "dtv") || strings.Contains(ua, "appletv") || strings.Contains(ua, "smarttv") || strings.Contains(ua, "tuner") || strings.Contains(ua, "smart-tv") || strings.Contains(ua, "hbbtv") || strings.Contains(ua, "netcast") || strings.Contains(ua, "vizio"): - u.DeviceType = DeviceTV - - case u.OS.Name == OSAndroid: - // android phones report as "mobile", android tablets should not but often do -- http://android-developers.blogspot.com/2010/12/android-browser-user-agent-issues.html - if strings.Contains(ua, "mobile") { - u.DeviceType = DevicePhone - return - } - - if strings.Contains(ua, "tablet") || strings.Contains(ua, "nexus 7") || strings.Contains(ua, "nexus 9") || strings.Contains(ua, "nexus 10") || strings.Contains(ua, "xoom") { - u.DeviceType = DeviceTablet - return - } - - u.DeviceType = DevicePhone // default to phone - - case u.OS.Platform == PlatformPlaystation || u.OS.Platform == PlatformXbox || u.OS.Platform == PlatformNintendo: - u.DeviceType = DeviceConsole - - case strings.Contains(ua, "glass") || strings.Contains(ua, "watch") || strings.Contains(ua, "sm-v"): - u.DeviceType = DeviceWearable - - // specifically above "mobile" string check as Kindle Fire tablets report as "mobile" - case u.Browser.Name == BrowserSilk || u.OS.Name == OSKindle && !strings.Contains(ua, "sd4930ur"): - u.DeviceType = DeviceTablet - - case strings.Contains(ua, "mobile") || strings.Contains(ua, "touch") || strings.Contains(ua, " mobi") || strings.Contains(ua, "webos"): //anything "mobile"/"touch" that didn't get captured as tablet, console or wearable is presumed a phone - u.DeviceType = DevicePhone - - case u.OS.Name == OSLinux: // linux goes last since it's in so many other device types (tvs, wearables, android-based stuff) - u.DeviceType = DeviceComputer - - default: - u.DeviceType = DeviceUnknown - } -} diff --git a/vendor/github.com/avct/uasurfer/system.go b/vendor/github.com/avct/uasurfer/system.go deleted file mode 100644 index 45a80409f..000000000 --- a/vendor/github.com/avct/uasurfer/system.go +++ /dev/null @@ -1,332 +0,0 @@ -package uasurfer - -import ( - "regexp" - "strconv" - "strings" -) - -var ( - amazonFireFingerprint = regexp.MustCompile("\\s(k[a-z]{3,5}|sd\\d{4}ur)\\s") //tablet or phone -) - -func (u *UserAgent) evalOS(ua string) bool { - - s := strings.IndexRune(ua, '(') - e := strings.IndexRune(ua, ')') - if s > e { - s = 0 - e = len(ua) - } - if e == -1 { - e = len(ua) - } - - agentPlatform := ua[s+1 : e] - specsEnd := strings.Index(agentPlatform, ";") - var specs string - if specsEnd != -1 { - specs = agentPlatform[:specsEnd] - } else { - specs = agentPlatform - } - - //strict OS & version identification - switch specs { - case "android": - u.evalLinux(ua, agentPlatform) - - case "bb10", "playbook": - u.OS.Platform = PlatformBlackberry - u.OS.Name = OSBlackberry - - case "x11", "linux": - u.evalLinux(ua, agentPlatform) - - case "ipad", "iphone", "ipod touch", "ipod": - u.evaliOS(specs, agentPlatform) - - case "macintosh": - u.evalMacintosh(ua) - - default: - switch { - // Blackberry - case strings.Contains(ua, "blackberry") || strings.Contains(ua, "playbook"): - u.OS.Platform = PlatformBlackberry - u.OS.Name = OSBlackberry - - // Windows Phone - case strings.Contains(agentPlatform, "windows phone "): - u.evalWindowsPhone(agentPlatform) - - // Windows, Xbox - case strings.Contains(ua, "windows "): - u.evalWindows(ua) - - // Kindle - case strings.Contains(ua, "kindle/") || amazonFireFingerprint.MatchString(agentPlatform): - u.OS.Platform = PlatformLinux - u.OS.Name = OSKindle - - // Linux (broader attempt) - case strings.Contains(ua, "linux"): - u.evalLinux(ua, agentPlatform) - - // WebOS (non-linux flagged) - case strings.Contains(ua, "webos") || strings.Contains(ua, "hpwos"): - u.OS.Platform = PlatformLinux - u.OS.Name = OSWebOS - - // Nintendo - case strings.Contains(ua, "nintendo"): - u.OS.Platform = PlatformNintendo - u.OS.Name = OSNintendo - - // Playstation - case strings.Contains(ua, "playstation") || strings.Contains(ua, "vita") || strings.Contains(ua, "psp"): - u.OS.Platform = PlatformPlaystation - u.OS.Name = OSPlaystation - - // Android - case strings.Contains(ua, "android"): - u.evalLinux(ua, agentPlatform) - - default: - u.OS.Platform = PlatformUnknown - u.OS.Name = OSUnknown - } - } - - return u.isBot() -} - -func (u *UserAgent) isBot() bool { - - if u.OS.Platform == PlatformBot || u.OS.Name == OSBot { - u.DeviceType = DeviceComputer - return true - } - - if u.Browser.Name >= BrowserBot && u.Browser.Name <= BrowserYahooBot { - u.OS.Platform = PlatformBot - u.OS.Name = OSBot - u.DeviceType = DeviceComputer - return true - } - - return false -} - -// evalLinux returns the `Platform`, `OSName` and Version of UAs with -// 'linux' listed as their platform. -func (u *UserAgent) evalLinux(ua string, agentPlatform string) { - - switch { - // Kindle Fire - case strings.Contains(ua, "kindle") || amazonFireFingerprint.MatchString(agentPlatform): - // get the version of Android if available, though we don't call this OSAndroid - u.OS.Platform = PlatformLinux - u.OS.Name = OSKindle - u.OS.Version.findVersionNumber(agentPlatform, "android ") - - // Android, Kindle Fire - case strings.Contains(ua, "android") || strings.Contains(ua, "googletv"): - // Android - u.OS.Platform = PlatformLinux - u.OS.Name = OSAndroid - u.OS.Version.findVersionNumber(agentPlatform, "android ") - - // ChromeOS - case strings.Contains(ua, "cros"): - u.OS.Platform = PlatformLinux - u.OS.Name = OSChromeOS - - // WebOS - case strings.Contains(ua, "webos") || strings.Contains(ua, "hpwos"): - u.OS.Platform = PlatformLinux - u.OS.Name = OSWebOS - - // Linux, "Linux-like" - case strings.Contains(ua, "x11") || strings.Contains(ua, "bsd") || strings.Contains(ua, "suse") || strings.Contains(ua, "debian") || strings.Contains(ua, "ubuntu"): - u.OS.Platform = PlatformLinux - u.OS.Name = OSLinux - - default: - u.OS.Platform = PlatformLinux - u.OS.Name = OSLinux - } -} - -// evaliOS returns the `Platform`, `OSName` and Version of UAs with -// 'ipad' or 'iphone' listed as their platform. -func (u *UserAgent) evaliOS(uaPlatform string, agentPlatform string) { - - switch uaPlatform { - // iPhone - case "iphone": - u.OS.Platform = PlatformiPhone - u.OS.Name = OSiOS - u.OS.getiOSVersion(agentPlatform) - - // iPad - case "ipad": - u.OS.Platform = PlatformiPad - u.OS.Name = OSiOS - u.OS.getiOSVersion(agentPlatform) - - // iPod - case "ipod touch", "ipod": - u.OS.Platform = PlatformiPod - u.OS.Name = OSiOS - u.OS.getiOSVersion(agentPlatform) - - default: - u.OS.Platform = PlatformiPad - u.OS.Name = OSUnknown - } -} - -func (u *UserAgent) evalWindowsPhone(agentPlatform string) { - u.OS.Platform = PlatformWindowsPhone - - if u.OS.Version.findVersionNumber(agentPlatform, "windows phone os ") || u.OS.Version.findVersionNumber(agentPlatform, "windows phone ") { - u.OS.Name = OSWindowsPhone - } else { - u.OS.Name = OSUnknown - } -} - -func (u *UserAgent) evalWindows(ua string) { - - switch { - //Xbox -- it reads just like Windows - case strings.Contains(ua, "xbox"): - u.OS.Platform = PlatformXbox - u.OS.Name = OSXbox - if !u.OS.Version.findVersionNumber(ua, "windows nt ") { - u.OS.Version.Major = 6 - u.OS.Version.Minor = 0 - u.OS.Version.Patch = 0 - } - - // No windows version - case !strings.Contains(ua, "windows "): - u.OS.Platform = PlatformWindows - u.OS.Name = OSUnknown - - case strings.Contains(ua, "windows nt ") && u.OS.Version.findVersionNumber(ua, "windows nt "): - u.OS.Platform = PlatformWindows - u.OS.Name = OSWindows - - case strings.Contains(ua, "windows xp"): - u.OS.Platform = PlatformWindows - u.OS.Name = OSWindows - u.OS.Version.Major = 5 - u.OS.Version.Minor = 1 - u.OS.Version.Patch = 0 - - default: - u.OS.Platform = PlatformWindows - u.OS.Name = OSUnknown - - } -} - -func (u *UserAgent) evalMacintosh(uaPlatformGroup string) { - u.OS.Platform = PlatformMac - if i := strings.Index(uaPlatformGroup, "os x 10"); i != -1 { - u.OS.Name = OSMacOSX - u.OS.Version.parse(uaPlatformGroup[i+5:]) - - return - } - u.OS.Name = OSUnknown -} - -func (v *Version) findVersionNumber(s string, m string) bool { - if ind := strings.Index(s, m); ind != -1 { - return v.parse(s[ind+len(m):]) - } - return false -} - -// getiOSVersion accepts the platform portion of a UA string and returns -// a Version. -func (o *OS) getiOSVersion(uaPlatformGroup string) { - if i := strings.Index(uaPlatformGroup, "cpu iphone os "); i != -1 { - o.Version.parse(uaPlatformGroup[i+14:]) - return - } - - if i := strings.Index(uaPlatformGroup, "cpu os "); i != -1 { - o.Version.parse(uaPlatformGroup[i+7:]) - return - } - - o.Version.parse(uaPlatformGroup) -} - -// strToInt simply accepts a string and returns a `int`, -// with '0' being default. -func strToInt(str string) int { - i, _ := strconv.Atoi(str) - return i -} - -// strToVer accepts a string and returns a Version, -// with {0, 0, 0} being default. -func (v *Version) parse(str string) bool { - if len(str) == 0 || str[0] < '0' || str[0] > '9' { - return false - } - for i := 0; i < 3; i++ { - empty := true - val := 0 - l := len(str) - 1 - - for k, c := range str { - if c >= '0' && c <= '9' { - if empty { - val = int(c) - 48 - empty = false - if k == l { - str = str[:0] - } - continue - } - - if val == 0 { - if c == '0' { - if k == l { - str = str[:0] - } - continue - } - str = str[k:] - break - } - - val = 10*val + int(c) - 48 - if k == l { - str = str[:0] - } - continue - } - str = str[k+1:] - break - } - - switch i { - case 0: - v.Major = val - - case 1: - v.Minor = val - - case 2: - v.Patch = val - } - } - return true -} diff --git a/vendor/github.com/avct/uasurfer/uasurfer.go b/vendor/github.com/avct/uasurfer/uasurfer.go deleted file mode 100644 index 15aac6d40..000000000 --- a/vendor/github.com/avct/uasurfer/uasurfer.go +++ /dev/null @@ -1,227 +0,0 @@ -// Package uasurfer provides fast and reliable abstraction -// of HTTP User-Agent strings. The philosophy is to identify -// technologies that holds >1% market share, and to avoid -// expending resources and accuracy on guessing at esoteric UA -// strings. -package uasurfer - -import "strings" - -//go:generate stringer -type=DeviceType,BrowserName,OSName,Platform -output=const_string.go - -// DeviceType (int) returns a constant. -type DeviceType int - -// A complete list of supported devices in the -// form of constants. -const ( - DeviceUnknown DeviceType = iota - DeviceComputer - DeviceTablet - DevicePhone - DeviceConsole - DeviceWearable - DeviceTV -) - -// BrowserName (int) returns a constant. -type BrowserName int - -// A complete list of supported web browsers in the -// form of constants. -const ( - BrowserUnknown BrowserName = iota - BrowserChrome - BrowserIE - BrowserSafari - BrowserFirefox - BrowserAndroid - BrowserOpera - BrowserBlackberry - BrowserUCBrowser - BrowserSilk - BrowserNokia - BrowserNetFront - BrowserQQ - BrowserMaxthon - BrowserSogouExplorer - BrowserSpotify - BrowserBot // Bot list begins here - BrowserAppleBot - BrowserBaiduBot - BrowserBingBot - BrowserDuckDuckGoBot - BrowserFacebookBot - BrowserGoogleBot - BrowserLinkedInBot - BrowserMsnBot - BrowserPingdomBot - BrowserTwitterBot - BrowserYandexBot - BrowserYahooBot // Bot list ends here -) - -// OSName (int) returns a constant. -type OSName int - -// A complete list of supported OSes in the -// form of constants. For handling particular versions -// of operating systems (e.g. Windows 2000), see -// the README.md file. -const ( - OSUnknown OSName = iota - OSWindowsPhone - OSWindows - OSMacOSX - OSiOS - OSAndroid - OSBlackberry - OSChromeOS - OSKindle - OSWebOS - OSLinux - OSPlaystation - OSXbox - OSNintendo - OSBot -) - -// Platform (int) returns a constant. -type Platform int - -// A complete list of supported platforms in the -// form of constants. Many OSes report their -// true platform, such as Android OS being Linux -// platform. -const ( - PlatformUnknown Platform = iota - PlatformWindows - PlatformMac - PlatformLinux - PlatformiPad - PlatformiPhone - PlatformiPod - PlatformBlackberry - PlatformWindowsPhone - PlatformPlaystation - PlatformXbox - PlatformNintendo - PlatformBot -) - -type Version struct { - Major int - Minor int - Patch int -} - -func (v Version) Less(c Version) bool { - if v.Major < c.Major { - return true - } - - if v.Major > c.Major { - return false - } - - if v.Minor < c.Minor { - return true - } - - if v.Minor > c.Minor { - return false - } - - return v.Patch < c.Patch -} - -type UserAgent struct { - Browser Browser - OS OS - DeviceType DeviceType -} - -type Browser struct { - Name BrowserName - Version Version -} - -type OS struct { - Platform Platform - Name OSName - Version Version -} - -// Reset resets the UserAgent to it's zero value -func (ua *UserAgent) Reset() { - ua.Browser = Browser{} - ua.OS = OS{} - ua.DeviceType = DeviceUnknown -} - -// Parse accepts a raw user agent (string) and returns the UserAgent. -func Parse(ua string) *UserAgent { - dest := new(UserAgent) - parse(ua, dest) - return dest -} - -// ParseUserAgent is the same as Parse, but populates the supplied UserAgent. -// It is the caller's responsibility to call Reset() on the UserAgent before -// passing it to this function. -func ParseUserAgent(ua string, dest *UserAgent) { - parse(ua, dest) -} - -func parse(ua string, dest *UserAgent) { - ua = normalise(ua) - switch { - case len(ua) == 0: - dest.OS.Platform = PlatformUnknown - dest.OS.Name = OSUnknown - dest.Browser.Name = BrowserUnknown - dest.DeviceType = DeviceUnknown - - // stop on on first case returning true - case dest.evalOS(ua): - case dest.evalBrowserName(ua): - default: - dest.evalBrowserVersion(ua) - dest.evalDevice(ua) - } -} - -// normalise normalises the user supplied agent string so that -// we can more easily parse it. -func normalise(ua string) string { - if len(ua) <= 1024 { - var buf [1024]byte - ascii := copyLower(buf[:len(ua)], ua) - if !ascii { - // Fall back for non ascii characters - return strings.ToLower(ua) - } - return string(buf[:len(ua)]) - } - // Fallback for unusually long strings - return strings.ToLower(ua) -} - -// copyLower copies a lowercase version of s to b. It assumes s contains only single byte characters -// and will panic if b is nil or is not long enough to contain all the bytes from s. -// It returns early with false if any characters were non ascii. -func copyLower(b []byte, s string) bool { - for j := 0; j < len(s); j++ { - c := s[j] - if c > 127 { - return false - } - - if 'A' <= c && c <= 'Z' { - c += 'a' - 'A' - } - - b[j] = c - } - return true -} diff --git a/vendor/github.com/avct/uasurfer/uasurfer_test.go b/vendor/github.com/avct/uasurfer/uasurfer_test.go deleted file mode 100644 index 8668a159f..000000000 --- a/vendor/github.com/avct/uasurfer/uasurfer_test.go +++ /dev/null @@ -1,1064 +0,0 @@ -package uasurfer - -import "testing" - -var testUAVars = []struct { - UA string - UserAgent -}{ - // Empty - {"", - UserAgent{}}, - - // Single char - {"a", - UserAgent{}}, - - // Some random string - {"some random string", - UserAgent{}}, - - // Potentially malformed ua - {")(", - UserAgent{}}, - - // iPhone - {"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/546.10 (KHTML, like Gecko) Version/6.0 Mobile/7E18WD Safari/8536.25", - UserAgent{ - Browser{BrowserSafari, Version{6, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{7, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4", - UserAgent{ - Browser{BrowserSafari, Version{8, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{8, 0, 2}}, DevicePhone}}, - - // iPad - {"Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10", - UserAgent{ - Browser{BrowserSafari, Version{4, 0, 4}}, OS{PlatformiPad, OSiOS, Version{3, 2, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPad; CPU OS 9_0 like Mac OS X) AppleWebKit/601.1.17 (KHTML, like Gecko) Version/8.0 Mobile/13A175 Safari/600.1.4", - UserAgent{ - Browser{BrowserSafari, Version{8, 0, 0}}, OS{PlatformiPad, OSiOS, Version{9, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 10_0 like Mac OS X) AppleWebKit/602.1.32 (KHTML, like Gecko) Version/10.0 Mobile/14A5261v Safari/602.1", - UserAgent{ - Browser{BrowserSafari, Version{10, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{10, 0, 0}}, DevicePhone}}, - - // Chrome - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{43, 0, 2357}}, OS{PlatformMac, OSMacOSX, Version{10, 10, 4}}, DeviceComputer}}, - - {"Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en) AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60 Mobile/9B206 Safari/534.48.3", - UserAgent{ - Browser{BrowserChrome, Version{19, 0, 1084}}, OS{PlatformiPhone, OSiOS, Version{5, 1, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; Android 6.0; Nexus 5X Build/MDB08L) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{46, 0, 2490}}, OS{PlatformLinux, OSAndroid, Version{6, 0, 0}}, DevicePhone}}, - - // Chromium (Chrome) - {"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/11.10 Chromium/18.0.1025.142 Chrome/18.0.1025.142 Safari/535.19", - UserAgent{ - Browser{BrowserChrome, Version{18, 0, 1025}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/45.0.2454.85 Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{45, 0, 2454}}, OS{PlatformMac, OSMacOSX, Version{10, 11, 0}}, DeviceComputer}}, - - //TODO: refactor "getVersion()" to handle this device/chrome version douchebaggery - // {"Mozilla/5.0 (Linux; Android 4.4.2; en-gb; SAMSUNG SM-G800F Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Version/1.6 Chrome/28.0.1500.94 Mobile Safari/537.36", - // UserAgent{ - // Browser{BrowserChrome, Version{28,0,1500}, OS{PlatformLinux, OSAndroid, Version{4,4,2}}, DevicePhone}}, - - // Safari - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12", - UserAgent{ - Browser{BrowserSafari, Version{8, 0, 7}}, OS{PlatformMac, OSMacOSX, Version{10, 10, 4}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12", - UserAgent{ - Browser{BrowserSafari, Version{3, 2, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 5, 5}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12) AppleWebKit/602.1.32 (KHTML, like Gecko) Version/10.0 Safari/602.1.32", // macOS Sierra dev beta - UserAgent{ - Browser{BrowserSafari, Version{10, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 12, 0}}, DeviceComputer}}, - - // Firefox - {"Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4", - UserAgent{ - Browser{BrowserFirefox, Version{1, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{8, 3, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Android 4.4; Tablet; rv:41.0) Gecko/41.0 Firefox/41.0", - UserAgent{ - Browser{BrowserFirefox, Version{41, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 4, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (Android; Mobile; rv:40.0) Gecko/40.0 Firefox/40.0", - UserAgent{ - Browser{BrowserFirefox, Version{40, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:38.0) Gecko/20100101 Firefox/38.0", - UserAgent{ - Browser{BrowserFirefox, Version{38, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - // Silk - {"Mozilla/5.0 (Linux; U; Android 4.4.3; de-de; KFTHWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.47 like Chrome/37.0.2026.117 Safari/537.36", - UserAgent{ - Browser{BrowserSilk, Version{3, 47, 0}}, OS{PlatformLinux, OSKindle, Version{4, 4, 3}}, DeviceTablet}}, - - {"Mozilla/5.0 (Linux; U; en-us; KFJWI Build/IMM76D) AppleWebKit/535.19 (KHTML like Gecko) Silk/2.4 Safari/535.19 Silk-Acceleratedtrue", - UserAgent{ - Browser{BrowserSilk, Version{2, 4, 0}}, OS{PlatformLinux, OSKindle, Version{0, 0, 0}}, DeviceTablet}}, - - // Opera - {"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.63 Safari/537.36 OPR/18.0.1284.68", - UserAgent{ - Browser{BrowserOpera, Version{18, 0, 1284}}, OS{PlatformWindows, OSWindows, Version{6, 1, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 8_4 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) OPiOS/10.2.0.93022 Mobile/12H143 Safari/9537.53", - UserAgent{ - Browser{BrowserOpera, Version{10, 2, 0}}, OS{PlatformiPhone, OSiOS, Version{8, 4, 0}}, DevicePhone}}, - - // Internet Explorer -- https://msdn.microsoft.com/en-us/library/hh869301(v=vs.85).aspx - {"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.123", - UserAgent{ - Browser{BrowserIE, Version{12, 123, 0}}, OS{PlatformWindows, OSWindows, Version{10, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)", - UserAgent{ - Browser{BrowserIE, Version{10, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 2, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C; rv:11.0) like Gecko", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 3, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows Phone 10.0; Android 4.2.1; DEVICE INFO) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Mobile Safari/537.36 Edge/12.123", - UserAgent{ - Browser{BrowserIE, Version{12, 123, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{10, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Mobile; Windows Phone 8.1; Android 4.0; ARM; Trident/7.0; Touch; rv:11.0; IEMobile/11.0; NOKIA; Lumia 520) like iPhone OS 7_0_3 Mac OS X AppleWebKit/537 (KHTML, like Gecko) Mobile Safari/537", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{8, 1, 0}}, DevicePhone}}, - - {"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.50727)", - UserAgent{ - Browser{BrowserIE, Version{5, 0, 1}}, OS{PlatformWindows, OSWindows, Version{5, 0, 0}}, DeviceComputer}}, - - {"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; GTB6.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; OfficeLiveConnector.1.3; OfficeLivePatch.0.0; .NET CLR 1.1.4322)", - UserAgent{ - Browser{BrowserIE, Version{7, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 1, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; ARM; Trident/6.0; Touch)", //Windows Surface RT tablet - UserAgent{ - Browser{BrowserIE, Version{10, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 2, 0}}, DeviceTablet}}, - - // UC Browser - {"Mozilla/5.0 (Linux; U; Android 2.3.4; en-US; MT11i Build/4.0.2.A.0.62) AppleWebKit/534.31 (KHTML, like Gecko) UCBrowser/9.0.1.275 U3/0.8.0 Mobile Safari/534.31", - UserAgent{ - Browser{BrowserUCBrowser, Version{9, 0, 1}}, OS{PlatformLinux, OSAndroid, Version{2, 3, 4}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.0.4; en-US; Micromax P255 Build/IMM76D) AppleWebKit/534.31 (KHTML, like Gecko) UCBrowser/9.2.0.308 U3/0.8.0 Mobile Safari/534.31", - UserAgent{ - Browser{BrowserUCBrowser, Version{9, 2, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 0, 4}}, DevicePhone}}, - - {"UCWEB/2.0 (Java; U; MIDP-2.0; en-US; MicromaxQ5) U2/1.0.0 UCBrowser/9.4.0.342 U2/1.0.0 Mobile", - UserAgent{ - Browser{BrowserUCBrowser, Version{9, 4, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DevicePhone}}, - - // Nokia Browser - // {"Mozilla/5.0 (Series40; Nokia501/14.0.4/java_runtime_version=Nokia_Asha_1_2; Profile/MIDP-2.1 Configuration/CLDC-1.1) Gecko/20100401 S40OviBrowser/4.0.0.0.45", - // UserAgent{ - // Browser{BrowserUnknown, Version{4,0,0}}, OS{PlatformUnknown, OSUnknown, Version{0,0,0}}, DevicePhone}}, - - // {"Mozilla/5.0 (Symbian/3; Series60/5.3 NokiaN8-00/111.040.1511; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/535.1 (KHTML, like Gecko) NokiaBrowser/8.3.1.4 Mobile Safari/535.1", - // UserAgent{ - // Browser{BrowserUnknown, Version{8,0,0}}, OS{PlatformUnknown, OSUnknown, Version{0,0,0}}, DevicePhone}}, - - // {"NokiaN97/21.1.107 (SymbianOS/9.4; Series60/5.0 Mozilla/5.0; Profile/MIDP-2.1 Configuration/CLDC-1.1) AppleWebkit/525 (KHTML, like Gecko) BrowserNG/7.1.4", - // BrowserUnknown, Version{7,0,0}}, OS{PlatformUnknown, OSUnknown, Version{0,0,0}}, DevicePhone}}, - - // ChromeOS - {"Mozilla/5.0 (X11; U; CrOS i686 9.10.0; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.253.0 Safari/532.5", - UserAgent{ - Browser{BrowserChrome, Version{4, 0, 253}}, OS{PlatformLinux, OSChromeOS, Version{0, 0, 0}}, DeviceComputer}}, - - // iPod, iPod Touch - {"mozilla/5.0 (ipod touch; cpu iphone os 9_3_3 like mac os x) applewebkit/601.1.46 (khtml, like gecko) version/9.0 mobile/13g34 safari/601.1", - UserAgent{ - Browser{BrowserSafari, Version{9, 0, 0}}, OS{PlatformiPod, OSiOS, Version{9, 3, 3}}, DeviceTablet}}, - - {"mozilla/5.0 (ipod; cpu iphone os 6_1_6 like mac os x) applewebkit/536.26 (khtml, like gecko) version/6.0 mobile/10b500 safari/8536.25", - UserAgent{ - Browser{BrowserSafari, Version{6, 0, 0}}, OS{PlatformiPod, OSiOS, Version{6, 1, 6}}, DeviceTablet}}, - - // WebOS - {"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; de-DE) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (webOS/1.4.1.1; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pre/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{1, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DevicePhone}}, - - // Android WebView (Android <= 4.3) - {"Mozilla/5.0 (Linux; U; Android 2.2; en-us; DROID2 GLOBAL Build/S273) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 2, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.0.3; de-ch; HTC Sensation Build/IML74K) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari53/4.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 0, 3}}, DevicePhone}}, - - // BlackBerry - {"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+", - UserAgent{ - Browser{BrowserBlackberry, Version{7, 2, 1}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (BB10; Kbd) AppleWebKit/537.35+ (KHTML, like Gecko) Version/10.2.1.1925 Mobile Safari/537.35+", - UserAgent{ - Browser{BrowserBlackberry, Version{10, 2, 1}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) BlackBerry8703e/4.1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/104", - UserAgent{ - Browser{BrowserBlackberry, Version{0, 0, 0}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DevicePhone}}, - - // Windows Phone - {"Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 625; ANZ941)", - UserAgent{ - Browser{BrowserIE, Version{10, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{8, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0; NOKIA; Lumia 900)", - UserAgent{ - Browser{BrowserIE, Version{9, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{7, 5, 0}}, DevicePhone}}, - - // Kindle eReader - {"Mozilla/5.0 (Linux; U; en-US) AppleWebKit/528.5+ (KHTML, like Gecko, Safari/528.5+) Version/4.0 Kindle/3.0 (screen 600×800; rotate)", - UserAgent{ - Browser{BrowserUnknown, Version{4, 0, 0}}, OS{PlatformLinux, OSKindle, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (X11; U; Linux armv7l like Android; en-us) AppleWebKit/531.2+ (KHTML, like Gecko) Version/5.0 Safari/533.2+ Kindle/3.0+", - UserAgent{ - Browser{BrowserUnknown, Version{5, 0, 0}}, OS{PlatformLinux, OSKindle, Version{0, 0, 0}}, DeviceTablet}}, - - // Amazon Fire - {"Mozilla/5.0 (Linux; U; Android 4.4.3; de-de; KFTHWI Build/KTU84M) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.67 like Chrome/39.0.2171.93 Safari/537.36", - UserAgent{ - Browser{BrowserSilk, Version{3, 67, 0}}, OS{PlatformLinux, OSKindle, Version{4, 4, 3}}, DeviceTablet}}, // Fire tablet - - {"Mozilla/5.0 (Linux; U; Android 4.2.2; en­us; KFTHWI Build/JDQ39) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.22 like Chrome/34.0.1847.137 Mobile Safari/537.36", - UserAgent{ - Browser{BrowserSilk, Version{3, 22, 0}}, OS{PlatformLinux, OSKindle, Version{4, 2, 2}}, DeviceTablet}}, // Fire tablet, but with "Mobile" - - {"Mozilla/5.0 (Linux; Android 4.4.4; SD4930UR Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/34.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/35.0.0.48.273;]", - UserAgent{ - Browser{BrowserChrome, Version{34, 0, 0}}, OS{PlatformLinux, OSKindle, Version{4, 4, 4}}, DevicePhone}}, // Facebook app on Fire Phone - - {"mozilla/5.0 (linux; android 4.4.3; kfthwi build/ktu84m) applewebkit/537.36 (khtml, like gecko) version/4.0 chrome/34.0.0.0 safari/537.36 [pinterest/android]", - UserAgent{ - Browser{BrowserChrome, Version{34, 0, 0}}, OS{PlatformLinux, OSKindle, Version{4, 4, 3}}, DeviceTablet}}, // Fire tablet running pinterest - - // extra logic to identify phone when using silk has not been added - // {"Mozilla/5.0 (Linux; Android 4.4.4; SD4930UR Build/KTU84P) AppleWebKit/537.36 (KHTML, like Gecko) Silk/3.67 like Chrome/39.0.2171.93 Mobile Safari/537.36", - // UserAgent{ - // Browser{BrowserSilk, Version{3,0,0}}, OS{PlatformLinux, OSKindle, Version{4,0,0}}, DevicePhone}}, // Silk on Fire Phone - - // Nintendo - {"Opera/9.30 (Nintendo Wii; U; ; 2047-7; fr)", - UserAgent{ - Browser{BrowserOpera, Version{9, 30, 0}}, OS{PlatformNintendo, OSNintendo, Version{0, 0, 0}}, DeviceConsole}}, - - {"Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/2.1.0.8.21 NintendoBrowser/1.0.0.7494.US", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformNintendo, OSNintendo, Version{0, 0, 0}}, DeviceConsole}}, - - // Xbox - {"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)", //Xbox 360 - UserAgent{ - Browser{BrowserIE, Version{9, 0, 0}}, OS{PlatformXbox, OSXbox, Version{6, 1, 0}}, DeviceConsole}}, - - // Playstation - {"Mozilla/5.0 (PlayStation 4 4.50) AppleWebKit/601.2 (KHTML, like Gecko)", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformPlaystation, OSPlaystation, Version{0, 0, 0}}, DeviceConsole}}, - - {"Mozilla/5.0 (Playstation Vita 1.61) AppleWebKit/531.22.8 (KHTML, like Gecko) Silk/3.2", - UserAgent{ - Browser{BrowserSilk, Version{3, 2, 0}}, OS{PlatformPlaystation, OSPlaystation, Version{0, 0, 0}}, DeviceConsole}}, - - // Smart TVs and TV dongles - {"Mozilla/5.0 (CrKey armv7l 1.4.15250) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/31.0.1650.0 Safari/537.36", // Chromecast - UserAgent{ - Browser{BrowserChrome, Version{31, 0, 1650}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DeviceTV}}, - - {"Mozilla/5.0 (Linux; GoogleTV 3.2; VAP430 Build/MASTER) AppleWebKit/534.24 (KHTML, like Gecko) Chrome/11.0.696.77 Safari/534.24", // Google TV - UserAgent{ - Browser{BrowserChrome, Version{11, 0, 696}}, OS{PlatformLinux, OSAndroid, Version{0, 0, 0}}, DeviceTV}}, - - {"Mozilla/5.0 (Linux; Android 5.0; ADT-1 Build/LPX13D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/40.0.2214.89 Mobile Safari/537.36", // Android TV - UserAgent{ - Browser{BrowserChrome, Version{40, 0, 2214}}, OS{PlatformLinux, OSAndroid, Version{5, 0, 0}}, DeviceTV}}, - - {"Mozilla/5.0 (Linux; Android 4.2.2; AFTB Build/JDQ39) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.173 Mobile Safari/537.22", // Amazon Fire - UserAgent{ - Browser{BrowserChrome, Version{25, 0, 1364}}, OS{PlatformLinux, OSAndroid, Version{4, 2, 2}}, DeviceTV}}, - - {"Mozilla/5.0 (Unknown; Linux armv7l) AppleWebKit/537.1+ (KHTML, like Gecko) Safari/537.1+ LG Browser/6.00.00(+mouse+3D+SCREEN+TUNER; LGE; GLOBAL-PLAT5; 03.07.01; 0x00000001;); LG NetCast.TV-2013/03.17.01 (LG, GLOBAL-PLAT4, wired)", // LG TV - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceTV}}, - - {"Mozilla/5.0 (X11; FreeBSD; U; Viera; de-DE) AppleWebKit/537.11 (KHTML, like Gecko) Viera/3.10.0 Chrome/23.0.1271.97 Safari/537.11", // Panasonic Viera - UserAgent{ - Browser{BrowserChrome, Version{23, 0, 1271}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceTV}}, - - // TODO: not catching "browser/" and reporting as safari -- ua string not being fully checked? - // {"Mozilla/5.0 (DTV) AppleWebKit/531.2+ (KHTML, like Gecko) Espial/6.1.5 AQUOSBrowser/2.0 (US01DTV;V;0001;0001)", // Sharp Aquos - // BrowserUnknown, Version{0,0,0}}, OS{PlatformUnknown, OSUnknown, Version{0,0,0}}, DeviceTV}}, - - {"Roku/DVP-5.2 (025.02E03197A)", // Roku - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DeviceTV}}, - - {"mozilla/5.0 (smart-tv; linux; tizen 2.3) applewebkit/538.1 (khtml, like gecko) samsungbrowser/1.0 tv safari/538.1", // Samsung SmartTV - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceTV}}, - - {"mozilla/5.0 (linux; u) applewebkit/537.36 (khtml, like gecko) version/4.0 mobile safari/537.36 smarttv/6.0 (netcast)", - UserAgent{ - Browser{BrowserUnknown, Version{4, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceTV}}, - - // Google search app (GSA) for iOS -- it's Safari in disguise as of v6 - {"Mozilla/5.0 (iPad; CPU OS 8_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) GSA/6.0.51363 Mobile/12F69 Safari/600.1.4", - UserAgent{ - Browser{BrowserSafari, Version{8, 3, 0}}, OS{PlatformiPad, OSiOS, Version{8, 3, 0}}, DeviceTablet}}, - - // Spotify (applicable for advertising applications) - {"Mozilla/5.0 (Windows NT 5.1) AppleWebKit/537.36 (KHTML, like Gecko) Spotify/1.0.9.133 Safari/537.36", - UserAgent{ - Browser{BrowserSpotify, Version{1, 0, 9}}, OS{PlatformWindows, OSWindows, Version{5, 1, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_2) AppleWebKit/537.36 (KHTML, like Gecko) Spotify/1.0.9.133 Safari/537.36", - UserAgent{ - Browser{BrowserSpotify, Version{1, 0, 9}}, OS{PlatformMac, OSMacOSX, Version{10, 10, 2}}, DeviceComputer}}, - - // Bots - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/600.2.5 (KHTML, like Gecko) Version/8.0.2 Safari/600.2.5 (Applebot/0.1; +http://www.apple.com/go/applebot)", - UserAgent{ - Browser{BrowserAppleBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{10, 10, 1}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; Baiduspider/2.0; +http://www.baidu.com/search/spider.html)", - UserAgent{ - Browser{BrowserBaiduBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)", - UserAgent{ - Browser{BrowserBingBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"DuckDuckBot/1.0; (+http://duckduckgo.com/duckduckbot.html)", - UserAgent{ - Browser{BrowserDuckDuckGoBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"facebookexternalhit/1.1 (+http://www.facebook.com/externalhit_uatext.php)", - UserAgent{ - Browser{BrowserFacebookBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Facebot/1.0", - UserAgent{ - Browser{BrowserFacebookBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", - UserAgent{ - Browser{BrowserGoogleBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"LinkedInBot/1.0 (compatible; Mozilla/5.0; Jakarta Commons-HttpClient/3.1 +http://www.linkedin.com)", - UserAgent{ - Browser{BrowserLinkedInBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"msnbot/2.0b (+http://search.msn.com/msnbot.htm)", - UserAgent{ - Browser{BrowserMsnBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Pingdom.com_bot_version_1.4_(http://www.pingdom.com/)", - UserAgent{ - Browser{BrowserPingdomBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Twitterbot/1.0", - UserAgent{ - Browser{BrowserTwitterBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; YandexBot/3.0; +http://yandex.com/bots)", - UserAgent{ - Browser{BrowserYandexBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; Yahoo! Slurp; http://help.yahoo.com/help/us/ysearch/slurp)", - UserAgent{ - Browser{BrowserYahooBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - // {"Mozilla/5.0 (iPhone; CPU iPhone OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5376e Safari/8536.25 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)", - // BrowserBot, Version{0,0,0}}, OS{PlatformBot, OSBot, Version{6,0,0}}, DeviceComputer}}, - - {"mozilla/5.0 (unknown; linux x86_64) applewebkit/538.1 (khtml, like gecko) phantomjs/2.1.1 safari/538.1", - UserAgent{ - Browser{BrowserBot, Version{0, 0, 0}}, OS{PlatformBot, OSBot, Version{0, 0, 0}}, DeviceComputer}}, - - // Unknown or partially handled - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.1b3pre) Gecko/20090223 SeaMonkey/2.0a3", //Seamonkey (~FF) - UserAgent{ - Browser{BrowserFirefox, Version{0, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 4, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.8pre) Gecko/2009022800 Camino/2.0b3pre", //Camino (~FF) - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 5, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Mobile; rv:26.0) Gecko/26.0 Firefox/26.0", //firefox OS - UserAgent{ - Browser{BrowserFirefox, Version{26, 0, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.45 Safari/535.19", //chrome for android having requested desktop site - UserAgent{ - Browser{BrowserChrome, Version{18, 0, 1025}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - {"Opera/9.80 (S60; SymbOS; Opera Mobi/352; U; de) Presto/2.4.15 Version/10.00", - UserAgent{ - Browser{BrowserOpera, Version{10, 0, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DevicePhone}}, - - // BrowserQQ - // {"Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; Touch; .NET4.0E; .NET4.0C; .NET CLR 3.5.30729; .NET CLR 2.0.50727; .NET CLR 3.0.30729; InfoPath.3; Tablet PC 2.0; QQBrowser/7.6.21433.400; rv:11.0) like Gecko", - // UserAgent{ - // Browser{BrowserQQ, Version{7,0,0}}, OS{PlatformWindows, OSWindows, Version{8,0,0}}, DeviceTablet}}, - - // {"Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.124 Safari/537.36 QQBrowser/9.0.2191.400", - // UserAgent{ - // Browser{BrowserQQ, Version{9,0,0}}, OS{PlatformWindows, OSWindows, Version{7,0,0}}, DeviceComputer}}, - - // ANDROID TESTS - - {"Mozilla/5.0 (Linux; U; Android 1.0; en-us; dream) AppleWebKit/525.10+ (KHTML,like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.0; en-us; generic) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.0.3; de-de; A80KSC Build/ECLAIR) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{1, 0, 3}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.5; en-gb; T-Mobile G1 Build/CRC1) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1", - UserAgent{ - Browser{BrowserAndroid, Version{3, 1, 2}}, OS{PlatformLinux, OSAndroid, Version{1, 5, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.5; es-; FBW1_4 Build/MASTER) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 5, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux U; Android 1.5 en-us hero) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 5, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.5; en-us; Opus One Build/RBE.00.00) AppleWebKit/528.18.1 (KHTML, like Gecko) Version/3.1.1 Mobile Safari/525.20.1", - UserAgent{ - Browser{BrowserAndroid, Version{3, 1, 1}}, OS{PlatformLinux, OSAndroid, Version{1, 5, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.6; ar-us; SonyEricssonX10i Build/R2BA026) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1", - UserAgent{ - Browser{BrowserAndroid, Version{3, 1, 2}}, OS{PlatformLinux, OSAndroid, Version{1, 6, 0}}, DevicePhone}}, - - // TODO: support names of Android OS? - //{"Mozilla/5.0 (Linux; U; Android Donut; de-de; HTC Tattoo 1.52.161.1 Build/Donut) AppleWebKit/528.5+ (KHTML, like Gecko) Version/3.1.2 Mobile Safari/525.20.1", - // UserAgent{ - // Browser{BrowserAndroid, Version{3, 1, 2}}, OS{PlatformLinux, OSAndroid, Version{1, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.6; en-gb; HTC Tattoo Build/DRC79) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 6, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 1.6; ja-jp; Docomo HT-03A Build/DRD08) AppleWebKit/525.10 (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{1, 6, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.1; en-us; Nexus One Build/ERD62) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 1, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.1-update1; en-au; HTC_Desire_A8183 V1.16.841.1 Build/ERE27) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 1, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.1; en-us; generic) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{2, 1, 0}}, DevicePhone}}, - - // TODO support named versions of Android? - {"Mozilla/5.0 (Linux; U; Android Eclair; en-us; sholes) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2", - UserAgent{ - Browser{BrowserAndroid, Version{3, 0, 4}}, OS{PlatformLinux, OSAndroid, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.2; en-sa; HTC_DesireHD_A9191 Build/FRF91) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 2, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.2.1; en-gb; HTC_DesireZ_A7272 Build/FRG83D) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 2, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.3.3; en-us; Sensation_4G Build/GRI40) AppleWebKit/533.1 (KHTML, like Gecko) Version/5.0 Safari/533.16", - UserAgent{ - Browser{BrowserAndroid, Version{5, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 3, 3}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.3.5; ko-kr; SHW-M250S Build/GINGERBREAD) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 3, 5}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 2.3.7; ja-jp; L-02D Build/GWK74) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{2, 3, 7}}, DevicePhone}}, - - // TODO: is tablet, not phone - {"Mozilla/5.0 (Linux; U; Android 3.0; xx-xx; Transformer TF101 Build/HRI66) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{3, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 3.0; en-us; Xoom Build/HRI39) AppleWebKit/534.13 (KHTML, like Gecko) Version/4.0 Safari/534.13", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{3, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (Linux; U; Android 4.0.1; en-us; sdk Build/ICS_MR0) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 0, 1}}, DevicePhone}}, - - // TODO support "android-" version prefix - // However, can't find reference to this naming scheme in real-world UA gathering - // {"Mozilla/5.0 (Linux; U; Android-4.0.3; en-us; Galaxy Nexus Build/IML74K) AppleWebKit/535.7 (KHTML, like Gecko) CrMo/16.0.912.75 Mobile Safari/535.7", - // UserAgent{ - // Browser{BrowserChrome, Version{16,0,0}}, OS{PlatformLinux, OSAndroid, Version{4,0,0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.1.1; en-us; Nexus S Build/JRO03E) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 1, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.1; en-gb; Build/JRN84D) AppleWebKit/534.30 (KHTML like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 1, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.1.1; el-gr; MB525 Build/JRO03H; CyanogenMod-10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 1, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.1.1; fr-fr; MB525 Build/JRO03H; CyanogenMod-10) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 1, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; U; Android 4.2; en-us; Nexus 10 Build/JVP15I) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 2, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (Linux; U; Android 4.2; ro-ro; LT18i Build/4.1.B.0.431) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30", - UserAgent{ - Browser{BrowserAndroid, Version{4, 0, 0}}, OS{PlatformLinux, OSAndroid, Version{4, 2, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; Android 4.3; Nexus 7 Build/JWR66D) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.111 Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{27, 0, 1453}}, OS{PlatformLinux, OSAndroid, Version{4, 3, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (Linux; Android 4.4; Nexus 7 Build/KOT24) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.105 Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{30, 0, 1599}}, OS{PlatformLinux, OSAndroid, Version{4, 4, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (Linux; Android 4.4; Nexus 4 Build/KRT16E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/30.0.1599.105 Mobile Safari", - UserAgent{ - Browser{BrowserChrome, Version{30, 0, 1599}}, OS{PlatformLinux, OSAndroid, Version{4, 4, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; Android 6.0.1; SM-G930V Build/MMB29M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{52, 0, 2743}}, OS{PlatformLinux, OSAndroid, Version{6, 0, 1}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; Android 7.0; Nexus 5X Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.98 Mobile Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{52, 0, 2743}}, OS{PlatformLinux, OSAndroid, Version{7, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Linux; Android 7.0; Nexus 6P Build/NRD90M; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/52.0.2743.98 Mobile Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{52, 0, 2743}}, OS{PlatformLinux, OSAndroid, Version{7, 0, 0}}, DevicePhone}}, - - // BLACKBERRY TESTS - - {"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0) BlackBerry8703e/4.1.0 Profile/MIDP-2.0 Configuration/CLDC-1.1 VendorID/104", - UserAgent{ - Browser{BrowserBlackberry, Version{0, 0, 0}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (BB10; Touch) AppleWebKit/537.10+ (KHTML, like Gecko) Version/10.1.0.4633 Mobile Safari/537.10+", - UserAgent{ - Browser{BrowserBlackberry, Version{10, 1, 0}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (BB10; Kbd) AppleWebKit/537.35+ (KHTML, like Gecko) Version/10.2.1.1925 Mobile Safari/537.35+", - UserAgent{ - Browser{BrowserBlackberry, Version{10, 2, 1}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 1.0.0; en-US) AppleWebKit/534.11 (KHTML, like Gecko) Version/7.1.0.7 Safari/534.11", - UserAgent{ - Browser{BrowserBlackberry, Version{7, 1, 0}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (PlayBook; U; RIM Tablet OS 2.1.0; en-US) AppleWebKit/536.2+ (KHTML, like Gecko) Version/7.2.1.0 Safari/536.2+", - UserAgent{ - Browser{BrowserBlackberry, Version{7, 2, 1}}, OS{PlatformBlackberry, OSBlackberry, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (X11; U; CrOS i686 9.10.0; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.253.0 Safari/532.5", - UserAgent{ - Browser{BrowserChrome, Version{4, 0, 253}}, OS{PlatformLinux, OSChromeOS, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (X11; CrOS armv7l 5500.100.6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.120 Safari/537.36", - UserAgent{ - Browser{BrowserChrome, Version{34, 0, 1847}}, OS{PlatformLinux, OSChromeOS, Version{0, 0, 0}}, DeviceComputer}}, - - // {"Mozilla/5.0 (Mobile; rv:14.0) Gecko/14.0 Firefox/14.0", - // UserAgent{ - // Browser{BrowserFirefox, 14, OSFirefoxOS, 14}, DevicePhone}}, - - // {"Mozilla/5.0 (Mobile; rv:17.0) Gecko/17.0 Firefox/17.0", - // UserAgent{ - // Browser{BrowserFirefox, , OSFirefoxOS}, DevicePhone}}, - - // {"Mozilla/5.0 (Mobile; rv:18.1) Gecko/18.1 Firefox/18.1", - // UserAgent{ - // Browser{BrowserFirefox, , OSFirefoxOS}, DevicePhone}}, - - // {"Mozilla/5.0 (Tablet; rv:18.1) Gecko/18.1 Firefox/18.1", - // UserAgent{ - // Browser{BrowserFirefox, , OSFirefoxOS}, DevicePhone}}, - - // {"Mozilla/5.0 (Mobile; LG-D300; rv:18.1) Gecko/18.1 Firefox/18.1", - // UserAgent{ - // Browser{BrowserFirefox, , OSFirefoxOS}, DevicePhone}}, - - {"Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10", - UserAgent{ - Browser{BrowserSafari, Version{4, 0, 4}}, OS{PlatformiPad, OSiOS, Version{3, 2, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7", - UserAgent{ - Browser{BrowserSafari, Version{4, 0, 5}}, OS{PlatformiPhone, OSiOS, Version{4, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3", - UserAgent{ - Browser{BrowserSafari, Version{5, 1, 0}}, OS{PlatformiPhone, OSiOS, Version{5, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3", - UserAgent{ - Browser{BrowserSafari, Version{5, 1, 0}}, OS{PlatformiPad, OSiOS, Version{5, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPad; CPU OS 6_0 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10A5355d Safari/8536.25", - UserAgent{ - Browser{BrowserSafari, Version{6, 0, 0}}, OS{PlatformiPad, OSiOS, Version{6, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 7_0 like Mac OS X) AppleWebKit/546.10 (KHTML, like Gecko) Version/6.0 Mobile/7E18WD Safari/8536.25", - UserAgent{ - Browser{BrowserSafari, Version{6, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{7, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (iPad; CPU OS 7_0 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A465 Safari/9537.53", - UserAgent{ - Browser{BrowserSafari, Version{7, 0, 0}}, OS{PlatformiPad, OSiOS, Version{7, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPad; CPU OS 7_0_2 like Mac OS X) AppleWebKit/537.51.1 (KHTML, like Gecko) Version/7.0 Mobile/11A501 Safari/9537.53", - UserAgent{ - Browser{BrowserSafari, Version{7, 0, 0}}, OS{PlatformiPad, OSiOS, Version{7, 0, 2}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 10_2_1 like Mac OS X) AppleWebKit/602.4.6 (KHTML, like Gecko) Mobile/14D27 [FBAN/FBIOS;FBAV/86.0.0.48.52;FBBV/53842252;FBDV/iPhone9,1;FBMD/iPhone;FBSN/iOS;FBSV/10.2.1;FBSS/2;FBCR/Verizon;FBID/phone;FBLC/en_US;FBOP/5;FBRV/0]", - UserAgent{ - Browser{BrowserSafari, Version{10, 2, 1}}, OS{PlatformiPhone, OSiOS, Version{10, 2, 1}}, DevicePhone}}, - - // TODO handle default browser based on iOS version - // {"Mozilla/5.0 (iPhone; CPU iPhone OS 8_0 like Mac OS X) AppleWebKit/538.34.9 (KHTML, like Gecko) Mobile/12A4265u", - // UserAgent{ - // Browser{BrowserSafari, Version{8,0,0}}, OS{PlatformiPhone, OSiOS, Version{8,0,0}}, DevicePhone}}, - - // TODO extrapolate browser from iOS version - // {"Mozilla/5.0 (iPad; CPU OS 8_0 like Mac OS X) AppleWebKit/538.34.9 (KHTML, like Gecko) Mobile/12A4265u", - // UserAgent{ - // Browser{BrowserSafari, Version{8,0,0}}, OS{PlatformiPad, OSiOS, Version{8,0,0}}, DeviceTablet}}, - - {"Mozilla/5.0 (iPhone; CPU iPhone OS 8_0_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12A405 Safari/600.1.4", - UserAgent{ - Browser{BrowserSafari, Version{8, 0, 0}}, OS{PlatformiPhone, OSiOS, Version{8, 0, 2}}, DevicePhone}}, - - {"Mozilla/5.0 (X11; U; Linux x86_64; en; rv:1.9.0.14) Gecko/20080528 Ubuntu/9.10 (karmic) Epiphany/2.22 Firefox/3.0", - UserAgent{ - Browser{BrowserFirefox, Version{3, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - // Can't parse browser due to limitation of user agent library - {"Mozilla/5.0 (X11; U; Linux x86_64; zh-TW; rv:1.9.0.8) Gecko/2009032712 Ubuntu/8.04 (hardy) Firefox/3.0.8 GTB5", - UserAgent{ - Browser{BrowserFirefox, Version{3, 0, 8}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; Konqueror/3.5; Linux; x86_64) KHTML/3.5.5 (like Gecko) (Debian)", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (X11; U; Linux i686; de; rv:1.9.1.5) Gecko/20091112 Iceweasel/3.5.5 (like Firefox/3.5.5; Debian-3.5.5-1)", - UserAgent{ - Browser{BrowserFirefox, Version{3, 5, 5}}, OS{PlatformLinux, OSLinux, Version{0, 0, 0}}, DeviceComputer}}, - - // TODO consider bot? - // {"Miro/2.0.4 (http://www.getmiro.com/; Darwin 10.3.0 i386)", - // UserAgent{ - // Browser{BrowserUnknown, Version{0,0,0}}, OS{PlatformMac, OSMacOSX, Version{3,0,0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.4; en-US; rv:1.9.1b3pre) Gecko/20090223 SeaMonkey/2.0a3", - UserAgent{ - Browser{BrowserFirefox, Version{0, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 4, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_5; en-us) AppleWebKit/525.26.2 (KHTML, like Gecko) Version/3.2 Safari/525.26.12", - UserAgent{ - Browser{BrowserSafari, Version{3, 2, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 5, 5}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en; rv:1.9.0.8pre) Gecko/2009022800 Camino/2.0b3pre", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 5, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_2; en-US) AppleWebKit/533.1 (KHTML, like Gecko) Chrome/5.0.329.0 Safari/533.1", - UserAgent{ - Browser{BrowserChrome, Version{5, 0, 329}}, OS{PlatformMac, OSMacOSX, Version{10, 6, 2}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.6; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6 (.NET CLR 3.5.30729)", - UserAgent{ - Browser{BrowserFirefox, Version{3, 5, 6}}, OS{PlatformMac, OSMacOSX, Version{10, 6, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/534.52.7 (KHTML, like Gecko) Version/5.1.2 Safari/534.52.7", - UserAgent{ - Browser{BrowserSafari, Version{5, 1, 2}}, OS{PlatformMac, OSMacOSX, Version{10, 7, 2}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:9.0) Gecko/20111222 Thunderbird/9.0.1", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 7, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_2) AppleWebKit/535.7 (KHTML, like Gecko) Chrome/16.0.912.75 Safari/535.7", - UserAgent{ - Browser{BrowserChrome, Version{16, 0, 912}}, OS{PlatformMac, OSMacOSX, Version{10, 7, 2}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8) AppleWebKit/535.18.5 (KHTML, like Gecko) Version/5.2 Safari/535.18.5", - UserAgent{ - Browser{BrowserSafari, Version{5, 2, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 8, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_8; en-US) AppleWebKit/532.5 (KHTML, like Gecko) Chrome/4.0.249.0 Safari/532.5", - UserAgent{ - Browser{BrowserChrome, Version{4, 0, 249}}, OS{PlatformMac, OSMacOSX, Version{10, 8, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9) AppleWebKit/537.35.1 (KHTML, like Gecko) Version/6.1 Safari/537.35.1", - UserAgent{ - Browser{BrowserSafari, Version{6, 1, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 9, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/538.34.48 (KHTML, like Gecko) Version/8.0 Safari/538.35.8", - UserAgent{ - Browser{BrowserSafari, Version{8, 0, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 10, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/538.32 (KHTML, like Gecko) Version/7.1 Safari/538.4", - UserAgent{ - Browser{BrowserSafari, Version{7, 1, 0}}, OS{PlatformMac, OSMacOSX, Version{10, 10, 0}}, DeviceComputer}}, - - {"Opera/9.80 (S60; SymbOS; Opera Mobi/352; U; de) Presto/2.4.15 Version/10.00", - UserAgent{ - Browser{BrowserOpera, Version{10, 0, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DevicePhone}}, - - {"Opera/9.80 (S60; SymbOS; Opera Mobi/352; U; de) Presto/2.4.15 Version/10.00", - UserAgent{ - Browser{BrowserOpera, Version{10, 0, 0}}, OS{PlatformUnknown, OSUnknown, Version{0, 0, 0}}, DevicePhone}}, - - // TODO: support OneBrowser? https://play.google.com/store/apps/details?id=com.tencent.ibibo.mtt&hl=en_GB - // {"OneBrowser/3.1 (NokiaN70-1/5.0638.3.0.1)", - // UserAgent{ - // Browser{BrowserUnknown, Version{0,0,0}}, OS{PlatformUnknown, OSUnknown, Version{0,0,0}}, DevicePhone}}, - - // WebOS reports itself as safari :( - {"Mozilla/5.0 (webOS/1.0; U; en-US) AppleWebKit/525.27.1 (KHTML, like Gecko) Version/1.0 Safari/525.27.1 Pre/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{1, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (webOS/1.4.1.1; U; en-US) AppleWebKit/532.2 (KHTML, like Gecko) Version/1.0 Safari/532.2 Pre/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{1, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.0; U; de-DE) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/233.70 Safari/534.6 TouchPad/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (hp-tablet; Linux; hpwOS/3.0.2; U; en-US) AppleWebKit/534.6 (KHTML, like Gecko) wOSBrowser/234.40.1 Safari/534.6 TouchPad/1.0", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformLinux, OSWebOS, Version{0, 0, 0}}, DeviceTablet}}, - - {"Opera/9.30 (Nintendo Wii; U; ; 2047-7; fr)", - UserAgent{ - Browser{BrowserOpera, Version{9, 30, 0}}, OS{PlatformNintendo, OSNintendo, Version{0, 0, 0}}, DeviceConsole}}, - - {"Mozilla/5.0 (Nintendo WiiU) AppleWebKit/534.52 (KHTML, like Gecko) NX/2.1.0.8.21 NintendoBrowser/1.0.0.7494.US", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformNintendo, OSNintendo, Version{0, 0, 0}}, DeviceConsole}}, - - {"Mozilla/5.0 (Nintendo WiiU) AppleWebKit/536.28 (KHTML, like Gecko) NX/3.0.3.12.6 NintendoBrowser/2.0.0.9362.US", - UserAgent{ - Browser{BrowserUnknown, Version{0, 0, 0}}, OS{PlatformNintendo, OSNintendo, Version{0, 0, 0}}, DeviceConsole}}, - - // TODO fails to get opera first -- but is this a real UA string or an uncommon spoof? - // {"Mozilla/4.0 (compatible; MSIE 5.0; Windows 2000) Opera 6.0 [en]", - // BrowserIE, Version{5,0,0}}, OS{PlatformWindows, OSWindows, Version{4,0,0}}, DeviceComputer}}, - - {"Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0; SV1; .NET CLR 1.1.4322; .NET CLR 1.0.3705; .NET CLR 2.0.50727)", - UserAgent{ - Browser{BrowserIE, Version{5, 0, 1}}, OS{PlatformWindows, OSWindows, Version{5, 0, 0}}, DeviceComputer}}, - - {"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/4.0; GTB6.4; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; OfficeLiveConnector.1.3; OfficeLivePatch.0.0; .NET CLR 1.1.4322)", - UserAgent{ - Browser{BrowserIE, Version{7, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 1, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows; U; Windows NT 6.1; sk; rv:1.9.1.7) Gecko/20091221 Firefox/3.5.7", - UserAgent{ - Browser{BrowserFirefox, Version{3, 5, 7}}, OS{PlatformWindows, OSWindows, Version{6, 1, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Trident/6.0)", - UserAgent{ - Browser{BrowserIE, Version{10, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 2, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/536.5 (KHTML, like Gecko) YaBrowser/1.0.1084.5402 Chrome/19.0.1084.5402 Safari/536.5", - UserAgent{ - Browser{BrowserChrome, Version{19, 0, 1084}}, OS{PlatformWindows, OSWindows, Version{6, 2, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.15 (KHTML, like Gecko) Chrome/24.0.1295.0 Safari/537.15", - UserAgent{ - Browser{BrowserChrome, Version{24, 0, 1295}}, OS{PlatformWindows, OSWindows, Version{6, 2, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; Touch; rv:11.0) like Gecko", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 3, 0}}, DeviceTablet}}, - - {"Mozilla/5.0 (IE 11.0; Windows NT 6.3; Trident/7.0; .NET4.0E; .NET4.0C; rv:11.0) like Gecko", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 3, 0}}, DeviceComputer}}, - - // {"Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)", - // UserAgent{ - // Browser{BrowserIE, Version{5,0,0}}, OS{PlatformWindows, OSWindows95, Version{5,0,0}}, DeviceComputer}}, - - // {"Mozilla/4.0 (compatible; MSIE 5.0; Windows 95) Opera 6.02 [en]", - // UserAgent{ - // Browser{BrowserIE, Version{5,0,0}}, OS{PlatformWindows, OSWindows95, Version{5,0,0}}, DeviceComputer}}, - - // {"Mozilla/4.0 (compatible; MSIE 6.0b; Windows 98; YComp 5.0.0.0)", - // UserAgent{ - // Browser{BrowserIE, Version{6,0,0}}, OS{PlatformWindows, OSWindows98, Version{5,0,0}}, DeviceComputer}}, - - // {"Mozilla/4.0 (compatible; MSIE 4.01; Windows 98)", - // UserAgent{ - // Browser{BrowserIE, Version{4,0,0}}, OS{PlatformWindows, OSWindows98, Version{5,0,0}}, DeviceComputer}}, - - // {"Mozilla/5.0 (Windows; U; Windows 98; en-US; rv:1.8.1.8pre) Gecko/20071019 Firefox/2.0.0.8 Navigator/9.0.0.1", - // UserAgent{ - // Browser{BrowserFirefox, Version{2,0,0}}, OS{PlatformWindows, OSWindows98, Version{5,0,0}}, DeviceComputer}}, - - //Can't parse due to limitation of user agent library - // {"Mozilla/5.0 (Windows; U; Windows CE 5.1; rv:1.8.1a3) Gecko/20060610 Minimo/0.016", - // UserAgent{ - // Browser{ BrowserUnknown, Version{0,0,0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{0,0,0}}, DevicePhone}}, - - // {"Mozilla/4.0 (compatible; MSIE 4.01; Windows CE; 176x220)", - // UserAgent{ - // Browser{BrowserIE, Version{4,0,0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{0,0,0}}, DevicePhone}}, - - // Can't parse browser due to limitation of user agent library - // {"Mozilla/4.0 (compatible; MSIE 5.0; Windows ME) Opera 6.0 [de]", - // UserAgent{ - // Browser{BrowserUnknown, OSWindowsME}, DeviceComputer}}, - - {"Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; InfoPath.2; .NET CLR 3.5.21022; .NET CLR 3.5.30729; MS-RTC LM 8; OfficeLiveConnector.1.4; OfficeLivePatch.1.3; .NET CLR 3.0.30729)", - UserAgent{ - Browser{BrowserIE, Version{8, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 0, 0}}, DeviceComputer}}, - - {"Mozilla/5.0 (Windows; U; Windows NT 5.1; cs; rv:1.9.1.8) Gecko/20100202 Firefox/3.5.8", - UserAgent{ - Browser{BrowserFirefox, Version{3, 5, 8}}, OS{PlatformWindows, OSWindows, Version{5, 1, 0}}, DeviceComputer}}, - - {"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; )", - UserAgent{ - Browser{BrowserIE, Version{7, 0, 0}}, OS{PlatformWindows, OSWindows, Version{5, 1, 0}}, DeviceComputer}}, - - // Can't parse due to limitation of user agent library - {"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; Windows Phone 6.5.3.5)", - UserAgent{ - Browser{BrowserIE, Version{6, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{6, 5, 3}}, DevicePhone}}, - - // desktop mode for Windows Phone 7 - {"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; XBLWP7; ZuneWP7)", - UserAgent{ - Browser{BrowserIE, Version{7, 0, 0}}, OS{PlatformWindows, OSWindows, Version{6, 1, 0}}, DeviceComputer}}, - - // mobile mode for Windows Phone 7 - {"Mozilla/4.0 (compatible; MSIE 7.0; Windows Phone OS 7.0; Trident/3.1; IEMobile/7.0; HTC; T8788)", - UserAgent{ - Browser{BrowserIE, Version{7, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{7, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (compatible; MSIE 9.0; Windows Phone OS 7.5; Trident/5.0; IEMobile/9.0)", - UserAgent{ - Browser{BrowserIE, Version{9, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{7, 5, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (compatible; MSIE 10.0; Windows Phone 8.0; Trident/6.0; IEMobile/10.0; ARM; Touch; NOKIA; Lumia 920)", - UserAgent{ - Browser{BrowserIE, Version{10, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{8, 0, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch IEMobile/11.0; HTC; Windows Phone 8S by HTC) like Gecko", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{8, 1, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (Windows Phone 8.1; ARM; Trident/7.0; Touch IEMobile/11.0; NOKIA; 909) like Gecko", - UserAgent{ - Browser{BrowserIE, Version{11, 0, 0}}, OS{PlatformWindowsPhone, OSWindowsPhone, Version{8, 1, 0}}, DevicePhone}}, - - {"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0; Xbox)", - UserAgent{ - Browser{BrowserIE, Version{9, 0, 0}}, OS{PlatformXbox, OSXbox, Version{6, 1, 0}}, DeviceConsole}}, -} - -func TestAgentSurfer(t *testing.T) { - for _, determined := range testUAVars { - t.Run("", func(t *testing.T) { - testFuncs := []func(string) *UserAgent{ - Parse, - func(ua string) *UserAgent { - u := new(UserAgent) - ParseUserAgent(ua, u) - return u - }, - } - - for _, f := range testFuncs { - ua := f(determined.UA) - - if ua.Browser.Name != determined.Browser.Name { - t.Errorf("browserName: got %v, wanted %v", ua.Browser.Name, determined.Browser.Name) - t.Logf("agent: %s", determined.UA) - } - - if ua.Browser.Version != determined.Browser.Version { - t.Errorf("browser version: got %d, wanted %d", ua.Browser.Version, determined.Browser.Version) - t.Logf("agent: %s", determined.UA) - } - - if ua.OS.Platform != determined.OS.Platform { - t.Errorf("platform: got %v, wanted %v", ua.OS.Platform, determined.OS.Platform) - t.Logf("agent: %s", determined.UA) - } - - if ua.OS.Name != determined.OS.Name { - t.Errorf("os: got %s, wanted %s", ua.OS.Name, determined.OS.Name) - t.Logf("agent: %s", determined.UA) - } - - if ua.OS.Version != determined.OS.Version { - t.Errorf("os version: got %d, wanted %d", ua.OS.Version, determined.OS.Version) - t.Logf("agent: %s", determined.UA) - } - - if ua.DeviceType != determined.DeviceType { - t.Errorf("device type: got %v, wanted %v", ua.DeviceType, determined.DeviceType) - t.Logf("agent: %s", determined.UA) - } - } - }) - } -} - -func BenchmarkAgentSurfer(b *testing.B) { - num := len(testUAVars) - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse(testUAVars[i%num].UA) - } -} - -func BenchmarkAgentSurferReuse(b *testing.B) { - dest := new(UserAgent) - num := len(testUAVars) - b.ResetTimer() - for i := 0; i < b.N; i++ { - dest.Reset() - ParseUserAgent(testUAVars[i%num].UA, dest) - } -} - -func BenchmarkEvalSystem(b *testing.B) { - num := len(testUAVars) - v := UserAgent{} - b.ResetTimer() - for i := 0; i < b.N; i++ { - v.evalOS(testUAVars[i%num].UA) - } -} - -func BenchmarkEvalBrowserName(b *testing.B) { - num := len(testUAVars) - v := UserAgent{} - b.ResetTimer() - for i := 0; i < b.N; i++ { - v.evalBrowserName(testUAVars[i%num].UA) - } -} - -func BenchmarkEvalBrowserVersion(b *testing.B) { - num := len(testUAVars) - v := UserAgent{} - b.ResetTimer() - for i := 0; i < b.N; i++ { - v.Browser.Name = testUAVars[i%num].Browser.Name - v.evalBrowserVersion(testUAVars[i%num].UA) - } -} - -func BenchmarkEvalDevice(b *testing.B) { - num := len(testUAVars) - v := UserAgent{} - - b.ResetTimer() - for i := 0; i < b.N; i++ { - v.OS.Name = testUAVars[i%num].OS.Name - v.OS.Platform = testUAVars[i%num].OS.Platform - v.Browser.Name = testUAVars[i%num].Browser.Name - v.evalDevice(testUAVars[i%num].UA) - } -} - -// Chrome for Mac -func BenchmarkParseChromeMac(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.130 Safari/537.36") - } -} - -// Chrome for Windows -func BenchmarkParseChromeWin(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.134 Safari/537.36") - } -} - -// Chrome for Android -func BenchmarkParseChromeAndroid(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse("Mozilla/5.0 (Linux; Android 4.4.2; GT-P5210 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/43.0.2357.93 Safari/537.36") - } -} - -// Safari for Mac -func BenchmarkParseSafariMac(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_4) AppleWebKit/600.7.12 (KHTML, like Gecko) Version/8.0.7 Safari/600.7.12") - } -} - -// Safari for iPad -func BenchmarkParseSafariiPad(b *testing.B) { - b.ResetTimer() - for i := 0; i < b.N; i++ { - Parse("Mozilla/5.0 (iPad; CPU OS 8_1_2 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B440 Safari/600.1.4") - } -} diff --git a/vendor/github.com/cpanato/html2text/.gitignore b/vendor/github.com/cpanato/html2text/.gitignore deleted file mode 100644 index daf913b1b..000000000 --- a/vendor/github.com/cpanato/html2text/.gitignore +++ /dev/null @@ -1,24 +0,0 @@ -# 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 diff --git a/vendor/github.com/cpanato/html2text/.travis.yml b/vendor/github.com/cpanato/html2text/.travis.yml deleted file mode 100644 index 6c7f48efd..000000000 --- a/vendor/github.com/cpanato/html2text/.travis.yml +++ /dev/null @@ -1,14 +0,0 @@ -language: go -go: - - tip - - 1.8 - - 1.7 - - 1.6 - - 1.5 - - 1.4 - - 1.3 - - 1.2 -notifications: - email: - on_success: change - on_failure: always diff --git a/vendor/github.com/cpanato/html2text/LICENSE b/vendor/github.com/cpanato/html2text/LICENSE deleted file mode 100644 index 1f2423ecb..000000000 --- a/vendor/github.com/cpanato/html2text/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -The MIT License (MIT) - -Copyright (c) 2015 Jay Taylor -Modified work: Copyright (c) 2017-present Mattermost, Inc. All Rights Reserved. - -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/github.com/cpanato/html2text/README.md b/vendor/github.com/cpanato/html2text/README.md deleted file mode 100644 index 57abf3ff3..000000000 --- a/vendor/github.com/cpanato/html2text/README.md +++ /dev/null @@ -1,108 +0,0 @@ -# html2text - -[![Documentation](https://godoc.org/github.com/cpanato/html2text?status.svg)](https://godoc.org/github.com/cpanato/html2text) -[![Build Status](https://travis-ci.org/cpanato/html2text.svg?branch=master)](https://travis-ci.org/cpanato/html2text) -[![Report Card](https://goreportcard.com/badge/github.com/jaytaylor/html2text)](https://goreportcard.com/report/github.com/cpanato/html2text) - -### Initial information - This project was forked from [github.com/jaytaylor/html2text](https://github.com/jaytaylor/html2text) in order to use another clean bom library due the original one has no license. - - -### Converts HTML into text - - -## Introduction - -Ensure your emails are readable by all! - -Turns HTML into raw text, useful for sending fancy HTML emails with a equivalently nicely formatted TXT document as a fallback (e.g. for people who don't allow HTML emails or have other display issues). - -html2text is a simple golang package for rendering HTML into plaintext. - -There are still lots of improvements to be had, but FWIW this has worked fine for my [basic] HTML-2-text needs. - -It requires go 1.x or newer ;) - - -## Download the package - -```bash -go get github.com/cpanato/html2text -``` - -## Example usage - -```go -package main - -import ( - "fmt" - - "github.com/cpanato/html2text" -) - -func main() { - inputHtml := ` - - - My Mega Service - - - - - - - -

Welcome to your new account on my service!

- -

- Here is some more information: - -

-

- - - ` - - text, err := html2text.FromString(inputHtml) - if err != nil { - panic(err) - } - fmt.Println(text) -} -``` - -Output: -``` -Mega Service ( http://mymegaservice.com/ ) - -****************************************** -Welcome to your new account on my service! -****************************************** - -Here is some more information: - -* Link 1: Example.com ( https://example.com ) -* Link 2: Example2.com ( https://example2.com ) -* Something else -``` - - -## Unit-tests - -Running the unit-tests is straightforward and standard: - -```bash -go test -``` - - -# License - -Permissive MIT license. diff --git a/vendor/github.com/cpanato/html2text/html2text.go b/vendor/github.com/cpanato/html2text/html2text.go deleted file mode 100644 index 61774e8a0..000000000 --- a/vendor/github.com/cpanato/html2text/html2text.go +++ /dev/null @@ -1,312 +0,0 @@ -package html2text - -import ( - "bytes" - "io" - "io/ioutil" - "regexp" - "strings" - "unicode" - - "github.com/dimchansky/utfbom" - - "golang.org/x/net/html" - "golang.org/x/net/html/atom" -) - -var ( - spacingRe = regexp.MustCompile(`[ \r\n\t]+`) - newlineRe = regexp.MustCompile(`\n\n+`) -) - -type textifyTraverseCtx struct { - Buf bytes.Buffer - - prefix string - blockquoteLevel int - lineLength int - endsWithSpace bool - endsWithNewline bool - justClosedDiv bool -} - -func (ctx *textifyTraverseCtx) traverse(node *html.Node) error { - switch node.Type { - default: - return ctx.traverseChildren(node) - - case html.TextNode: - data := strings.Trim(spacingRe.ReplaceAllString(node.Data, " "), " ") - return ctx.emit(data) - - case html.ElementNode: - return ctx.handleElementNode(node) - } -} - -func (ctx *textifyTraverseCtx) handleElementNode(node *html.Node) error { - ctx.justClosedDiv = false - switch node.DataAtom { - case atom.Br: - return ctx.emit("\n") - - case atom.H1, atom.H2, atom.H3: - subCtx := textifyTraverseCtx{} - if err := subCtx.traverseChildren(node); err != nil { - return err - } - - str := subCtx.Buf.String() - dividerLen := 0 - for _, line := range strings.Split(str, "\n") { - if lineLen := len([]rune(line)); lineLen-1 > dividerLen { - dividerLen = lineLen - 1 - } - } - divider := "" - if node.DataAtom == atom.H1 { - divider = strings.Repeat("*", dividerLen) - } else { - divider = strings.Repeat("-", dividerLen) - } - - if node.DataAtom == atom.H3 { - return ctx.emit("\n\n" + str + "\n" + divider + "\n\n") - } - return ctx.emit("\n\n" + divider + "\n" + str + "\n" + divider + "\n\n") - - case atom.Blockquote: - ctx.blockquoteLevel++ - ctx.prefix = strings.Repeat(">", ctx.blockquoteLevel) + " " - if err := ctx.emit("\n"); err != nil { - return err - } - if ctx.blockquoteLevel == 1 { - if err := ctx.emit("\n"); err != nil { - return err - } - } - if err := ctx.traverseChildren(node); err != nil { - return err - } - ctx.blockquoteLevel-- - ctx.prefix = strings.Repeat(">", ctx.blockquoteLevel) - if ctx.blockquoteLevel > 0 { - ctx.prefix += " " - } - return ctx.emit("\n\n") - - case atom.Div: - if ctx.lineLength > 0 { - if err := ctx.emit("\n"); err != nil { - return err - } - } - if err := ctx.traverseChildren(node); err != nil { - return err - } - var err error - if ctx.justClosedDiv == false { - err = ctx.emit("\n") - } - ctx.justClosedDiv = true - return err - - case atom.Li: - if err := ctx.emit("* "); err != nil { - return err - } - - if err := ctx.traverseChildren(node); err != nil { - return err - } - - return ctx.emit("\n") - - case atom.B, atom.Strong: - subCtx := textifyTraverseCtx{} - subCtx.endsWithSpace = true - if err := subCtx.traverseChildren(node); err != nil { - return err - } - str := subCtx.Buf.String() - return ctx.emit("*" + str + "*") - - case atom.A: - // If image is the only child, take its alt text as the link text - if img := node.FirstChild; img != nil && node.LastChild == img && img.DataAtom == atom.Img { - if altText := getAttrVal(img, "alt"); altText != "" { - ctx.emit(altText) - } - } else if err := ctx.traverseChildren(node); err != nil { - return err - } - - hrefLink := "" - if attrVal := getAttrVal(node, "href"); attrVal != "" { - attrVal = ctx.normalizeHrefLink(attrVal) - if attrVal != "" { - hrefLink = "( " + attrVal + " )" - } - } - - return ctx.emit(hrefLink) - - case atom.P, atom.Ul, atom.Table: - if err := ctx.emit("\n\n"); err != nil { - return err - } - - if err := ctx.traverseChildren(node); err != nil { - return err - } - - return ctx.emit("\n\n") - - case atom.Tr: - if err := ctx.traverseChildren(node); err != nil { - return err - } - - return ctx.emit("\n") - - case atom.Style, atom.Script, atom.Head: - // Ignore the subtree - return nil - - default: - return ctx.traverseChildren(node) - } -} -func (ctx *textifyTraverseCtx) traverseChildren(node *html.Node) error { - for c := node.FirstChild; c != nil; c = c.NextSibling { - if err := ctx.traverse(c); err != nil { - return err - } - } - - return nil -} - -func (ctx *textifyTraverseCtx) emit(data string) error { - if len(data) == 0 { - return nil - } - lines := ctx.breakLongLines(data) - var err error - for _, line := range lines { - runes := []rune(line) - startsWithSpace := unicode.IsSpace(runes[0]) - if !startsWithSpace && !ctx.endsWithSpace { - ctx.Buf.WriteByte(' ') - ctx.lineLength++ - } - ctx.endsWithSpace = unicode.IsSpace(runes[len(runes)-1]) - for _, c := range line { - _, err = ctx.Buf.WriteString(string(c)) - if err != nil { - return err - } - ctx.lineLength++ - if c == '\n' { - ctx.lineLength = 0 - if ctx.prefix != "" { - _, err = ctx.Buf.WriteString(ctx.prefix) - if err != nil { - return err - } - } - } - } - } - return nil -} - -func (ctx *textifyTraverseCtx) breakLongLines(data string) []string { - // only break lines when we are in blockquotes - if ctx.blockquoteLevel == 0 { - return []string{data} - } - var ret []string - runes := []rune(data) - l := len(runes) - existing := ctx.lineLength - if existing >= 74 { - ret = append(ret, "\n") - existing = 0 - } - for l+existing > 74 { - i := 74 - existing - for i >= 0 && !unicode.IsSpace(runes[i]) { - i-- - } - if i == -1 { - // no spaces, so go the other way - i = 74 - existing - for i < l && !unicode.IsSpace(runes[i]) { - i++ - } - } - ret = append(ret, string(runes[:i])+"\n") - for i < l && unicode.IsSpace(runes[i]) { - i++ - } - runes = runes[i:] - l = len(runes) - existing = 0 - } - if len(runes) > 0 { - ret = append(ret, string(runes)) - } - return ret -} - -func (ctx *textifyTraverseCtx) normalizeHrefLink(link string) string { - link = strings.TrimSpace(link) - link = strings.TrimPrefix(link, "mailto:") - return link -} - -func getAttrVal(node *html.Node, attrName string) string { - for _, attr := range node.Attr { - if attr.Key == attrName { - return attr.Val - } - } - - return "" -} - -func FromHtmlNode(doc *html.Node) (string, error) { - ctx := textifyTraverseCtx{ - Buf: bytes.Buffer{}, - } - if err := ctx.traverse(doc); err != nil { - return "", err - } - - text := strings.TrimSpace(newlineRe.ReplaceAllString( - strings.Replace(ctx.Buf.String(), "\n ", "\n", -1), "\n\n")) - return text, nil - -} - -func FromReader(reader io.Reader) (string, error) { - bs, err := ioutil.ReadAll(reader) - newReader, _ := utfbom.Skip(bytes.NewReader(bs)) - - doc, err := html.Parse(newReader) - if err != nil { - return "", err - } - return FromHtmlNode(doc) -} - -func FromString(input string) (string, error) { - bs := utfbom.SkipOnly(bytes.NewReader([]byte(input))) - text, err := FromReader(bs) - if err != nil { - return "", err - } - return text, nil -} diff --git a/vendor/github.com/cpanato/html2text/html2text_test.go b/vendor/github.com/cpanato/html2text/html2text_test.go deleted file mode 100644 index b30d68ac9..000000000 --- a/vendor/github.com/cpanato/html2text/html2text_test.go +++ /dev/null @@ -1,674 +0,0 @@ -package html2text - -import ( - "bytes" - "fmt" - "io/ioutil" - "path" - "regexp" - "strings" - "testing" -) - -const ( - destPath = "testdata" -) - -func TestParseUTF8(t *testing.T) { - htmlFiles := []struct { - file string - keywordShouldNotExist string - keywordShouldExist string - }{ - { - "utf8.html", - "学习之道:美国公认学习第一书title", - "次世界冠军赛上,我几近疯狂", - }, - { - "utf8_with_bom.xhtml", - "1892年波兰文版序言title", - "种新的波兰文本已成为必要", - }, - } - - for _, htmlFile := range htmlFiles { - bs, err := ioutil.ReadFile(path.Join(destPath, htmlFile.file)) - if err != nil { - t.Fatal(err) - } - text, err := FromReader(bytes.NewReader(bs)) - if err != nil { - t.Fatal(err) - } - if !strings.Contains(text, htmlFile.keywordShouldExist) { - t.Fatalf("keyword %s should exists in file %s", htmlFile.keywordShouldExist, htmlFile.file) - } - if strings.Contains(text, htmlFile.keywordShouldNotExist) { - t.Fatalf("keyword %s should not exists in file %s", htmlFile.keywordShouldNotExist, htmlFile.file) - } - } -} - -func TestStrippingWhitespace(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "test text", - "test text", - }, - { - " \ttext\ntext\n", - "text text", - }, - { - " \na \n\t \n \n a \t", - "a a", - }, - { - "test text", - "test text", - }, - { - "test    text ", - "test    text", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestParagraphsAndBreaks(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "Test text", - "Test text", - }, - { - "Test text
", - "Test text", - }, - { - "Test text
Test", - "Test text\nTest", - }, - { - "

Test text

", - "Test text", - }, - { - "

Test text

Test text

", - "Test text\n\nTest text", - }, - { - "\n

Test text

\n\n\n\t

Test text

\n", - "Test text\n\nTest text", - }, - { - "\n

Test text
Test text

\n", - "Test text\nTest text", - }, - { - "\n

Test text
\tTest text

\n", - "Test text\nTest text", - }, - { - "Test text

Test text", - "Test text\n\nTest text", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestTables(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "
", - "", - }, - { - "
cell1cell2
", - "cell1 cell2", - }, - { - "
row1
row2
", - "row1\nrow2", - }, - { - ` - - -
cell1-1cell1-2
cell2-1cell2-2
`, - "cell1-1 cell1-2\ncell2-1 cell2-2", - }, - { - "_
cell
_", - "_\n\ncell\n\n_", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestStrippingLists(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "", - "", - }, - { - "_", - "* item\n\n_", - }, - { - "
  • item 1
  • item 2
  • \n_", - "* item 1\n* item 2\n_", - }, - { - "
  • item 1
  • \t\n
  • item 2
  • item 3
  • \n_", - "* item 1\n* item 2\n* item 3\n_", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestLinks(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - ``, - ``, - }, - { - ``, - ``, - }, - { - ``, - `( http://example.com/ )`, - }, - { - `Link`, - `Link`, - }, - { - `Link`, - `Link ( http://example.com/ )`, - }, - { - `Link`, - `Link ( http://example.com/ )`, - }, - { - "\n\tLink\n\t", - `Link ( http://example.com/ )`, - }, - { - "Contact Us", - `Contact Us ( contact@example.org )`, - }, - { - "Link", - `Link ( http://example.com:80/~user?aaa=bb&c=d,e,f#foo )`, - }, - { - "Link", - `Link ( http://example.com/ )`, - }, - { - " Link ", - `Link ( http://example.com/ )`, - }, - { - "Link A Link B", - `Link A ( http://example.com/a/ ) Link B ( http://example.com/b/ )`, - }, - { - "Link", - `Link ( %%LINK%% )`, - }, - { - "Link", - `Link ( [LINK] )`, - }, - { - "Link", - `Link ( {LINK} )`, - }, - { - "Link", - `Link ( [[!unsubscribe]] )`, - }, - { - "

    This is link1 and link2 is next.

    ", - `This is link1 ( http://www.google.com ) and link2 ( http://www.google.com ) is next.`, - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestImageAltTags(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - ``, - ``, - }, - { - ``, - ``, - }, - { - `Example`, - ``, - }, - { - `Example`, - ``, - }, - // Images do matter if they are in a link - { - `Example`, - `Example ( http://example.com/ )`, - }, - { - `Example`, - `Example ( http://example.com/ )`, - }, - { - `Example`, - `Example ( http://example.com/ )`, - }, - { - `Example`, - `Example ( http://example.com/ )`, - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestHeadings(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "

    Test

    ", - "****\nTest\n****", - }, - { - "\t

    \nTest

    ", - "****\nTest\n****", - }, - { - "\t

    \nTest line 1
    Test 2

    ", - "***********\nTest line 1\nTest 2\n***********", - }, - { - "

    Test

    Test

    ", - "****\nTest\n****\n\n****\nTest\n****", - }, - { - "

    Test

    ", - "----\nTest\n----", - }, - { - "

    Test

    ", - "****************************\nTest ( http://example.com/ )\n****************************", - }, - { - "

    Test

    ", - "Test\n----", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } - -} - -func TestBold(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "Test", - "*Test*", - }, - { - "\tTest ", - "*Test*", - }, - { - "\tTest line 1
    Test 2
    ", - "*Test line 1\nTest 2*", - }, - { - "Test Test", - "*Test* *Test*", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } - -} - -func TestDiv(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "
    Test
    ", - "Test", - }, - { - "\t
    Test
    ", - "Test", - }, - { - "
    Test line 1
    Test 2
    ", - "Test line 1\nTest 2", - }, - { - "Test 1
    Test 2
    Test 3
    Test 4", - "Test 1\nTest 2\nTest 3\nTest 4", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } - -} - -func TestBlockquotes(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "
    level 0
    level 1
    level 2
    level 1
    level 0
    ", - "level 0\n> \n> level 1\n> \n>> level 2\n> \n> level 1\n\nlevel 0", - }, - { - "
    Test
    Test", - "> \n> Test\n\nTest", - }, - { - "\t
    \nTest
    ", - "> \n> Test\n>", - }, - { - "\t
    \nTest line 1
    Test 2
    ", - "> \n> Test line 1\n> Test 2", - }, - { - "
    Test
    Test
    Other Test", - "> \n> Test\n\n> \n> Test\n\nOther Test", - }, - { - "
    Lorem ipsum Commodo id consectetur pariatur ea occaecat minim aliqua ad sit consequat quis ex commodo Duis incididunt eu mollit consectetur fugiat voluptate dolore in pariatur in commodo occaecat Ut occaecat velit esse labore aute quis commodo non sit dolore officia Excepteur cillum amet cupidatat culpa velit labore ullamco dolore mollit elit in aliqua dolor irure do
    ", - "> \n> Lorem ipsum Commodo id consectetur pariatur ea occaecat minim aliqua ad\n> sit consequat quis ex commodo Duis incididunt eu mollit consectetur fugiat\n> voluptate dolore in pariatur in commodo occaecat Ut occaecat velit esse\n> labore aute quis commodo non sit dolore officia Excepteur cillum amet\n> cupidatat culpa velit labore ullamco dolore mollit elit in aliqua dolor\n> irure do", - }, - { - "
    LoremipsumCommodoidconsecteturpariatureaoccaecatminimaliquaadsitconsequatquisexcommodoDuisincididunteumollitconsecteturfugiatvoluptatedoloreinpariaturincommodooccaecatUtoccaecatvelitesselaboreautequiscommodononsitdoloreofficiaExcepteurcillumametcupidatatculpavelitlaboreullamcodoloremollitelitinaliquadoloriruredo
    ", - "> \n> Lorem *ipsum* *Commodo* *id* *consectetur* *pariatur* *ea* *occaecat* *minim*\n> *aliqua* *ad* *sit* *consequat* *quis* *ex* *commodo* *Duis* *incididunt* *eu*\n> *mollit* *consectetur* *fugiat* *voluptate* *dolore* *in* *pariatur* *in* *commodo*\n> *occaecat* *Ut* *occaecat* *velit* *esse* *labore* *aute* *quis* *commodo*\n> *non* *sit* *dolore* *officia* *Excepteur* *cillum* *amet* *cupidatat* *culpa*\n> *velit* *labore* *ullamco* *dolore* *mollit* *elit* *in* *aliqua* *dolor* *irure*\n> *do*", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } - -} - -func TestIgnoreStylesScriptsHead(t *testing.T) { - testCases := []struct { - input string - output string - }{ - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - "", - "", - }, - { - `Title`, - "", - }, - } - - for _, testCase := range testCases { - assertString(t, testCase.input, testCase.output) - } -} - -func TestText(t *testing.T) { - testCases := []struct { - input string - expr string - }{ - { - `
  • - New repository -
  • `, - `\* New repository \( /new \)`, - }, - { - `hi - -
    - - hello google -

    - test

    List:

    - - -`, - `hi -hello google \( https://google.com \) - -test - -List: - -\* Foo \( foo \) -\* Barsoap \( http://www.microshwhat.com/bar/soapy \) -\* Baz`, - }, - // Malformed input html. - { - `hi - - hello google - - test

    List:

    - - - `, - `hi hello google \( https://google.com \) test - -List: - -\* Foo \( foo \) -\* Bar \( /\n[ \t]+bar/baz \) -\* Baz`, - }, - } - - for _, testCase := range testCases { - assertRegexp(t, testCase.input, testCase.expr) - } -} - -type StringMatcher interface { - MatchString(string) bool - String() string -} - -type RegexpStringMatcher string - -func (m RegexpStringMatcher) MatchString(str string) bool { - return regexp.MustCompile(string(m)).MatchString(str) -} -func (m RegexpStringMatcher) String() string { - return string(m) -} - -type ExactStringMatcher string - -func (m ExactStringMatcher) MatchString(str string) bool { - return string(m) == str -} -func (m ExactStringMatcher) String() string { - return string(m) -} - -func assertRegexp(t *testing.T, input string, outputRE string) { - assertPlaintext(t, input, RegexpStringMatcher(outputRE)) -} - -func assertString(t *testing.T, input string, output string) { - assertPlaintext(t, input, ExactStringMatcher(output)) -} - -func assertPlaintext(t *testing.T, input string, matcher StringMatcher) { - text, err := FromString(input) - if err != nil { - t.Error(err) - } - if !matcher.MatchString(text) { - t.Errorf("Input did not match expression\n"+ - "Input:\n>>>>\n%s\n<<<<\n\n"+ - "Output:\n>>>>\n%s\n<<<<\n\n"+ - "Expected output:\n>>>>\n%s\n<<<<\n\n", - input, text, matcher.String()) - } else { - t.Logf("input:\n\n%s\n\n\n\noutput:\n\n%s\n", input, text) - } -} - -func Example() { - inputHtml := ` - - - My Mega Service - - - - - - - -

    Welcome to your new account on my service!

    - -

    - Here is some more information: - -

    -

    - - - ` - - text, err := FromString(inputHtml) - if err != nil { - panic(err) - } - fmt.Println(text) - - // Output: - // Mega Service ( http://mymegaservice.com/ ) - // - // ****************************************** - // Welcome to your new account on my service! - // ****************************************** - // - // Here is some more information: - // - // * Link 1: Example.com ( https://example.com ) - // * Link 2: Example2.com ( https://example2.com ) - // * Something else -} diff --git a/vendor/github.com/cpanato/html2text/testdata/utf8.html b/vendor/github.com/cpanato/html2text/testdata/utf8.html deleted file mode 100755 index 53d401ce9..000000000 --- a/vendor/github.com/cpanato/html2text/testdata/utf8.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - 学习之道:美国公认学习第一书title - - - - - -

    写在前面的话 -

    -

    在台湾的那次世界冠军赛上,我几近疯狂,直至两年后的今天,我仍沉浸在这次的经历中。这是我生平第一次如此深入地审视我自己,甚至是第一次尝试审视自己。这个过程令人很是兴奋,同时也有点感觉怪异。我重新认识了自我,看到了自己的另外一面,自己从未发觉的另外一面。为了生存,为了取胜,我成了一名角斗士,彻头彻尾,简单纯粹。我并没有意识到这一角色早已在我的心中生根发芽,呼之欲出。也许,他的出现已是不可避免。

    -

    而我这全新的一面,与我一直熟识的那个乔希,那个曾经害怕黑暗的孩子,那个象棋手,那个狂热于雨水、反复诵读杰克·克鲁亚克作品的年轻人之间,又有什么样的联系呢?这些都是我正在努力弄清楚的问题。

    -

    自台湾赛事之后,我急切非常,一心想要回到训练中去,摆脱自己已经达到巅峰的想法。在过去的两年中,我已经重新开始。这是一个新的起点。前方的路还很长,有待进一步的探索。

    -

    这本书的创作耗费了相当多的时间和精力。在成长的过程中,我在我的小房间里从未想过等待我的会是这样的战斗。在创作中,我的思想逐渐成熟;爱恋从分崩离析,到失而复得,世界冠军头衔从失之交臂,到囊中取物。如果说在我人生的第一个二十九年中,我学到了什么,那就是,我们永远无法预测结局,无论是重要的比赛、冒险,还是轰轰烈烈的爱情。我们唯一可以肯定的只有,出乎意料。不管我们做了多么万全的准备,在生活的真实场景中,我们总是会处于陌生的境地。我们也许会无法冷静,失去理智,感觉似乎整个世界都在针对我们。在这个时候,我们所要做的是要付出加倍的努力,要表现得比预想得更好。我认为,关键在于准备好随机应变,准备好在所能想象的高压下发挥出创造力。

    -

    读者朋友们,我非常希望你们在读过这本书后,可以得到启发,甚至会得到触动,从而能够根据各自的天赋与特长,去实现自己的梦想。这就是我写作此书的目的。我在字里行间所传达的理念曾经使我受益匪浅,我很希望它们可以为大家提供一个基本的框架和方向。如果我的方法言之有理,那么就请接受它,琢磨它,并加之自己的见解。忘记我的那些数字。真正的掌握需要通过自己发现一些最能够引起共鸣的信息,并将其彻底地融合进来,直至成为一体,这样我们才能随心所欲地驾驭它。

    -
    - - - \ No newline at end of file diff --git a/vendor/github.com/cpanato/html2text/testdata/utf8_with_bom.xhtml b/vendor/github.com/cpanato/html2text/testdata/utf8_with_bom.xhtml deleted file mode 100755 index 68f0ee707..000000000 --- a/vendor/github.com/cpanato/html2text/testdata/utf8_with_bom.xhtml +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - 1892年波兰文版序言title - - - - -
    -

    1892年波兰文版序言[18]

    -

    出版共产主义宣言的一种新的波兰文本已成为必要,这一事实,引起了许多感想。

    -

    首先值得注意的是,近来宣言在一定程度上已成为欧洲大陆大工业发展的一种尺度。一个国家的大工业越发展,该国工人中想认清自己作为工人阶级在有产阶级面前所处地位的要求就越增加,他们中间的社会主义运动也越扩大,因而对宣言的需求也越增长。这样,根据宣言用某国文字销行的份数,不仅能够相当确切地断定该国工人运动的状况,而且还能够相当确切地断定该国大工业发展的程度。

    -

    因此,波兰文的新版本标志着波兰工业的决定性进步。从十年前发表的上一个版本以来确实有了这种进步,对此丝毫不容置疑。俄国的波兰,会议的波兰[19],成了俄罗斯帝国巨大的工业区。俄国大工业是零星分散的,一部分在芬兰湾沿岸,一部分在中央区(莫斯科和弗拉基米尔),第三部分在黑海和亚速海沿岸,还有另一些散布在别处;而波兰工业则紧缩于相对狭小的地区,享受到由这种积聚引起的长处与短处。这种长处是竞争着的俄罗斯工厂主所承认的,他们要求实行保护关税以对付波兰,尽管他们渴望使波兰人俄罗斯化。这种短处,对波兰工厂主与俄罗斯政府来说,表现在社会主义思想在波兰工人中间的迅速传播和对宣言需求的增长。

    -

    但是,波兰工业的迅速发展——它超过了俄国工业——本身是波兰人民的坚强生命力的一个新证明,是波兰人民临近的民族复兴的一个新保证。而一个独立强盛的波兰的复兴,不只是一件同波兰人有关、而且是同我们大家有关的事情。只有当每个民族在自己内部完全自主时,欧洲各民族间真诚的国际合作才是可能的。1848年革命在无产阶级旗帜下,使无产阶级的战士最终只作了资产阶级的工作,这次革命通过自己遗嘱的执行者路易·波拿巴和俾斯麦也实现了意大利、德国和匈牙利的独立。然而波兰,它从1792年以来为革命做的比所有这三个国家总共做的还要多,而当它1863年失败于强大十倍的俄军的时候,人们却把它抛弃不顾了。贵族既未能保持住、也未能重新争得波兰的独立;今天波兰的独立对资产阶级至少是无所谓的。然而波兰的独立对于欧洲各民族和谐的合作是必需的。这种独立只有年轻的波兰无产阶级才能争得,而且在它的手中会很好地保持住。因为欧洲所有其余的工人都象波兰工人自己一样也需要波兰的独立。

    -

    弗·恩格斯

    -

    1892年2月10日于伦敦

    -
    -
    [18] 恩格斯用德文为《宣言》新的波兰文本写了这篇序言。1892年由波兰社会主义者在伦敦办的《黎明》杂志社出版。序言寄出后,恩格斯写信给门德尔森(1892年2月11日),信中说,他很愿意学会波兰文,并且深入研究波兰工人运动的发展,以便能够为《宣言》的下一版写一篇更详细的序言。——第20页
    -
    [19] 指维也纳会议的波兰,即根据1814—1815年维也纳会议的决定,以波兰王国的正式名义割给俄国的那部分波兰土地。——第20页
    - - - \ No newline at end of file diff --git a/vendor/github.com/davecgh/go-spew/.travis.yml b/vendor/github.com/davecgh/go-spew/.travis.yml index 984e0736e..34a55c287 100644 --- a/vendor/github.com/davecgh/go-spew/.travis.yml +++ b/vendor/github.com/davecgh/go-spew/.travis.yml @@ -1,14 +1,27 @@ language: go +go_import_path: github.com/davecgh/go-spew go: - - 1.5.4 - - 1.6.3 - - 1.7 + - 1.6.x + - 1.7.x + - 1.8.x + - 1.9.x + - tip +sudo: false install: - - go get -v golang.org/x/tools/cmd/cover + - go get -v github.com/alecthomas/gometalinter + - gometalinter --install script: - - go test -v -tags=safe ./spew - - go test -v -tags=testcgo ./spew -covermode=count -coverprofile=profile.cov + - export PATH=$PATH:$HOME/gopath/bin + - export GORACE="halt_on_error=1" + - test -z "$(gometalinter --disable-all + --enable=gofmt + --enable=golint + --enable=vet + --enable=gosimple + --enable=unconvert + --deadline=4m ./spew | tee /dev/stderr)" + - go test -v -race -tags safe ./spew + - go test -v -race -tags testcgo ./spew -covermode=atomic -coverprofile=profile.cov after_success: - go get -v github.com/mattn/goveralls - - export PATH=$PATH:$HOME/gopath/bin - goveralls -coverprofile=profile.cov -service=travis-ci diff --git a/vendor/github.com/davecgh/go-spew/LICENSE b/vendor/github.com/davecgh/go-spew/LICENSE index bb6733231..bc52e96f2 100644 --- a/vendor/github.com/davecgh/go-spew/LICENSE +++ b/vendor/github.com/davecgh/go-spew/LICENSE @@ -1,8 +1,8 @@ ISC License -Copyright (c) 2012-2013 Dave Collins +Copyright (c) 2012-2016 Dave Collins -Permission to use, copy, modify, and distribute this software for any +Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/vendor/github.com/davecgh/go-spew/README.md b/vendor/github.com/davecgh/go-spew/README.md index 556170ae6..f6ed02c3b 100644 --- a/vendor/github.com/davecgh/go-spew/README.md +++ b/vendor/github.com/davecgh/go-spew/README.md @@ -1,10 +1,9 @@ go-spew ======= -[![Build Status](https://travis-ci.org/davecgh/go-spew.png?branch=master)] -(https://travis-ci.org/davecgh/go-spew) [![Coverage Status] -(https://coveralls.io/repos/davecgh/go-spew/badge.png?branch=master)] -(https://coveralls.io/r/davecgh/go-spew?branch=master) +[![Build Status](https://img.shields.io/travis/davecgh/go-spew.svg)](https://travis-ci.org/davecgh/go-spew) +[![ISC License](http://img.shields.io/badge/license-ISC-blue.svg)](http://copyfree.org) +[![Coverage Status](https://img.shields.io/coveralls/davecgh/go-spew.svg)](https://coveralls.io/r/davecgh/go-spew?branch=master) Go-spew implements a deep pretty printer for Go data structures to aid in debugging. A comprehensive suite of tests with 100% test coverage is provided @@ -19,8 +18,7 @@ post about it ## Documentation -[![GoDoc](https://godoc.org/github.com/davecgh/go-spew/spew?status.png)] -(http://godoc.org/github.com/davecgh/go-spew/spew) +[![GoDoc](https://img.shields.io/badge/godoc-reference-blue.svg)](http://godoc.org/github.com/davecgh/go-spew/spew) Full `go doc` style documentation for the project can be viewed online without installing this package by using the excellent GoDoc site here: @@ -160,6 +158,15 @@ options. See the ConfigState documentation for more details. App Engine or with the "safe" build tag specified. Pointer method invocation is enabled by default. +* DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + +* DisableCapacities + DisableCapacities specifies whether to disable the printing of capacities + for arrays, slices, maps and channels. This is useful when diffing data + structures in tests. + * ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. @@ -191,4 +198,4 @@ using the unsafe package. ## License -Go-spew is licensed under the liberal ISC License. +Go-spew is licensed under the [copyfree](http://copyfree.org) ISC License. diff --git a/vendor/github.com/davecgh/go-spew/spew/bypass.go b/vendor/github.com/davecgh/go-spew/spew/bypass.go index d42a0bc4a..7f166c3a3 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypass.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypass.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Dave Collins +// Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -41,9 +41,9 @@ var ( // after commit 82f48826c6c7 which changed the format again to mirror // the original format. Code in the init function updates these offsets // as necessary. - offsetPtr = uintptr(ptrSize) + offsetPtr = ptrSize offsetScalar = uintptr(0) - offsetFlag = uintptr(ptrSize * 2) + offsetFlag = ptrSize * 2 // flagKindWidth and flagKindShift indicate various bits that the // reflect package uses internally to track kind information. @@ -58,7 +58,7 @@ var ( // changed their positions. Code in the init function updates these // flags as necessary. flagKindWidth = uintptr(5) - flagKindShift = uintptr(flagKindWidth - 1) + flagKindShift = flagKindWidth - 1 flagRO = uintptr(1 << 0) flagIndir = uintptr(1 << 1) ) diff --git a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go index e47a4e795..1fe3cf3d5 100644 --- a/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go +++ b/vendor/github.com/davecgh/go-spew/spew/bypasssafe.go @@ -1,4 +1,4 @@ -// Copyright (c) 2015 Dave Collins +// Copyright (c) 2015-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/common.go b/vendor/github.com/davecgh/go-spew/spew/common.go index 14f02dc15..1be8ce945 100644 --- a/vendor/github.com/davecgh/go-spew/spew/common.go +++ b/vendor/github.com/davecgh/go-spew/spew/common.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -180,7 +180,7 @@ func printComplex(w io.Writer, c complex128, floatPrecision int) { w.Write(closeParenBytes) } -// printHexPtr outputs a uintptr formatted as hexidecimal with a leading '0x' +// printHexPtr outputs a uintptr formatted as hexadecimal with a leading '0x' // prefix to Writer w. func printHexPtr(w io.Writer, p uintptr) { // Null pointer. diff --git a/vendor/github.com/davecgh/go-spew/spew/common_test.go b/vendor/github.com/davecgh/go-spew/spew/common_test.go index 39b7525b3..0f5ce47dc 100644 --- a/vendor/github.com/davecgh/go-spew/spew/common_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/common_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/config.go b/vendor/github.com/davecgh/go-spew/spew/config.go index 555282723..2e3d22f31 100644 --- a/vendor/github.com/davecgh/go-spew/spew/config.go +++ b/vendor/github.com/davecgh/go-spew/spew/config.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -67,6 +67,15 @@ type ConfigState struct { // Google App Engine or with the "safe" build tag specified. DisablePointerMethods bool + // DisablePointerAddresses specifies whether to disable the printing of + // pointer addresses. This is useful when diffing data structures in tests. + DisablePointerAddresses bool + + // DisableCapacities specifies whether to disable the printing of capacities + // for arrays, slices, maps and channels. This is useful when diffing + // data structures in tests. + DisableCapacities bool + // ContinueOnMethod specifies whether or not recursion should continue once // a custom error or Stringer interface is invoked. The default, false, // means it will print the results of invoking the custom error or Stringer diff --git a/vendor/github.com/davecgh/go-spew/spew/doc.go b/vendor/github.com/davecgh/go-spew/spew/doc.go index 5be0c4060..aacaac6f1 100644 --- a/vendor/github.com/davecgh/go-spew/spew/doc.go +++ b/vendor/github.com/davecgh/go-spew/spew/doc.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -91,6 +91,15 @@ The following configuration options are available: which only accept pointer receivers from non-pointer variables. Pointer method invocation is enabled by default. + * DisablePointerAddresses + DisablePointerAddresses specifies whether to disable the printing of + pointer addresses. This is useful when diffing data structures in tests. + + * DisableCapacities + DisableCapacities specifies whether to disable the printing of + capacities for arrays, slices, maps and channels. This is useful when + diffing data structures in tests. + * ContinueOnMethod Enables recursion into types after invoking error and Stringer interface methods. Recursion after method invocation is disabled by default. diff --git a/vendor/github.com/davecgh/go-spew/spew/dump.go b/vendor/github.com/davecgh/go-spew/spew/dump.go index a0ff95e27..f78d89fc1 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dump.go +++ b/vendor/github.com/davecgh/go-spew/spew/dump.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -35,16 +35,16 @@ var ( // cCharRE is a regular expression that matches a cgo char. // It is used to detect character arrays to hexdump them. - cCharRE = regexp.MustCompile("^.*\\._Ctype_char$") + cCharRE = regexp.MustCompile(`^.*\._Ctype_char$`) // cUnsignedCharRE is a regular expression that matches a cgo unsigned // char. It is used to detect unsigned character arrays to hexdump // them. - cUnsignedCharRE = regexp.MustCompile("^.*\\._Ctype_unsignedchar$") + cUnsignedCharRE = regexp.MustCompile(`^.*\._Ctype_unsignedchar$`) // cUint8tCharRE is a regular expression that matches a cgo uint8_t. // It is used to detect uint8_t arrays to hexdump them. - cUint8tCharRE = regexp.MustCompile("^.*\\._Ctype_uint8_t$") + cUint8tCharRE = regexp.MustCompile(`^.*\._Ctype_uint8_t$`) ) // dumpState contains information about the state of a dump operation. @@ -129,7 +129,7 @@ func (d *dumpState) dumpPtr(v reflect.Value) { d.w.Write(closeParenBytes) // Display pointer information. - if len(pointerChain) > 0 { + if !d.cs.DisablePointerAddresses && len(pointerChain) > 0 { d.w.Write(openParenBytes) for i, addr := range pointerChain { if i > 0 { @@ -143,10 +143,10 @@ func (d *dumpState) dumpPtr(v reflect.Value) { // Display dereferenced value. d.w.Write(openParenBytes) switch { - case nilFound == true: + case nilFound: d.w.Write(nilAngleBytes) - case cycleFound == true: + case cycleFound: d.w.Write(circularBytes) default: @@ -282,13 +282,13 @@ func (d *dumpState) dump(v reflect.Value) { case reflect.Map, reflect.String: valueLen = v.Len() } - if valueLen != 0 || valueCap != 0 { + if valueLen != 0 || !d.cs.DisableCapacities && valueCap != 0 { d.w.Write(openParenBytes) if valueLen != 0 { d.w.Write(lenEqualsBytes) printInt(d.w, int64(valueLen), 10) } - if valueCap != 0 { + if !d.cs.DisableCapacities && valueCap != 0 { if valueLen != 0 { d.w.Write(spaceBytes) } diff --git a/vendor/github.com/davecgh/go-spew/spew/dump_test.go b/vendor/github.com/davecgh/go-spew/spew/dump_test.go index 2b320401d..5aad9c7af 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dump_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/dump_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -70,7 +70,7 @@ import ( "github.com/davecgh/go-spew/spew" ) -// dumpTest is used to describe a test to be perfomed against the Dump method. +// dumpTest is used to describe a test to be performed against the Dump method. type dumpTest struct { in interface{} wants []string diff --git a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go index ed3e3c31a..108baa55f 100644 --- a/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/dumpcgo_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013 Dave Collins +// Copyright (c) 2013-2016 Dave Collins // // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above @@ -82,18 +82,20 @@ func addCgoDumpTests() { v5Len := fmt.Sprintf("%d", v5l) v5Cap := fmt.Sprintf("%d", v5c) v5t := "[6]testdata._Ctype_uint8_t" + v5t2 := "[6]testdata._Ctype_uchar" v5s := "(len=" + v5Len + " cap=" + v5Cap + ") " + "{\n 00000000 74 65 73 74 35 00 " + " |test5.|\n}" - addDumpTest(v5, "("+v5t+") "+v5s+"\n") + addDumpTest(v5, "("+v5t+") "+v5s+"\n", "("+v5t2+") "+v5s+"\n") // C typedefed unsigned char array. v6, v6l, v6c := testdata.GetCgoTypdefedUnsignedCharArray() v6Len := fmt.Sprintf("%d", v6l) v6Cap := fmt.Sprintf("%d", v6c) v6t := "[6]testdata._Ctype_custom_uchar_t" + v6t2 := "[6]testdata._Ctype_uchar" v6s := "(len=" + v6Len + " cap=" + v6Cap + ") " + "{\n 00000000 74 65 73 74 36 00 " + " |test6.|\n}" - addDumpTest(v6, "("+v6t+") "+v6s+"\n") + addDumpTest(v6, "("+v6t+") "+v6s+"\n", "("+v6t2+") "+v6s+"\n") } diff --git a/vendor/github.com/davecgh/go-spew/spew/example_test.go b/vendor/github.com/davecgh/go-spew/spew/example_test.go index de6c4e309..c6ec8c6d5 100644 --- a/vendor/github.com/davecgh/go-spew/spew/example_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/example_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/format.go b/vendor/github.com/davecgh/go-spew/spew/format.go index ecf3b80e2..b04edb7d7 100644 --- a/vendor/github.com/davecgh/go-spew/spew/format.go +++ b/vendor/github.com/davecgh/go-spew/spew/format.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -182,10 +182,10 @@ func (f *formatState) formatPtr(v reflect.Value) { // Display dereferenced value. switch { - case nilFound == true: + case nilFound: f.fs.Write(nilAngleBytes) - case cycleFound == true: + case cycleFound: f.fs.Write(circularShortBytes) default: diff --git a/vendor/github.com/davecgh/go-spew/spew/format_test.go b/vendor/github.com/davecgh/go-spew/spew/format_test.go index b664b3f13..0719eb916 100644 --- a/vendor/github.com/davecgh/go-spew/spew/format_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/format_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -75,7 +75,7 @@ import ( "github.com/davecgh/go-spew/spew" ) -// formatterTest is used to describe a test to be perfomed against NewFormatter. +// formatterTest is used to describe a test to be performed against NewFormatter. type formatterTest struct { format string in interface{} @@ -1536,14 +1536,14 @@ func TestPrintSortedKeys(t *testing.T) { t.Errorf("Sorted keys mismatch 3:\n %v %v", s, expected) } - s = cfg.Sprint(map[testStruct]int{testStruct{1}: 1, testStruct{3}: 3, testStruct{2}: 2}) + s = cfg.Sprint(map[testStruct]int{{1}: 1, {3}: 3, {2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 4:\n %v %v", s, expected) } if !spew.UnsafeDisabled { - s = cfg.Sprint(map[testStructP]int{testStructP{1}: 1, testStructP{3}: 3, testStructP{2}: 2}) + s = cfg.Sprint(map[testStructP]int{{1}: 1, {3}: 3, {2}: 2}) expected = "map[ts.1:1 ts.2:2 ts.3:3]" if s != expected { t.Errorf("Sorted keys mismatch 5:\n %v %v", s, expected) diff --git a/vendor/github.com/davecgh/go-spew/spew/internal_test.go b/vendor/github.com/davecgh/go-spew/spew/internal_test.go index 1069ee21c..e312b4fad 100644 --- a/vendor/github.com/davecgh/go-spew/spew/internal_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/internal_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -36,10 +36,7 @@ type dummyFmtState struct { } func (dfs *dummyFmtState) Flag(f int) bool { - if f == int('+') { - return true - } - return false + return f == int('+') } func (dfs *dummyFmtState) Precision() (int, bool) { diff --git a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go index 863b62cf5..a0c612ec3 100644 --- a/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/internalunsafe_test.go @@ -1,4 +1,4 @@ -// Copyright (c) 2013-2015 Dave Collins +// Copyright (c) 2013-2016 Dave Collins // Permission to use, copy, modify, and distribute this software for any // purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/spew.go b/vendor/github.com/davecgh/go-spew/spew/spew.go index d8233f542..32c0e3388 100644 --- a/vendor/github.com/davecgh/go-spew/spew/spew.go +++ b/vendor/github.com/davecgh/go-spew/spew/spew.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above diff --git a/vendor/github.com/davecgh/go-spew/spew/spew_test.go b/vendor/github.com/davecgh/go-spew/spew/spew_test.go index dbbc08567..b70466c69 100644 --- a/vendor/github.com/davecgh/go-spew/spew/spew_test.go +++ b/vendor/github.com/davecgh/go-spew/spew/spew_test.go @@ -1,5 +1,5 @@ /* - * Copyright (c) 2013 Dave Collins + * Copyright (c) 2013-2016 Dave Collins * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -130,12 +130,19 @@ func initSpewTests() { scsNoPmethods := &spew.ConfigState{Indent: " ", DisablePointerMethods: true} scsMaxDepth := &spew.ConfigState{Indent: " ", MaxDepth: 1} scsContinue := &spew.ConfigState{Indent: " ", ContinueOnMethod: true} + scsNoPtrAddr := &spew.ConfigState{DisablePointerAddresses: true} + scsNoCap := &spew.ConfigState{DisableCapacities: true} // Variables for tests on types which implement Stringer interface with and // without a pointer receiver. ts := stringer("test") tps := pstringer("test") + type ptrTester struct { + s *struct{} + } + tptr := &ptrTester{s: &struct{}{}} + // depthTester is used to test max depth handling for structs, array, slices // and maps. type depthTester struct { @@ -192,6 +199,10 @@ func initSpewTests() { {scsContinue, fCSFprint, "", te, "(error: 10) 10"}, {scsContinue, fCSFdump, "", te, "(spew_test.customError) " + "(error: 10) 10\n"}, + {scsNoPtrAddr, fCSFprint, "", tptr, "<*>{<*>{}}"}, + {scsNoPtrAddr, fCSSdump, "", tptr, "(*spew_test.ptrTester)({\ns: (*struct {})({\n})\n})\n"}, + {scsNoCap, fCSSdump, "", make([]string, 0, 10), "([]string) {\n}\n"}, + {scsNoCap, fCSSdump, "", make([]string, 1, 10), "([]string) (len=1) {\n(string) \"\"\n}\n"}, } } diff --git a/vendor/github.com/disintegration/imaging/helpers.go b/vendor/github.com/disintegration/imaging/helpers.go index 5fb2b5aac..d4e73f120 100644 --- a/vendor/github.com/disintegration/imaging/helpers.go +++ b/vendor/github.com/disintegration/imaging/helpers.go @@ -76,8 +76,32 @@ func Open(filename string) (image.Image, error) { return img, err } +type encodeConfig struct { + jpegQuality int +} + +var defaultEncodeConfig = encodeConfig{ + jpegQuality: 95, +} + +// EncodeOption sets an optional parameter for the Encode and Save functions. +type EncodeOption func(*encodeConfig) + +// JPEGQuality returns an EncodeOption that sets the output JPEG quality. +// Quality ranges from 1 to 100 inclusive, higher is better. Default is 95. +func JPEGQuality(quality int) EncodeOption { + return func(c *encodeConfig) { + c.jpegQuality = quality + } +} + // Encode writes the image img to w in the specified format (JPEG, PNG, GIF, TIFF or BMP). -func Encode(w io.Writer, img image.Image, format Format) error { +func Encode(w io.Writer, img image.Image, format Format, opts ...EncodeOption) error { + cfg := defaultEncodeConfig + for _, option := range opts { + option(&cfg) + } + var err error switch format { case JPEG: @@ -92,9 +116,9 @@ func Encode(w io.Writer, img image.Image, format Format) error { } } if rgba != nil { - err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: 95}) + err = jpeg.Encode(w, rgba, &jpeg.Options{Quality: cfg.jpegQuality}) } else { - err = jpeg.Encode(w, img, &jpeg.Options{Quality: 95}) + err = jpeg.Encode(w, img, &jpeg.Options{Quality: cfg.jpegQuality}) } case PNG: @@ -113,7 +137,16 @@ func Encode(w io.Writer, img image.Image, format Format) error { // Save saves the image to file with the specified filename. // The format is determined from the filename extension: "jpg" (or "jpeg"), "png", "gif", "tif" (or "tiff") and "bmp" are supported. -func Save(img image.Image, filename string) (err error) { +// +// Examples: +// +// // Save the image as PNG. +// err := imaging.Save(img, "out.png") +// +// // Save the image as JPEG with optional quality parameter set to 80. +// err := imaging.Save(img, "out.jpg", imaging.JPEGQuality(80)) +// +func Save(img image.Image, filename string, opts ...EncodeOption) (err error) { formats := map[string]Format{ ".jpg": JPEG, ".jpeg": JPEG, @@ -136,7 +169,7 @@ func Save(img image.Image, filename string) (err error) { } defer file.Close() - return Encode(file, img, f) + return Encode(file, img, f, opts...) } // New creates a new image with the specified width and height, and fills it with the specified color. diff --git a/vendor/github.com/fsnotify/fsnotify/.travis.yml b/vendor/github.com/fsnotify/fsnotify/.travis.yml index 3a5c933bc..981d1bb81 100644 --- a/vendor/github.com/fsnotify/fsnotify/.travis.yml +++ b/vendor/github.com/fsnotify/fsnotify/.travis.yml @@ -2,12 +2,14 @@ sudo: false language: go go: - - 1.6.3 + - 1.8.x + - 1.9.x - tip matrix: allow_failures: - go: tip + fast_finish: true before_script: - go get -u github.com/golang/lint/golint diff --git a/vendor/github.com/fsnotify/fsnotify/AUTHORS b/vendor/github.com/fsnotify/fsnotify/AUTHORS index 0a5bf8f61..5ab5d41c5 100644 --- a/vendor/github.com/fsnotify/fsnotify/AUTHORS +++ b/vendor/github.com/fsnotify/fsnotify/AUTHORS @@ -8,8 +8,10 @@ # Please keep the list sorted. +Aaron L Adrien Bustany Amit Krishnan +Anmol Sethi Bjørn Erik Pedersen Bruno Bigras Caleb Spare @@ -26,6 +28,7 @@ Kelvin Fo Ken-ichirou MATSUZAWA Matt Layher Nathan Youngman +Nickolai Zeldovich Patrick Paul Hammond Pawel Knap @@ -33,12 +36,15 @@ Pieter Droogendijk Pursuit92 Riku Voipio Rob Figueiredo +Rodrigo Chiossi Slawek Ligus Soge Zhang Tiffany Jernigan Tilak Sharma +Tom Payne Travis Cline Tudor Golubenco +Vahe Khachikyan Yukang bronze1man debrando diff --git a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md index 40d7660d5..be4d7ea2c 100644 --- a/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md +++ b/vendor/github.com/fsnotify/fsnotify/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## v1.4.7 / 2018-01-09 + +* BSD/macOS: Fix possible deadlock on closing the watcher on kqueue (thanks @nhooyr and @glycerine) +* Tests: Fix missing verb on format string (thanks @rchiossi) +* Linux: Fix deadlock in Remove (thanks @aarondl) +* Linux: Watch.Add improvements (avoid race, fix consistency, reduce garbage) (thanks @twpayne) +* Docs: Moved FAQ into the README (thanks @vahe) +* Linux: Properly handle inotify's IN_Q_OVERFLOW event (thanks @zeldovich) +* Docs: replace references to OS X with macOS + ## v1.4.2 / 2016-10-10 * Linux: use InotifyInit1 with IN_CLOEXEC to stop leaking a file descriptor to a child process when using fork/exec [#178](https://github.com/fsnotify/fsnotify/pull/178) (thanks @pattyshack) @@ -79,7 +89,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn ## v1.0.2 / 2014-08-17 -* [Fix] Missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Fix] Missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) * [Fix] Make ./path and path equivalent. (thanks @zhsso) ## v1.0.0 / 2014-08-15 @@ -142,7 +152,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn ## v0.9.2 / 2014-08-17 -* [Backport] Fix missing create events on OS X. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) +* [Backport] Fix missing create events on macOS. [#14](https://github.com/fsnotify/fsnotify/issues/14) (thanks @zhsso) ## v0.9.1 / 2014-06-12 @@ -161,7 +171,7 @@ kqueue: Fix logic for CREATE after REMOVE [#111](https://github.com/fsnotify/fsn ## v0.8.11 / 2013-11-02 * [Doc] Add Changelog [#72][] (thanks @nathany) -* [Doc] Spotlight and double modify events on OS X [#62][] (reported by @paulhammond) +* [Doc] Spotlight and double modify events on macOS [#62][] (reported by @paulhammond) ## v0.8.10 / 2013-10-19 diff --git a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md index 6a81ba489..828a60b24 100644 --- a/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md +++ b/vendor/github.com/fsnotify/fsnotify/CONTRIBUTING.md @@ -17,7 +17,7 @@ Please indicate that you have signed the CLA in your pull request. ### How fsnotify is Developed * Development is done on feature branches. -* Tests are run on BSD, Linux, OS X and Windows. +* Tests are run on BSD, Linux, macOS and Windows. * Pull requests are reviewed and [applied to master][am] using [hub][]. * Maintainers may modify or squash commits rather than asking contributors to. * To issue a new release, the maintainers will: @@ -44,7 +44,7 @@ This workflow is [thoroughly explained by Katrina Owen](https://splice.com/blog/ ### Testing -fsnotify uses build tags to compile different code on Linux, BSD, OS X, and Windows. +fsnotify uses build tags to compile different code on Linux, BSD, macOS, and Windows. Before doing a pull request, please do your best to test your changes on multiple platforms, and list which platforms you were able/unable to test on. @@ -58,7 +58,7 @@ To aid in cross-platform testing there is a Vagrantfile for Linux and BSD. Notice: fsnotify file system events won't trigger in shared folders. The tests get around this limitation by using the /tmp directory. -Right now there is no equivalent solution for Windows and OS X, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). +Right now there is no equivalent solution for Windows and macOS, but there are Windows VMs [freely available from Microsoft](http://www.modern.ie/en-us/virtualization-tools#downloads). ### Maintainers diff --git a/vendor/github.com/fsnotify/fsnotify/README.md b/vendor/github.com/fsnotify/fsnotify/README.md index 3c891e349..399320741 100644 --- a/vendor/github.com/fsnotify/fsnotify/README.md +++ b/vendor/github.com/fsnotify/fsnotify/README.md @@ -8,14 +8,14 @@ fsnotify utilizes [golang.org/x/sys](https://godoc.org/golang.org/x/sys) rather go get -u golang.org/x/sys/... ``` -Cross platform: Windows, Linux, BSD and OS X. +Cross platform: Windows, Linux, BSD and macOS. |Adapter |OS |Status | |----------|----------|----------| |inotify |Linux 2.6.27 or later, Android\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| -|kqueue |BSD, OS X, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| +|kqueue |BSD, macOS, iOS\*|Supported [![Build Status](https://travis-ci.org/fsnotify/fsnotify.svg?branch=master)](https://travis-ci.org/fsnotify/fsnotify)| |ReadDirectoryChangesW|Windows|Supported [![Build status](https://ci.appveyor.com/api/projects/status/ivwjubaih4r0udeh/branch/master?svg=true)](https://ci.appveyor.com/project/NathanYoungman/fsnotify/branch/master)| -|FSEvents |OS X |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| +|FSEvents |macOS |[Planned](https://github.com/fsnotify/fsnotify/issues/11)| |FEN |Solaris 11 |[In Progress](https://github.com/fsnotify/fsnotify/issues/12)| |fanotify |Linux 2.6.37+ | | |USN Journals |Windows |[Maybe](https://github.com/fsnotify/fsnotify/issues/53)| @@ -23,7 +23,7 @@ Cross platform: Windows, Linux, BSD and OS X. \* Android and iOS are untested. -Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) for usage. Consult the [Wiki](https://github.com/fsnotify/fsnotify/wiki) for the FAQ and further information. +Please see [the documentation](https://godoc.org/github.com/fsnotify/fsnotify) and consult the [FAQ](#faq) for usage information. ## API stability @@ -41,6 +41,35 @@ Please refer to [CONTRIBUTING][] before opening an issue or pull request. See [example_test.go](https://github.com/fsnotify/fsnotify/blob/master/example_test.go). +## FAQ + +**When a file is moved to another directory is it still being watched?** + +No (it shouldn't be, unless you are watching where it was moved to). + +**When I watch a directory, are all subdirectories watched as well?** + +No, you must add watches for any directory you want to watch (a recursive watcher is on the roadmap [#18][]). + +**Do I have to watch the Error and Event channels in a separate goroutine?** + +As of now, yes. Looking into making this single-thread friendly (see [howeyc #7][#7]) + +**Why am I receiving multiple events for the same file on OS X?** + +Spotlight indexing on OS X can result in multiple events (see [howeyc #62][#62]). A temporary workaround is to add your folder(s) to the *Spotlight Privacy settings* until we have a native FSEvents implementation (see [#11][]). + +**How many files can be watched at once?** + +There are OS-specific limits as to how many watches can be created: +* Linux: /proc/sys/fs/inotify/max_user_watches contains the limit, reaching this limit results in a "no space left on device" error. +* BSD / OSX: sysctl variables "kern.maxfiles" and "kern.maxfilesperproc", reaching these limits results in a "too many open files" error. + +[#62]: https://github.com/howeyc/fsnotify/issues/62 +[#18]: https://github.com/fsnotify/fsnotify/issues/18 +[#11]: https://github.com/fsnotify/fsnotify/issues/11 +[#7]: https://github.com/howeyc/fsnotify/issues/7 + [contributing]: https://github.com/fsnotify/fsnotify/blob/master/CONTRIBUTING.md ## Related Projects diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify.go b/vendor/github.com/fsnotify/fsnotify/fsnotify.go index e7f55fee7..190bf0de5 100644 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify.go +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify.go @@ -9,6 +9,7 @@ package fsnotify import ( "bytes" + "errors" "fmt" ) @@ -60,3 +61,6 @@ func (op Op) String() string { func (e Event) String() string { return fmt.Sprintf("%q: %s", e.Name, e.Op.String()) } + +// Common errors that can be reported by a watcher +var ErrEventOverflow = errors.New("fsnotify queue overflow") diff --git a/vendor/github.com/fsnotify/fsnotify/fsnotify_test.go b/vendor/github.com/fsnotify/fsnotify/fsnotify_test.go index 9d6d72afc..f9771d9df 100644 --- a/vendor/github.com/fsnotify/fsnotify/fsnotify_test.go +++ b/vendor/github.com/fsnotify/fsnotify/fsnotify_test.go @@ -6,7 +6,11 @@ package fsnotify -import "testing" +import ( + "os" + "testing" + "time" +) func TestEventStringWithValue(t *testing.T) { for opMask, expectedString := range map[Op]string{ @@ -38,3 +42,29 @@ func TestEventOpStringWithNoValue(t *testing.T) { t.Fatalf("Expected %s, got: %v", expectedOpString, event.Op.String()) } } + +// TestWatcherClose tests that the goroutine started by creating the watcher can be +// signalled to return at any time, even if there is no goroutine listening on the events +// or errors channels. +func TestWatcherClose(t *testing.T) { + t.Parallel() + + name := tempMkFile(t, "") + w := newWatcher(t) + err := w.Add(name) + if err != nil { + t.Fatal(err) + } + + err = os.Remove(name) + if err != nil { + t.Fatal(err) + } + // Allow the watcher to receive the event. + time.Sleep(time.Millisecond * 100) + + err = w.Close() + if err != nil { + t.Fatal(err) + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/inotify.go b/vendor/github.com/fsnotify/fsnotify/inotify.go index f3b74c51f..d9fd1b88a 100644 --- a/vendor/github.com/fsnotify/fsnotify/inotify.go +++ b/vendor/github.com/fsnotify/fsnotify/inotify.go @@ -24,7 +24,6 @@ type Watcher struct { Events chan Event Errors chan error mu sync.Mutex // Map access - cv *sync.Cond // sync removing on rm_watch with IN_IGNORE fd int poller *fdPoller watches map[string]*watch // Map of inotify watches (key: path) @@ -56,7 +55,6 @@ func NewWatcher() (*Watcher, error) { done: make(chan struct{}), doneResp: make(chan struct{}), } - w.cv = sync.NewCond(&w.mu) go w.readEvents() return w, nil @@ -103,21 +101,23 @@ func (w *Watcher) Add(name string) error { var flags uint32 = agnosticEvents w.mu.Lock() - watchEntry, found := w.watches[name] - w.mu.Unlock() - if found { - watchEntry.flags |= flags - flags |= unix.IN_MASK_ADD + defer w.mu.Unlock() + watchEntry := w.watches[name] + if watchEntry != nil { + flags |= watchEntry.flags | unix.IN_MASK_ADD } wd, errno := unix.InotifyAddWatch(w.fd, name, flags) if wd == -1 { return errno } - w.mu.Lock() - w.watches[name] = &watch{wd: uint32(wd), flags: flags} - w.paths[wd] = name - w.mu.Unlock() + if watchEntry == nil { + w.watches[name] = &watch{wd: uint32(wd), flags: flags} + w.paths[wd] = name + } else { + watchEntry.wd = uint32(wd) + watchEntry.flags = flags + } return nil } @@ -135,6 +135,13 @@ func (w *Watcher) Remove(name string) error { if !ok { return fmt.Errorf("can't remove non-existent inotify watch for: %s", name) } + + // We successfully removed the watch if InotifyRmWatch doesn't return an + // error, we need to clean up our internal state to ensure it matches + // inotify's kernel state. + delete(w.paths, int(watch.wd)) + delete(w.watches, name) + // inotify_rm_watch will return EINVAL if the file has been deleted; // the inotify will already have been removed. // watches and pathes are deleted in ignoreLinux() implicitly and asynchronously @@ -152,13 +159,6 @@ func (w *Watcher) Remove(name string) error { return errno } - // wait until ignoreLinux() deleting maps - exists := true - for exists { - w.cv.Wait() - _, exists = w.watches[name] - } - return nil } @@ -245,13 +245,31 @@ func (w *Watcher) readEvents() { mask := uint32(raw.Mask) nameLen := uint32(raw.Len) + + if mask&unix.IN_Q_OVERFLOW != 0 { + select { + case w.Errors <- ErrEventOverflow: + case <-w.done: + return + } + } + // If the event happened to the watched directory or the watched file, the kernel // doesn't append the filename to the event, but we would like to always fill the // the "Name" field with a valid filename. We retrieve the path of the watch from // the "paths" map. w.mu.Lock() - name := w.paths[int(raw.Wd)] + name, ok := w.paths[int(raw.Wd)] + // IN_DELETE_SELF occurs when the file/directory being watched is removed. + // This is a sign to clean up the maps, otherwise we are no longer in sync + // with the inotify kernel state which has already deleted the watch + // automatically. + if ok && mask&unix.IN_DELETE_SELF == unix.IN_DELETE_SELF { + delete(w.paths, int(raw.Wd)) + delete(w.watches, name) + } w.mu.Unlock() + if nameLen > 0 { // Point "bytes" at the first byte of the filename bytes := (*[unix.PathMax]byte)(unsafe.Pointer(&buf[offset+unix.SizeofInotifyEvent])) @@ -262,7 +280,7 @@ func (w *Watcher) readEvents() { event := newEvent(name, mask) // Send the events that are not ignored on the events channel - if !event.ignoreLinux(w, raw.Wd, mask) { + if !event.ignoreLinux(mask) { select { case w.Events <- event: case <-w.done: @@ -279,15 +297,9 @@ func (w *Watcher) readEvents() { // Certain types of events can be "ignored" and not sent over the Events // channel. Such as events marked ignore by the kernel, or MODIFY events // against files that do not exist. -func (e *Event) ignoreLinux(w *Watcher, wd int32, mask uint32) bool { +func (e *Event) ignoreLinux(mask uint32) bool { // Ignore anything the inotify API says to ignore if mask&unix.IN_IGNORED == unix.IN_IGNORED { - w.mu.Lock() - defer w.mu.Unlock() - name := w.paths[int(wd)] - delete(w.paths, int(wd)) - delete(w.watches, name) - w.cv.Broadcast() return true } diff --git a/vendor/github.com/fsnotify/fsnotify/inotify_test.go b/vendor/github.com/fsnotify/fsnotify/inotify_test.go index a4bb202d1..54f3f00eb 100644 --- a/vendor/github.com/fsnotify/fsnotify/inotify_test.go +++ b/vendor/github.com/fsnotify/fsnotify/inotify_test.go @@ -293,25 +293,23 @@ func TestInotifyRemoveTwice(t *testing.T) { t.Fatalf("Failed to add testFile: %v", err) } - err = os.Remove(testFile) + err = w.Remove(testFile) if err != nil { - t.Fatalf("Failed to remove testFile: %v", err) + t.Fatalf("wanted successful remove but got: %v", err) } err = w.Remove(testFile) if err == nil { t.Fatalf("no error on removing invalid file") } - s1 := fmt.Sprintf("%s", err) - err = w.Remove(testFile) - if err == nil { - t.Fatalf("no error on removing invalid file") + w.mu.Lock() + defer w.mu.Unlock() + if len(w.watches) != 0 { + t.Fatalf("Expected watches len is 0, but got: %d, %v", len(w.watches), w.watches) } - s2 := fmt.Sprintf("%s", err) - - if s1 != s2 { - t.Fatalf("receive different error - %s / %s", s1, s2) + if len(w.paths) != 0 { + t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths) } } @@ -358,3 +356,94 @@ func TestInotifyInnerMapLength(t *testing.T) { t.Fatalf("Expected paths len is 0, but got: %d, %v", len(w.paths), w.paths) } } + +func TestInotifyOverflow(t *testing.T) { + // We need to generate many more events than the + // fs.inotify.max_queued_events sysctl setting. + // We use multiple goroutines (one per directory) + // to speed up file creation. + numDirs := 128 + numFiles := 1024 + + testDir := tempMkdir(t) + defer os.RemoveAll(testDir) + + w, err := NewWatcher() + if err != nil { + t.Fatalf("Failed to create watcher: %v", err) + } + defer w.Close() + + for dn := 0; dn < numDirs; dn++ { + testSubdir := fmt.Sprintf("%s/%d", testDir, dn) + + err := os.Mkdir(testSubdir, 0777) + if err != nil { + t.Fatalf("Cannot create subdir: %v", err) + } + + err = w.Add(testSubdir) + if err != nil { + t.Fatalf("Failed to add subdir: %v", err) + } + } + + errChan := make(chan error, numDirs*numFiles) + + for dn := 0; dn < numDirs; dn++ { + testSubdir := fmt.Sprintf("%s/%d", testDir, dn) + + go func() { + for fn := 0; fn < numFiles; fn++ { + testFile := fmt.Sprintf("%s/%d", testSubdir, fn) + + handle, err := os.Create(testFile) + if err != nil { + errChan <- fmt.Errorf("Create failed: %v", err) + continue + } + + err = handle.Close() + if err != nil { + errChan <- fmt.Errorf("Close failed: %v", err) + continue + } + } + }() + } + + creates := 0 + overflows := 0 + + after := time.After(10 * time.Second) + for overflows == 0 && creates < numDirs*numFiles { + select { + case <-after: + t.Fatalf("Not done") + case err := <-errChan: + t.Fatalf("Got an error from file creator goroutine: %v", err) + case err := <-w.Errors: + if err == ErrEventOverflow { + overflows++ + } else { + t.Fatalf("Got an error from watcher: %v", err) + } + case evt := <-w.Events: + if !strings.HasPrefix(evt.Name, testDir) { + t.Fatalf("Got an event for an unknown file: %s", evt.Name) + } + if evt.Op == Create { + creates++ + } + } + } + + if creates == numDirs*numFiles { + t.Fatalf("Could not trigger overflow") + } + + if overflows == 0 { + t.Fatalf("No overflow and not enough creates (expected %d, got %d)", + numDirs*numFiles, creates) + } +} diff --git a/vendor/github.com/fsnotify/fsnotify/integration_darwin_test.go b/vendor/github.com/fsnotify/fsnotify/integration_darwin_test.go index 5564554f7..cd6adc273 100644 --- a/vendor/github.com/fsnotify/fsnotify/integration_darwin_test.go +++ b/vendor/github.com/fsnotify/fsnotify/integration_darwin_test.go @@ -13,9 +13,9 @@ import ( "golang.org/x/sys/unix" ) -// testExchangedataForWatcher tests the watcher with the exchangedata operation on OS X. +// testExchangedataForWatcher tests the watcher with the exchangedata operation on macOS. // -// This is widely used for atomic saves on OS X, e.g. TextMate and in Apple's NSDocument. +// This is widely used for atomic saves on macOS, e.g. TextMate and in Apple's NSDocument. // // See https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man2/exchangedata.2.html // Also see: https://github.com/textmate/textmate/blob/cd016be29489eba5f3c09b7b70b06da134dda550/Frameworks/io/src/swap_file_data.cc#L20 diff --git a/vendor/github.com/fsnotify/fsnotify/kqueue.go b/vendor/github.com/fsnotify/fsnotify/kqueue.go index c2b4acb18..86e76a3d6 100644 --- a/vendor/github.com/fsnotify/fsnotify/kqueue.go +++ b/vendor/github.com/fsnotify/fsnotify/kqueue.go @@ -22,7 +22,7 @@ import ( type Watcher struct { Events chan Event Errors chan error - done chan bool // Channel for sending a "quit message" to the reader goroutine + done chan struct{} // Channel for sending a "quit message" to the reader goroutine kq int // File descriptor (as returned by the kqueue() syscall). @@ -56,7 +56,7 @@ func NewWatcher() (*Watcher, error) { externalWatches: make(map[string]bool), Events: make(chan Event), Errors: make(chan error), - done: make(chan bool), + done: make(chan struct{}), } go w.readEvents() @@ -71,10 +71,8 @@ func (w *Watcher) Close() error { return nil } w.isClosed = true - w.mu.Unlock() // copy paths to remove while locked - w.mu.Lock() var pathsToRemove = make([]string, 0, len(w.watches)) for name := range w.watches { pathsToRemove = append(pathsToRemove, name) @@ -82,15 +80,12 @@ func (w *Watcher) Close() error { w.mu.Unlock() // unlock before calling Remove, which also locks - var err error for _, name := range pathsToRemove { - if e := w.Remove(name); e != nil && err == nil { - err = e - } + w.Remove(name) } - // Send "quit" message to the reader goroutine: - w.done <- true + // send a "quit" message to the reader goroutine + close(w.done) return nil } @@ -266,17 +261,12 @@ func (w *Watcher) addWatch(name string, flags uint32) (string, error) { func (w *Watcher) readEvents() { eventBuffer := make([]unix.Kevent_t, 10) +loop: for { // See if there is a message on the "done" channel select { case <-w.done: - err := unix.Close(w.kq) - if err != nil { - w.Errors <- err - } - close(w.Events) - close(w.Errors) - return + break loop default: } @@ -284,7 +274,11 @@ func (w *Watcher) readEvents() { kevents, err := read(w.kq, eventBuffer, &keventWaitTime) // EINTR is okay, the syscall was interrupted before timeout expired. if err != nil && err != unix.EINTR { - w.Errors <- err + select { + case w.Errors <- err: + case <-w.done: + break loop + } continue } @@ -319,8 +313,12 @@ func (w *Watcher) readEvents() { if path.isDir && event.Op&Write == Write && !(event.Op&Remove == Remove) { w.sendDirectoryChangeEvents(event.Name) } else { - // Send the event on the Events channel - w.Events <- event + // Send the event on the Events channel. + select { + case w.Events <- event: + case <-w.done: + break loop + } } if event.Op&Remove == Remove { @@ -352,6 +350,18 @@ func (w *Watcher) readEvents() { kevents = kevents[1:] } } + + // cleanup + err := unix.Close(w.kq) + if err != nil { + // only way the previous loop breaks is if w.done was closed so we need to async send to w.Errors. + select { + case w.Errors <- err: + default: + } + } + close(w.Events) + close(w.Errors) } // newEvent returns an platform-independent Event based on kqueue Fflags. @@ -407,7 +417,11 @@ func (w *Watcher) sendDirectoryChangeEvents(dirPath string) { // Get all files files, err := ioutil.ReadDir(dirPath) if err != nil { - w.Errors <- err + select { + case w.Errors <- err: + case <-w.done: + return + } } // Search for new files @@ -428,7 +442,11 @@ func (w *Watcher) sendFileCreatedEventIfNew(filePath string, fileInfo os.FileInf w.mu.Unlock() if !doesExist { // Send create event - w.Events <- newCreateEvent(filePath) + select { + case w.Events <- newCreateEvent(filePath): + case <-w.done: + return + } } // like watchDirectoryFiles (but without doing another ReadDir) diff --git a/vendor/github.com/go-ldap/ldap/.travis.yml b/vendor/github.com/go-ldap/ldap/.travis.yml index e32a2aa75..9782c9bac 100644 --- a/vendor/github.com/go-ldap/ldap/.travis.yml +++ b/vendor/github.com/go-ldap/ldap/.travis.yml @@ -1,8 +1,8 @@ language: go env: global: - - VET_VERSIONS="1.6 1.7 tip" - - LINT_VERSIONS="1.6 1.7 tip" + - VET_VERSIONS="1.6 1.7 1.8 1.9 tip" + - LINT_VERSIONS="1.6 1.7 1.8 1.9 tip" go: - 1.2 - 1.3 @@ -10,6 +10,8 @@ go: - 1.5 - 1.6 - 1.7 + - 1.8 + - 1.9 - tip matrix: fast_finish: true diff --git a/vendor/github.com/go-ldap/ldap/Makefile b/vendor/github.com/go-ldap/ldap/Makefile index c1fc96657..a9d351c76 100644 --- a/vendor/github.com/go-ldap/ldap/Makefile +++ b/vendor/github.com/go-ldap/ldap/Makefile @@ -1,5 +1,15 @@ .PHONY: default install build test quicktest fmt vet lint +GO_VERSION := $(shell go version | cut -d' ' -f3 | cut -d. -f2) + +# Only use the `-race` flag on newer versions of Go +IS_OLD_GO := $(shell test $(GO_VERSION) -le 2 && echo true) +ifeq ($(IS_OLD_GO),true) + RACE_FLAG := +else + RACE_FLAG := -race -cpu 1,2,4 +endif + default: fmt vet lint build quicktest install: @@ -9,7 +19,7 @@ build: go build -v ./... test: - go test -v -cover ./... + go test -v $(RACE_FLAG) -cover ./... quicktest: go test ./... diff --git a/vendor/github.com/go-ldap/ldap/atomic_value.go b/vendor/github.com/go-ldap/ldap/atomic_value.go new file mode 100644 index 000000000..bccf7573e --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/atomic_value.go @@ -0,0 +1,13 @@ +// +build go1.4 + +package ldap + +import ( + "sync/atomic" +) + +// For compilers that support it, we just use the underlying sync/atomic.Value +// type. +type atomicValue struct { + atomic.Value +} diff --git a/vendor/github.com/go-ldap/ldap/atomic_value_go13.go b/vendor/github.com/go-ldap/ldap/atomic_value_go13.go new file mode 100644 index 000000000..04920bb26 --- /dev/null +++ b/vendor/github.com/go-ldap/ldap/atomic_value_go13.go @@ -0,0 +1,28 @@ +// +build !go1.4 + +package ldap + +import ( + "sync" +) + +// This is a helper type that emulates the use of the "sync/atomic.Value" +// struct that's available in Go 1.4 and up. +type atomicValue struct { + value interface{} + lock sync.RWMutex +} + +func (av *atomicValue) Store(val interface{}) { + av.lock.Lock() + av.value = val + av.lock.Unlock() +} + +func (av *atomicValue) Load() interface{} { + av.lock.RLock() + ret := av.value + av.lock.RUnlock() + + return ret +} diff --git a/vendor/github.com/go-ldap/ldap/conn.go b/vendor/github.com/go-ldap/ldap/conn.go index b5bd99adb..eb28eb472 100644 --- a/vendor/github.com/go-ldap/ldap/conn.go +++ b/vendor/github.com/go-ldap/ldap/conn.go @@ -11,6 +11,7 @@ import ( "log" "net" "sync" + "sync/atomic" "time" "gopkg.in/asn1-ber.v1" @@ -82,20 +83,18 @@ const ( type Conn struct { conn net.Conn isTLS bool - isClosing bool - closeErr error + closing uint32 + closeErr atomicValue isStartingTLS bool Debug debugging - chanConfirm chan bool + chanConfirm chan struct{} messageContexts map[int64]*messageContext chanMessage chan *messagePacket chanMessageID chan int64 - wgSender sync.WaitGroup wgClose sync.WaitGroup - once sync.Once outstandingRequests uint messageMutex sync.Mutex - requestTimeout time.Duration + requestTimeout int64 } var _ Client = &Conn{} @@ -142,7 +141,7 @@ func DialTLS(network, addr string, config *tls.Config) (*Conn, error) { func NewConn(conn net.Conn, isTLS bool) *Conn { return &Conn{ conn: conn, - chanConfirm: make(chan bool), + chanConfirm: make(chan struct{}), chanMessageID: make(chan int64), chanMessage: make(chan *messagePacket, 10), messageContexts: map[int64]*messageContext{}, @@ -158,12 +157,22 @@ func (l *Conn) Start() { l.wgClose.Add(1) } +// isClosing returns whether or not we're currently closing. +func (l *Conn) isClosing() bool { + return atomic.LoadUint32(&l.closing) == 1 +} + +// setClosing sets the closing value to true +func (l *Conn) setClosing() bool { + return atomic.CompareAndSwapUint32(&l.closing, 0, 1) +} + // Close closes the connection. func (l *Conn) Close() { - l.once.Do(func() { - l.isClosing = true - l.wgSender.Wait() + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + if l.setClosing() { l.Debug.Printf("Sending quit message and waiting for confirmation") l.chanMessage <- &messagePacket{Op: MessageQuit} <-l.chanConfirm @@ -171,27 +180,25 @@ func (l *Conn) Close() { l.Debug.Printf("Closing network connection") if err := l.conn.Close(); err != nil { - log.Print(err) + log.Println(err) } l.wgClose.Done() - }) + } l.wgClose.Wait() } // SetTimeout sets the time after a request is sent that a MessageTimeout triggers func (l *Conn) SetTimeout(timeout time.Duration) { if timeout > 0 { - l.requestTimeout = timeout + atomic.StoreInt64(&l.requestTimeout, int64(timeout)) } } // Returns the next available messageID func (l *Conn) nextMessageID() int64 { - if l.chanMessageID != nil { - if messageID, ok := <-l.chanMessageID; ok { - return messageID - } + if messageID, ok := <-l.chanMessageID; ok { + return messageID } return 0 } @@ -258,7 +265,7 @@ func (l *Conn) sendMessage(packet *ber.Packet) (*messageContext, error) { } func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) (*messageContext, error) { - if l.isClosing { + if l.isClosing() { return nil, NewError(ErrorNetwork, errors.New("ldap: connection closed")) } l.messageMutex.Lock() @@ -297,7 +304,7 @@ func (l *Conn) sendMessageWithFlags(packet *ber.Packet, flags sendMessageFlags) func (l *Conn) finishMessage(msgCtx *messageContext) { close(msgCtx.done) - if l.isClosing { + if l.isClosing() { return } @@ -316,12 +323,12 @@ func (l *Conn) finishMessage(msgCtx *messageContext) { } func (l *Conn) sendProcessMessage(message *messagePacket) bool { - if l.isClosing { + l.messageMutex.Lock() + defer l.messageMutex.Unlock() + if l.isClosing() { return false } - l.wgSender.Add(1) l.chanMessage <- message - l.wgSender.Done() return true } @@ -333,15 +340,14 @@ func (l *Conn) processMessages() { for messageID, msgCtx := range l.messageContexts { // If we are closing due to an error, inform anyone who // is waiting about the error. - if l.isClosing && l.closeErr != nil { - msgCtx.sendResponse(&PacketResponse{Error: l.closeErr}) + if l.isClosing() && l.closeErr.Load() != nil { + msgCtx.sendResponse(&PacketResponse{Error: l.closeErr.Load().(error)}) } l.Debug.Printf("Closing channel for MessageID %d", messageID) close(msgCtx.responses) delete(l.messageContexts, messageID) } close(l.chanMessageID) - l.chanConfirm <- true close(l.chanConfirm) }() @@ -350,11 +356,7 @@ func (l *Conn) processMessages() { select { case l.chanMessageID <- messageID: messageID++ - case message, ok := <-l.chanMessage: - if !ok { - l.Debug.Printf("Shutting down - message channel is closed") - return - } + case message := <-l.chanMessage: switch message.Op { case MessageQuit: l.Debug.Printf("Shutting down - quit message received") @@ -377,14 +379,15 @@ func (l *Conn) processMessages() { l.messageContexts[message.MessageID] = message.Context // Add timeout if defined - if l.requestTimeout > 0 { + requestTimeout := time.Duration(atomic.LoadInt64(&l.requestTimeout)) + if requestTimeout > 0 { go func() { defer func() { if err := recover(); err != nil { log.Printf("ldap: recovered panic in RequestTimeout: %v", err) } }() - time.Sleep(l.requestTimeout) + time.Sleep(requestTimeout) timeoutMessage := &messagePacket{ Op: MessageTimeout, MessageID: message.MessageID, @@ -397,7 +400,7 @@ func (l *Conn) processMessages() { if msgCtx, ok := l.messageContexts[message.MessageID]; ok { msgCtx.sendResponse(&PacketResponse{message.Packet, nil}) } else { - log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing) + log.Printf("Received unexpected message %d, %v", message.MessageID, l.isClosing()) ber.PrintPacket(message.Packet) } case MessageTimeout: @@ -439,8 +442,8 @@ func (l *Conn) reader() { packet, err := ber.ReadPacket(l.conn) if err != nil { // A read error is expected here if we are closing the connection... - if !l.isClosing { - l.closeErr = fmt.Errorf("unable to read LDAP response packet: %s", err) + if !l.isClosing() { + l.closeErr.Store(fmt.Errorf("unable to read LDAP response packet: %s", err)) l.Debug.Printf("reader error: %s", err.Error()) } return diff --git a/vendor/github.com/go-ldap/ldap/conn_test.go b/vendor/github.com/go-ldap/ldap/conn_test.go index 10766bbd4..488754d16 100644 --- a/vendor/github.com/go-ldap/ldap/conn_test.go +++ b/vendor/github.com/go-ldap/ldap/conn_test.go @@ -60,7 +60,7 @@ func TestUnresponsiveConnection(t *testing.T) { // TestFinishMessage tests that we do not enter deadlock when a goroutine makes // a request but does not handle all responses from the server. -func TestConn(t *testing.T) { +func TestFinishMessage(t *testing.T) { ptc := newPacketTranslatorConn() defer ptc.Close() @@ -174,16 +174,12 @@ func testSendUnhandledResponsesAndFinish(t *testing.T, ptc *packetTranslatorConn } func runWithTimeout(t *testing.T, timeout time.Duration, f func()) { - runtime.Gosched() - done := make(chan struct{}) go func() { f() close(done) }() - runtime.Gosched() - select { case <-done: // Success! case <-time.After(timeout): @@ -192,7 +188,7 @@ func runWithTimeout(t *testing.T, timeout time.Duration, f func()) { } } -// packetTranslatorConn is a helful type which can be used with various tests +// packetTranslatorConn is a helpful type which can be used with various tests // in this package. It implements the net.Conn interface to be used as an // underlying connection for a *ldap.Conn. Most methods are no-ops but the // Read() and Write() methods are able to translate ber-encoded packets for @@ -245,7 +241,7 @@ func (c *packetTranslatorConn) Read(b []byte) (n int, err error) { } // SendResponse writes the given response packet to the response buffer for -// this conection, signalling any goroutine waiting to read a response. +// this connection, signalling any goroutine waiting to read a response. func (c *packetTranslatorConn) SendResponse(packet *ber.Packet) error { c.lock.Lock() defer c.lock.Unlock() diff --git a/vendor/github.com/go-ldap/ldap/debug.go b/vendor/github.com/go-ldap/ldap/debug.go index b8a7ecbff..7279fc251 100644 --- a/vendor/github.com/go-ldap/ldap/debug.go +++ b/vendor/github.com/go-ldap/ldap/debug.go @@ -6,7 +6,7 @@ import ( "gopkg.in/asn1-ber.v1" ) -// debbuging type +// debugging type // - has a Printf method to write the debug output type debugging bool diff --git a/vendor/github.com/go-ldap/ldap/dn.go b/vendor/github.com/go-ldap/ldap/dn.go index a8ece3142..34e9023af 100644 --- a/vendor/github.com/go-ldap/ldap/dn.go +++ b/vendor/github.com/go-ldap/ldap/dn.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. // -// File contains DN parsing functionallity +// File contains DN parsing functionality // // https://tools.ietf.org/html/rfc4514 // @@ -52,7 +52,7 @@ import ( "fmt" "strings" - ber "gopkg.in/asn1-ber.v1" + "gopkg.in/asn1-ber.v1" ) // AttributeTypeAndValue represents an attributeTypeAndValue from https://tools.ietf.org/html/rfc4514 @@ -143,6 +143,9 @@ func ParseDN(str string) (*DN, error) { } } else if char == ',' || char == '+' { // We're done with this RDN or value, push it + if len(attribute.Type) == 0 { + return nil, errors.New("incomplete type, value pair") + } attribute.Value = stringFromBuffer() rdn.Attributes = append(rdn.Attributes, attribute) attribute = new(AttributeTypeAndValue) diff --git a/vendor/github.com/go-ldap/ldap/dn_test.go b/vendor/github.com/go-ldap/ldap/dn_test.go index 5055cc15b..af5fc1468 100644 --- a/vendor/github.com/go-ldap/ldap/dn_test.go +++ b/vendor/github.com/go-ldap/ldap/dn_test.go @@ -75,11 +75,13 @@ func TestSuccessfulDNParsing(t *testing.T) { func TestErrorDNParsing(t *testing.T) { testcases := map[string]string{ - "*": "DN ended with incomplete type, value pair", - "cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'", - "cn=Jim\\0": "Got corrupted escaped character", - "DC=example,=net": "DN ended with incomplete type, value pair", - "1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string", + "*": "DN ended with incomplete type, value pair", + "cn=Jim\\0Test": "Failed to decode escaped character: encoding/hex: invalid byte: U+0054 'T'", + "cn=Jim\\0": "Got corrupted escaped character", + "DC=example,=net": "DN ended with incomplete type, value pair", + "1=#0402486": "Failed to decode BER encoding: encoding/hex: odd length hex string", + "test,DC=example,DC=com": "incomplete type, value pair", + "=test,DC=example,DC=com": "incomplete type, value pair", } for test, answer := range testcases { diff --git a/vendor/github.com/go-ldap/ldap/error.go b/vendor/github.com/go-ldap/ldap/error.go index ff697873d..4cccb537f 100644 --- a/vendor/github.com/go-ldap/ldap/error.go +++ b/vendor/github.com/go-ldap/ldap/error.go @@ -97,6 +97,13 @@ var LDAPResultCodeMap = map[uint8]string{ LDAPResultObjectClassModsProhibited: "Object Class Mods Prohibited", LDAPResultAffectsMultipleDSAs: "Affects Multiple DSAs", LDAPResultOther: "Other", + + ErrorNetwork: "Network Error", + ErrorFilterCompile: "Filter Compile Error", + ErrorFilterDecompile: "Filter Decompile Error", + ErrorDebugging: "Debugging Error", + ErrorUnexpectedMessage: "Unexpected Message", + ErrorUnexpectedResponse: "Unexpected Response", } func getLDAPResultCode(packet *ber.Packet) (code uint8, description string) { diff --git a/vendor/github.com/go-ldap/ldap/error_test.go b/vendor/github.com/go-ldap/ldap/error_test.go index c010ebe3e..e456431bd 100644 --- a/vendor/github.com/go-ldap/ldap/error_test.go +++ b/vendor/github.com/go-ldap/ldap/error_test.go @@ -49,7 +49,7 @@ func TestConnReadErr(t *testing.T) { // Send the signal after a short amount of time. time.AfterFunc(10*time.Millisecond, func() { conn.signals <- expectedError }) - // This should block until the underlyiny conn gets the error signal + // This should block until the underlying conn gets the error signal // which should bubble up through the reader() goroutine, close the // connection, and _, err := ldapConn.Search(searchReq) @@ -58,7 +58,7 @@ func TestConnReadErr(t *testing.T) { } } -// signalErrConn is a helful type used with TestConnReadErr. It implements the +// signalErrConn is a helpful type used with TestConnReadErr. It implements the // net.Conn interface to be used as a connection for the test. Most methods are // no-ops but the Read() method blocks until it receives a signal which it // returns as an error. diff --git a/vendor/github.com/go-ldap/ldap/example_test.go b/vendor/github.com/go-ldap/ldap/example_test.go index b018a9664..650af0a43 100644 --- a/vendor/github.com/go-ldap/ldap/example_test.go +++ b/vendor/github.com/go-ldap/ldap/example_test.go @@ -9,7 +9,7 @@ import ( ) // ExampleConn_Bind demonstrates how to bind a connection to an ldap user -// allowing access to restricted attrabutes that user has access to +// allowing access to restricted attributes that user has access to func ExampleConn_Bind() { l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) if err != nil { @@ -63,10 +63,10 @@ func ExampleConn_StartTLS() { log.Fatal(err) } - // Opertations via l are now encrypted + // Operations via l are now encrypted } -// ExampleConn_Compare demonstrates how to comapre an attribute with a value +// ExampleConn_Compare demonstrates how to compare an attribute with a value func ExampleConn_Compare() { l, err := ldap.Dial("tcp", fmt.Sprintf("%s:%d", "ldap.example.com", 389)) if err != nil { @@ -193,7 +193,7 @@ func Example_userAuthentication() { searchRequest := ldap.NewSearchRequest( "dc=example,dc=com", ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false, - fmt.Sprintf("(&(objectClass=organizationalPerson)&(uid=%s))", username), + fmt.Sprintf("(&(objectClass=organizationalPerson)(uid=%s))", username), []string{"dn"}, nil, ) @@ -215,7 +215,7 @@ func Example_userAuthentication() { log.Fatal(err) } - // Rebind as the read only user for any futher queries + // Rebind as the read only user for any further queries err = l.Bind(bindusername, bindpassword) if err != nil { log.Fatal(err) @@ -240,7 +240,7 @@ func Example_beherappolicy() { if ppolicyControl != nil { ppolicy = ppolicyControl.(*ldap.ControlBeheraPasswordPolicy) } else { - log.Printf("ppolicyControl response not avaliable.\n") + log.Printf("ppolicyControl response not available.\n") } if err != nil { errStr := "ERROR: Cannot bind: " + err.Error() diff --git a/vendor/github.com/go-ldap/ldap/filter.go b/vendor/github.com/go-ldap/ldap/filter.go index 7eae310f1..3858a2865 100644 --- a/vendor/github.com/go-ldap/ldap/filter.go +++ b/vendor/github.com/go-ldap/ldap/filter.go @@ -82,7 +82,10 @@ func CompileFilter(filter string) (*ber.Packet, error) { if err != nil { return nil, err } - if pos != len(filter) { + switch { + case pos > len(filter): + return nil, NewError(ErrorFilterCompile, errors.New("ldap: unexpected end of filter")) + case pos < len(filter): return nil, NewError(ErrorFilterCompile, errors.New("ldap: finished compiling filter with extra at end: "+fmt.Sprint(filter[pos:]))) } return packet, nil diff --git a/vendor/github.com/go-ldap/ldap/filter_test.go b/vendor/github.com/go-ldap/ldap/filter_test.go index ae1b79b0c..2b019ac5d 100644 --- a/vendor/github.com/go-ldap/ldap/filter_test.go +++ b/vendor/github.com/go-ldap/ldap/filter_test.go @@ -131,6 +131,12 @@ var testFilters = []compileTest{ expectedType: 0, expectedErr: "unexpected end of filter", }, + compileTest{ + filterStr: `((cn=)`, + expectedFilter: ``, + expectedType: 0, + expectedErr: "unexpected end of filter", + }, compileTest{ filterStr: `(&(objectclass=inetorgperson)(cn=中文))`, expectedFilter: `(&(objectclass=inetorgperson)(cn=\e4\b8\ad\e6\96\87))`, diff --git a/vendor/github.com/go-ldap/ldap/ldap.go b/vendor/github.com/go-ldap/ldap/ldap.go index d27e639d0..496924756 100644 --- a/vendor/github.com/go-ldap/ldap/ldap.go +++ b/vendor/github.com/go-ldap/ldap/ldap.go @@ -9,7 +9,7 @@ import ( "io/ioutil" "os" - ber "gopkg.in/asn1-ber.v1" + "gopkg.in/asn1-ber.v1" ) // LDAP Application Codes diff --git a/vendor/github.com/go-ldap/ldap/passwdmodify.go b/vendor/github.com/go-ldap/ldap/passwdmodify.go index 26110ccf4..7d8246fd1 100644 --- a/vendor/github.com/go-ldap/ldap/passwdmodify.go +++ b/vendor/github.com/go-ldap/ldap/passwdmodify.go @@ -135,10 +135,10 @@ func (l *Conn) PasswordModify(passwordModifyRequest *PasswordModifyRequest) (*Pa extendedResponse := packet.Children[1] for _, child := range extendedResponse.Children { if child.Tag == 11 { - passwordModifyReponseValue := ber.DecodePacket(child.Data.Bytes()) - if len(passwordModifyReponseValue.Children) == 1 { - if passwordModifyReponseValue.Children[0].Tag == 0 { - result.GeneratedPassword = ber.DecodeString(passwordModifyReponseValue.Children[0].Data.Bytes()) + passwordModifyResponseValue := ber.DecodePacket(child.Data.Bytes()) + if len(passwordModifyResponseValue.Children) == 1 { + if passwordModifyResponseValue.Children[0].Tag == 0 { + result.GeneratedPassword = ber.DecodeString(passwordModifyResponseValue.Children[0].Data.Bytes()) } } } diff --git a/vendor/github.com/go-ldap/ldap/search_test.go b/vendor/github.com/go-ldap/ldap/search_test.go index efb8147d1..5f77b22e9 100644 --- a/vendor/github.com/go-ldap/ldap/search_test.go +++ b/vendor/github.com/go-ldap/ldap/search_test.go @@ -15,7 +15,7 @@ func TestNewEntry(t *testing.T) { "delta": {"value"}, "epsilon": {"value"}, } - exectedEntry := NewEntry(dn, attributes) + executedEntry := NewEntry(dn, attributes) iteration := 0 for { @@ -23,8 +23,8 @@ func TestNewEntry(t *testing.T) { break } testEntry := NewEntry(dn, attributes) - if !reflect.DeepEqual(exectedEntry, testEntry) { - t.Fatalf("consequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", exectedEntry, testEntry) + if !reflect.DeepEqual(executedEntry, testEntry) { + t.Fatalf("subsequent calls to NewEntry did not yield the same result:\n\texpected:\n\t%s\n\tgot:\n\t%s\n", executedEntry, testEntry) } iteration = iteration + 1 } diff --git a/vendor/github.com/go-redis/redis/.travis.yml b/vendor/github.com/go-redis/redis/.travis.yml index f49927ee8..c95b3e6c6 100644 --- a/vendor/github.com/go-redis/redis/.travis.yml +++ b/vendor/github.com/go-redis/redis/.travis.yml @@ -5,7 +5,6 @@ services: - redis-server go: - - 1.4.x - 1.7.x - 1.8.x - 1.9.x @@ -13,7 +12,6 @@ go: matrix: allow_failures: - - go: 1.4.x - go: tip install: diff --git a/vendor/github.com/go-redis/redis/README.md b/vendor/github.com/go-redis/redis/README.md index 0a2a67124..9f349764a 100644 --- a/vendor/github.com/go-redis/redis/README.md +++ b/vendor/github.com/go-redis/redis/README.md @@ -2,6 +2,7 @@ [![Build Status](https://travis-ci.org/go-redis/redis.png?branch=master)](https://travis-ci.org/go-redis/redis) [![GoDoc](https://godoc.org/github.com/go-redis/redis?status.svg)](https://godoc.org/github.com/go-redis/redis) +[![Airbrake](https://img.shields.io/badge/kudos-airbrake.io-orange.svg)](https://airbrake.io) Supports: @@ -66,14 +67,14 @@ func ExampleClient() { val2, err := client.Get("key2").Result() if err == redis.Nil { - fmt.Println("key2 does not exists") + fmt.Println("key2 does not exist") } else if err != nil { panic(err) } else { fmt.Println("key2", val2) } // Output: key value - // key2 does not exists + // key2 does not exist } ``` diff --git a/vendor/github.com/go-redis/redis/cluster.go b/vendor/github.com/go-redis/redis/cluster.go index c81fc1d57..accdb3d27 100644 --- a/vendor/github.com/go-redis/redis/cluster.go +++ b/vendor/github.com/go-redis/redis/cluster.go @@ -226,7 +226,7 @@ func (c *clusterNodes) NextGeneration() uint32 { } // GC removes unused nodes. -func (c *clusterNodes) GC(generation uint32) error { +func (c *clusterNodes) GC(generation uint32) { var collected []*clusterNode c.mu.Lock() for i := 0; i < len(c.addrs); { @@ -243,14 +243,11 @@ func (c *clusterNodes) GC(generation uint32) error { } c.mu.Unlock() - var firstErr error - for _, node := range collected { - if err := node.Client.Close(); err != nil && firstErr == nil { - firstErr = err + time.AfterFunc(time.Minute, func() { + for _, node := range collected { + _ = node.Client.Close() } - } - - return firstErr + }) } func (c *clusterNodes) All() ([]*clusterNode, error) { @@ -533,16 +530,22 @@ func (c *ClusterClient) cmdInfo(name string) *CommandInfo { return info } +func cmdSlot(cmd Cmder, pos int) int { + if pos == 0 { + return hashtag.RandomSlot() + } + firstKey := cmd.stringArg(pos) + return hashtag.Slot(firstKey) +} + func (c *ClusterClient) cmdSlot(cmd Cmder) int { cmdInfo := c.cmdInfo(cmd.Name()) - firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) - return hashtag.Slot(firstKey) + return cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo)) } func (c *ClusterClient) cmdSlotAndNode(state *clusterState, cmd Cmder) (int, *clusterNode, error) { cmdInfo := c.cmdInfo(cmd.Name()) - firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) - slot := hashtag.Slot(firstKey) + slot := cmdSlot(cmd, cmdFirstKeyPos(cmd, cmdInfo)) if cmdInfo != nil && cmdInfo.ReadOnly && c.opt.ReadOnly { if c.opt.RouteByLatency { @@ -590,6 +593,10 @@ func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error { break } + if internal.IsRetryableError(err, true) { + continue + } + moved, ask, addr := internal.IsMovedError(err) if moved || ask { c.lazyReloadState() @@ -600,6 +607,13 @@ func (c *ClusterClient) Watch(fn func(*Tx) error, keys ...string) error { continue } + if err == pool.ErrClosed { + node, err = state.slotMasterNode(slot) + if err != nil { + return err + } + } + return err } @@ -635,10 +649,10 @@ func (c *ClusterClient) Process(cmd Cmder) error { if ask { pipe := node.Client.Pipeline() - pipe.Process(NewCmd("ASKING")) - pipe.Process(cmd) + _ = pipe.Process(NewCmd("ASKING")) + _ = pipe.Process(cmd) _, err = pipe.Exec() - pipe.Close() + _ = pipe.Close() ask = false } else { err = node.Client.Process(cmd) @@ -679,6 +693,14 @@ func (c *ClusterClient) Process(cmd Cmder) error { continue } + if err == pool.ErrClosed { + _, node, err = c.cmdSlotAndNode(state, cmd) + if err != nil { + cmd.setErr(err) + return err + } + } + break } @@ -915,7 +937,11 @@ func (c *ClusterClient) pipelineExec(cmds []Cmder) error { for node, cmds := range cmdsMap { cn, _, err := node.Client.getConn() if err != nil { - setCmdsErr(cmds, err) + if err == pool.ErrClosed { + c.remapCmds(cmds, failedCmds) + } else { + setCmdsErr(cmds, err) + } continue } @@ -955,6 +981,18 @@ func (c *ClusterClient) mapCmdsByNode(cmds []Cmder) (map[*clusterNode][]Cmder, e return cmdsMap, nil } +func (c *ClusterClient) remapCmds(cmds []Cmder, failedCmds map[*clusterNode][]Cmder) { + remappedCmds, err := c.mapCmdsByNode(cmds) + if err != nil { + setCmdsErr(cmds, err) + return + } + + for node, cmds := range remappedCmds { + failedCmds[node] = cmds + } +} + func (c *ClusterClient) pipelineProcessCmds( node *clusterNode, cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder, ) error { @@ -1061,7 +1099,11 @@ func (c *ClusterClient) txPipelineExec(cmds []Cmder) error { for node, cmds := range cmdsMap { cn, _, err := node.Client.getConn() if err != nil { - setCmdsErr(cmds, err) + if err == pool.ErrClosed { + c.remapCmds(cmds, failedCmds) + } else { + setCmdsErr(cmds, err) + } continue } diff --git a/vendor/github.com/go-redis/redis/cluster_test.go b/vendor/github.com/go-redis/redis/cluster_test.go index 6f3677b93..43f3261bc 100644 --- a/vendor/github.com/go-redis/redis/cluster_test.go +++ b/vendor/github.com/go-redis/redis/cluster_test.go @@ -536,6 +536,32 @@ var _ = Describe("ClusterClient", func() { Expect(nodesList).Should(HaveLen(1)) }) + It("should RANDOMKEY", func() { + const nkeys = 100 + + for i := 0; i < nkeys; i++ { + err := client.Set(fmt.Sprintf("key%d", i), "value", 0).Err() + Expect(err).NotTo(HaveOccurred()) + } + + var keys []string + addKey := func(key string) { + for _, k := range keys { + if k == key { + return + } + } + keys = append(keys, key) + } + + for i := 0; i < nkeys*10; i++ { + key := client.RandomKey().Val() + addKey(key) + } + + Expect(len(keys)).To(BeNumerically("~", nkeys, nkeys/10)) + }) + assertClusterClient() }) diff --git a/vendor/github.com/go-redis/redis/command.go b/vendor/github.com/go-redis/redis/command.go index d2688082a..598ed9800 100644 --- a/vendor/github.com/go-redis/redis/command.go +++ b/vendor/github.com/go-redis/redis/command.go @@ -82,13 +82,13 @@ func cmdFirstKeyPos(cmd Cmder, info *CommandInfo) int { if cmd.stringArg(2) != "0" { return 3 } else { - return -1 + return 0 } case "publish": return 1 } if info == nil { - return -1 + return 0 } return int(info.FirstKeyPos) } @@ -675,6 +675,44 @@ func (cmd *StringIntMapCmd) readReply(cn *pool.Conn) error { //------------------------------------------------------------------------------ +type StringStructMapCmd struct { + baseCmd + + val map[string]struct{} +} + +var _ Cmder = (*StringStructMapCmd)(nil) + +func NewStringStructMapCmd(args ...interface{}) *StringStructMapCmd { + return &StringStructMapCmd{ + baseCmd: baseCmd{_args: args}, + } +} + +func (cmd *StringStructMapCmd) Val() map[string]struct{} { + return cmd.val +} + +func (cmd *StringStructMapCmd) Result() (map[string]struct{}, error) { + return cmd.val, cmd.err +} + +func (cmd *StringStructMapCmd) String() string { + return cmdString(cmd, cmd.val) +} + +func (cmd *StringStructMapCmd) readReply(cn *pool.Conn) error { + var v interface{} + v, cmd.err = cn.Rd.ReadArrayReply(stringStructMapParser) + if cmd.err != nil { + return cmd.err + } + cmd.val = v.(map[string]struct{}) + return nil +} + +//------------------------------------------------------------------------------ + type ZSliceCmd struct { baseCmd diff --git a/vendor/github.com/go-redis/redis/commands.go b/vendor/github.com/go-redis/redis/commands.go index c04b3c49b..569342cfa 100644 --- a/vendor/github.com/go-redis/redis/commands.go +++ b/vendor/github.com/go-redis/redis/commands.go @@ -143,6 +143,7 @@ type Cmdable interface { SInterStore(destination string, keys ...string) *IntCmd SIsMember(key string, member interface{}) *BoolCmd SMembers(key string) *StringSliceCmd + SMembersMap(key string) *StringStructMapCmd SMove(source, destination string, member interface{}) *BoolCmd SPop(key string) *StringCmd SPopN(key string, count int64) *StringSliceCmd @@ -676,6 +677,7 @@ func (c *cmdable) DecrBy(key string, decrement int64) *IntCmd { return cmd } +// Redis `GET key` command. It returns redis.Nil error when key does not exist. func (c *cmdable) Get(key string) *StringCmd { cmd := NewStringCmd("get", key) c.process(cmd) @@ -1163,12 +1165,20 @@ func (c *cmdable) SIsMember(key string, member interface{}) *BoolCmd { return cmd } +// Redis `SMEMBERS key` command output as a slice func (c *cmdable) SMembers(key string) *StringSliceCmd { cmd := NewStringSliceCmd("smembers", key) c.process(cmd) return cmd } +// Redis `SMEMBERS key` command output as a map +func (c *cmdable) SMembersMap(key string) *StringStructMapCmd { + cmd := NewStringStructMapCmd("smembers", key) + c.process(cmd) + return cmd +} + func (c *cmdable) SMove(source, destination string, member interface{}) *BoolCmd { cmd := NewBoolCmd("smove", source, destination, member) c.process(cmd) diff --git a/vendor/github.com/go-redis/redis/commands_test.go b/vendor/github.com/go-redis/redis/commands_test.go index 6b81f23cf..715379556 100644 --- a/vendor/github.com/go-redis/redis/commands_test.go +++ b/vendor/github.com/go-redis/redis/commands_test.go @@ -1848,6 +1848,17 @@ var _ = Describe("Commands", func() { Expect(sMembers.Val()).To(ConsistOf([]string{"Hello", "World"})) }) + It("should SMembersMap", func() { + sAdd := client.SAdd("set", "Hello") + Expect(sAdd.Err()).NotTo(HaveOccurred()) + sAdd = client.SAdd("set", "World") + Expect(sAdd.Err()).NotTo(HaveOccurred()) + + sMembersMap := client.SMembersMap("set") + Expect(sMembersMap.Err()).NotTo(HaveOccurred()) + Expect(sMembersMap.Val()).To(Equal(map[string]struct{}{"Hello": struct{}{}, "World": struct{}{}})) + }) + It("should SMove", func() { sAdd := client.SAdd("set1", "one") Expect(sAdd.Err()).NotTo(HaveOccurred()) diff --git a/vendor/github.com/go-redis/redis/example_test.go b/vendor/github.com/go-redis/redis/example_test.go index 7e04cd487..4d18ddb94 100644 --- a/vendor/github.com/go-redis/redis/example_test.go +++ b/vendor/github.com/go-redis/redis/example_test.go @@ -96,14 +96,14 @@ func ExampleClient() { val2, err := client.Get("key2").Result() if err == redis.Nil { - fmt.Println("key2 does not exists") + fmt.Println("key2 does not exist") } else if err != nil { panic(err) } else { fmt.Println("key2", val2) } // Output: key value - // key2 does not exists + // key2 does not exist } func ExampleClient_Set() { diff --git a/vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go b/vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go index 2866488e5..8c7ebbfa6 100644 --- a/vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go +++ b/vendor/github.com/go-redis/redis/internal/hashtag/hashtag.go @@ -55,13 +55,17 @@ func Key(key string) string { return key } +func RandomSlot() int { + return rand.Intn(SlotNumber) +} + // hashSlot returns a consistent slot number between 0 and 16383 // for any given string key. func Slot(key string) int { - key = Key(key) if key == "" { - return rand.Intn(SlotNumber) + return RandomSlot() } + key = Key(key) return int(crc16sum(key)) % SlotNumber } diff --git a/vendor/github.com/go-redis/redis/internal/proto/scan.go b/vendor/github.com/go-redis/redis/internal/proto/scan.go index 03c8b59aa..0329ffd99 100644 --- a/vendor/github.com/go-redis/redis/internal/proto/scan.go +++ b/vendor/github.com/go-redis/redis/internal/proto/scan.go @@ -123,8 +123,9 @@ func ScanSlice(data []string, slice interface{}) error { next := internal.MakeSliceNextElemFunc(v) for i, s := range data { elem := next() - if err := Scan(internal.StringToBytes(s), elem.Addr().Interface()); err != nil { - return fmt.Errorf("redis: ScanSlice(index=%d value=%q) failed: %s", i, s, err) + if err := Scan([]byte(s), elem.Addr().Interface()); err != nil { + err = fmt.Errorf("redis: ScanSlice index=%d value=%q failed: %s", i, s, err) + return err } } diff --git a/vendor/github.com/go-redis/redis/internal/safe.go b/vendor/github.com/go-redis/redis/internal/safe.go index 870fe541f..dc5f4cc8a 100644 --- a/vendor/github.com/go-redis/redis/internal/safe.go +++ b/vendor/github.com/go-redis/redis/internal/safe.go @@ -5,7 +5,3 @@ package internal func BytesToString(b []byte) string { return string(b) } - -func StringToBytes(s string) []byte { - return []byte(s) -} diff --git a/vendor/github.com/go-redis/redis/internal/unsafe.go b/vendor/github.com/go-redis/redis/internal/unsafe.go index c18b25c17..3ae48c14b 100644 --- a/vendor/github.com/go-redis/redis/internal/unsafe.go +++ b/vendor/github.com/go-redis/redis/internal/unsafe.go @@ -3,25 +3,10 @@ package internal import ( - "reflect" "unsafe" ) +// BytesToString converts byte slice to string. func BytesToString(b []byte) string { - bytesHeader := (*reflect.SliceHeader)(unsafe.Pointer(&b)) - strHeader := reflect.StringHeader{ - Data: bytesHeader.Data, - Len: bytesHeader.Len, - } - return *(*string)(unsafe.Pointer(&strHeader)) -} - -func StringToBytes(s string) []byte { - sh := (*reflect.StringHeader)(unsafe.Pointer(&s)) - bh := reflect.SliceHeader{ - Data: sh.Data, - Len: sh.Len, - Cap: sh.Len, - } - return *(*[]byte)(unsafe.Pointer(&bh)) + return *(*string)(unsafe.Pointer(&b)) } diff --git a/vendor/github.com/go-redis/redis/options_test.go b/vendor/github.com/go-redis/redis/options_test.go index 6a4af7169..211f6b195 100644 --- a/vendor/github.com/go-redis/redis/options_test.go +++ b/vendor/github.com/go-redis/redis/options_test.go @@ -71,7 +71,7 @@ func TestParseURL(t *testing.T) { t.Run(c.u, func(t *testing.T) { o, err := ParseURL(c.u) if c.err == nil && err != nil { - t.Fatalf("unexpected error: '%q'", err) + t.Fatalf("unexpected error: %q", err) return } if c.err != nil && err != nil { diff --git a/vendor/github.com/go-redis/redis/parser.go b/vendor/github.com/go-redis/redis/parser.go index 1d7ec630e..b378abc4e 100644 --- a/vendor/github.com/go-redis/redis/parser.go +++ b/vendor/github.com/go-redis/redis/parser.go @@ -97,6 +97,20 @@ func stringIntMapParser(rd *proto.Reader, n int64) (interface{}, error) { return m, nil } +// Implements proto.MultiBulkParse +func stringStructMapParser(rd *proto.Reader, n int64) (interface{}, error) { + m := make(map[string]struct{}, n) + for i := int64(0); i < n; i++ { + key, err := rd.ReadStringReply() + if err != nil { + return nil, err + } + + m[key] = struct{}{} + } + return m, nil +} + // Implements proto.MultiBulkParse func zSliceParser(rd *proto.Reader, n int64) (interface{}, error) { zz := make([]Z, n/2) diff --git a/vendor/github.com/go-redis/redis/redis.go b/vendor/github.com/go-redis/redis/redis.go index 230091b3e..37ffafd97 100644 --- a/vendor/github.com/go-redis/redis/redis.go +++ b/vendor/github.com/go-redis/redis/redis.go @@ -11,7 +11,7 @@ import ( "github.com/go-redis/redis/internal/proto" ) -// Redis nil reply, .e.g. when key does not exist. +// Redis nil reply returned when key does not exist. const Nil = internal.Nil func init() { diff --git a/vendor/github.com/go-redis/redis/ring.go b/vendor/github.com/go-redis/redis/ring.go index a30c32102..c11ef6bc2 100644 --- a/vendor/github.com/go-redis/redis/ring.go +++ b/vendor/github.com/go-redis/redis/ring.go @@ -298,6 +298,9 @@ func (c *Ring) cmdInfo(name string) *CommandInfo { if err != nil { return nil } + if c.cmdsInfo == nil { + return nil + } info := c.cmdsInfo[name] if info == nil { internal.Logf("info for cmd=%s not found", name) @@ -343,7 +346,11 @@ func (c *Ring) shardByName(name string) (*ringShard, error) { func (c *Ring) cmdShard(cmd Cmder) (*ringShard, error) { cmdInfo := c.cmdInfo(cmd.Name()) - firstKey := cmd.stringArg(cmdFirstKeyPos(cmd, cmdInfo)) + pos := cmdFirstKeyPos(cmd, cmdInfo) + if pos == 0 { + return c.randomShard() + } + firstKey := cmd.stringArg(pos) return c.shardByKey(firstKey) } diff --git a/vendor/github.com/go-redis/redis/universal.go b/vendor/github.com/go-redis/redis/universal.go index 29eb12b18..ea42f6984 100644 --- a/vendor/github.com/go-redis/redis/universal.go +++ b/vendor/github.com/go-redis/redis/universal.go @@ -114,6 +114,8 @@ func (o *UniversalOptions) simple() *Options { type UniversalClient interface { Cmdable Process(cmd Cmder) error + Subscribe(channels ...string) *PubSub + PSubscribe(channels ...string) *PubSub Close() error } diff --git a/vendor/github.com/go-sql-driver/mysql/.gitignore b/vendor/github.com/go-sql-driver/mysql/.gitignore index ba8e0cb3a..2de28da16 100644 --- a/vendor/github.com/go-sql-driver/mysql/.gitignore +++ b/vendor/github.com/go-sql-driver/mysql/.gitignore @@ -6,3 +6,4 @@ Icon? ehthumbs.db Thumbs.db +.idea diff --git a/vendor/github.com/go-sql-driver/mysql/.travis.yml b/vendor/github.com/go-sql-driver/mysql/.travis.yml index c1cc10aaf..e922f9187 100644 --- a/vendor/github.com/go-sql-driver/mysql/.travis.yml +++ b/vendor/github.com/go-sql-driver/mysql/.travis.yml @@ -1,13 +1,92 @@ sudo: false language: go go: - - 1.2 - - 1.3 - - 1.4 - - 1.5 - - 1.6 - - 1.7 - - tip + - 1.7.x + - 1.8.x + - 1.9.x + - master + +before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls before_script: + - echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf + - sudo service mysql restart + - .travis/wait_mysql.sh - mysql -e 'create database gotest;' + +matrix: + include: + - env: DB=MYSQL57 + sudo: required + dist: trusty + go: 1.9.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mysql:5.7 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB + - sleep 30 + - cp .travis/docker.cnf ~/.my.cnf + - mysql --print-defaults + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + + - env: DB=MARIA55 + sudo: required + dist: trusty + go: 1.9.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mariadb:5.5 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB + - sleep 30 + - cp .travis/docker.cnf ~/.my.cnf + - mysql --print-defaults + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + + - env: DB=MARIA10_1 + sudo: required + dist: trusty + go: 1.9.x + services: + - docker + before_install: + - go get golang.org/x/tools/cmd/cover + - go get github.com/mattn/goveralls + - docker pull mariadb:10.1 + - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret + mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB + - sleep 30 + - cp .travis/docker.cnf ~/.my.cnf + - mysql --print-defaults + - .travis/wait_mysql.sh + before_script: + - export MYSQL_TEST_USER=gotest + - export MYSQL_TEST_PASS=secret + - export MYSQL_TEST_ADDR=127.0.0.1:3307 + - export MYSQL_TEST_CONCURRENT=1 + +script: + - go test -v -covermode=count -coverprofile=coverage.out + - go vet ./... + - test -z "$(gofmt -d -s . | tee /dev/stderr)" +after_script: + - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci diff --git a/vendor/github.com/go-sql-driver/mysql/.travis/docker.cnf b/vendor/github.com/go-sql-driver/mysql/.travis/docker.cnf new file mode 100644 index 000000000..e57754e5a --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/.travis/docker.cnf @@ -0,0 +1,5 @@ +[client] +user = gotest +password = secret +host = 127.0.0.1 +port = 3307 diff --git a/vendor/github.com/go-sql-driver/mysql/.travis/wait_mysql.sh b/vendor/github.com/go-sql-driver/mysql/.travis/wait_mysql.sh new file mode 100755 index 000000000..abcf5f0ae --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/.travis/wait_mysql.sh @@ -0,0 +1,8 @@ +#!/bin/sh +while : +do + sleep 3 + if mysql -e 'select version()'; then + break + fi +done diff --git a/vendor/github.com/go-sql-driver/mysql/AUTHORS b/vendor/github.com/go-sql-driver/mysql/AUTHORS index 692c186fd..4702c83ab 100644 --- a/vendor/github.com/go-sql-driver/mysql/AUTHORS +++ b/vendor/github.com/go-sql-driver/mysql/AUTHORS @@ -12,35 +12,58 @@ # Individual Persons Aaron Hopkins +Achille Roussel Arne Hormann +Asta Xie +Bulat Gaifullin Carlos Nieto Chris Moos +Daniel Montoya Daniel Nichter Daniël van Eeden +Dave Protasowski DisposaBoy +Egor Smolyakov +Evan Shaw Frederick Mayle Gustavo Kristic Hanno Braun Henri Yandell Hirotaka Yamamoto +ICHINOSE Shogo INADA Naoki +Jacek Szwec James Harr +Jeff Hodges +Jeffrey Charles Jian Zhen Joshua Prunier Julien Lefevre Julien Schmidt +Justin Li +Justin Nuß Kamil Dziedzic Kevin Malachowski +Kieron Woodhouse Lennart Rudolph Leonardo YongUk Kim +Linh Tran Tuan +Lion Yang Luca Looz Lucas Liu Luke Scott +Maciej Zimnoch Michael Woolnough Nicola Peduzzi Olivier Mengué +oscarzhao Paul Bonser +Peter Schultz +Rebecca Chin +Reed Allman Runrioter Wung +Robert Russell +Shuode Li Soroush Pour Stan Putrya Stanley Gunawan @@ -52,5 +75,9 @@ Zhenye Xie # Organizations Barracuda Networks, Inc. +Counting Ltd. Google Inc. +InfoSum Ltd. +Keybase Inc. +Pivotal Inc. Stripe Inc. diff --git a/vendor/github.com/go-sql-driver/mysql/README.md b/vendor/github.com/go-sql-driver/mysql/README.md index a16012f81..299198d53 100644 --- a/vendor/github.com/go-sql-driver/mysql/README.md +++ b/vendor/github.com/go-sql-driver/mysql/README.md @@ -1,6 +1,6 @@ # Go-MySQL-Driver -A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) package +A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) package ![Go-MySQL-Driver logo](https://raw.github.com/wiki/go-sql-driver/mysql/gomysql_m.png "Golang Gopher holding the MySQL Dolphin") @@ -15,6 +15,9 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa * [Address](#address) * [Parameters](#parameters) * [Examples](#examples) + * [Connection pool and timeouts](#connection-pool-and-timeouts) + * [context.Context Support](#contextcontext-support) + * [ColumnType Support](#columntype-support) * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support) * [time.Time support](#timetime-support) * [Unicode support](#unicode-support) @@ -26,31 +29,31 @@ A MySQL-Driver for Go's [database/sql](http://golang.org/pkg/database/sql) packa ## Features * Lightweight and [fast](https://github.com/go-sql-driver/sql-benchmark "golang MySQL-Driver performance") * Native Go implementation. No C-bindings, just pure Go - * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](http://godoc.org/github.com/go-sql-driver/mysql#DialFunc) + * Connections over TCP/IPv4, TCP/IPv6, Unix domain sockets or [custom protocols](https://godoc.org/github.com/go-sql-driver/mysql#DialFunc) * Automatic handling of broken connections * Automatic Connection Pooling *(by database/sql package)* * Supports queries larger than 16MB - * Full [`sql.RawBytes`](http://golang.org/pkg/database/sql/#RawBytes) support. + * Full [`sql.RawBytes`](https://golang.org/pkg/database/sql/#RawBytes) support. * Intelligent `LONG DATA` handling in prepared statements * Secure `LOAD DATA LOCAL INFILE` support with file Whitelisting and `io.Reader` support * Optional `time.Time` parsing * Optional placeholder interpolation ## Requirements - * Go 1.2 or higher + * Go 1.7 or higher. We aim to support the 3 latest versions of Go. * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+) --------------------------------------- ## Installation -Simple install the package to your [$GOPATH](http://code.google.com/p/go-wiki/wiki/GOPATH "GOPATH") with the [go tool](http://golang.org/cmd/go/ "go command") from shell: +Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell: ```bash -$ go get github.com/go-sql-driver/mysql +$ go get -u github.com/go-sql-driver/mysql ``` -Make sure [Git is installed](http://git-scm.com/downloads) on your machine and in your system's `PATH`. +Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`. ## Usage -_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](http://golang.org/pkg/database/sql) API then. +_Go MySQL Driver_ is an implementation of Go's `database/sql/driver` interface. You only need to import the driver and can use the full [`database/sql`](https://golang.org/pkg/database/sql/) API then. Use `mysql` as `driverName` and a valid [DSN](#dsn-data-source-name) as `dataSourceName`: ```go @@ -95,13 +98,14 @@ Alternatively, [Config.FormatDSN](https://godoc.org/github.com/go-sql-driver/mys Passwords can consist of any character. Escaping is **not** necessary. #### Protocol -See [net.Dial](http://golang.org/pkg/net/#Dial) for more information which networks are available. +See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which networks are available. In general you should use an Unix domain socket if available and TCP otherwise for best performance. #### Address -For TCP and UDP networks, addresses have the form `host:port`. +For TCP and UDP networks, addresses have the form `host[:port]`. +If `port` is omitted, the default port will be used. If `host` is a literal IPv6 address, it must be enclosed in square brackets. -The functions [net.JoinHostPort](http://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](http://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. +The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form. For Unix domain sockets the address is the absolute path to the MySQL-Server-socket, e.g. `/var/run/mysqld/mysqld.sock` or `/tmp/mysql.sock`. @@ -136,9 +140,9 @@ Default: false ``` Type: bool Valid Values: true, false -Default: false +Default: true ``` -`allowNativePasswords=true` allows the usage of the mysql native password method. +`allowNativePasswords=false` disallows the usage of MySQL native password method. ##### `allowOldPasswords` @@ -220,19 +224,19 @@ Valid Values: Default: UTC ``` -Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](http://golang.org/pkg/time/#LoadLocation) for details. +Sets the location for time.Time values (when using `parseTime=true`). *"Local"* sets the system's location. See [time.LoadLocation](https://golang.org/pkg/time/#LoadLocation) for details. Note that this sets the location for time.Time values but does not change MySQL's [time_zone setting](https://dev.mysql.com/doc/refman/5.5/en/time-zone-support.html). For that see the [time_zone system variable](#system-variables), which can also be set as a DSN parameter. -Please keep in mind, that param values must be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. +Please keep in mind, that param values must be [url.QueryEscape](https://golang.org/pkg/net/url/#QueryEscape)'ed. Alternatively you can manually replace the `/` with `%2F`. For example `US/Pacific` would be `loc=US%2FPacific`. ##### `maxAllowedPacket` ``` Type: decimal number -Default: 0 +Default: 4194304 ``` -Max packet size allowed in bytes. Use `maxAllowedPacket=0` to automatically fetch the `max_allowed_packet` variable from server. +Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*. ##### `multiStatements` @@ -260,13 +264,13 @@ Default: false ##### `readTimeout` ``` -Type: decimal number +Type: duration Default: 0 ``` -I/O read timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. +I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. -##### `strict` +##### `rejectReadOnly` ``` Type: bool @@ -274,20 +278,37 @@ Valid Values: true, false Default: false ``` -`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations. -A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable. +`rejectReadOnly=true` causes the driver to reject read-only connections. This +is for a possible race condition during an automatic failover, where the mysql +client gets connected to a read-only replica after the failover. + +Note that this should be a fairly rare case, as an automatic failover normally +happens when the primary is down, and the race condition shouldn't happen +unless it comes back up online as soon as the failover is kicked off. On the +other hand, when this happens, a MySQL application can get stuck on a +read-only connection until restarted. It is however fairly easy to reproduce, +for example, using a manual failover on AWS Aurora's MySQL-compatible cluster. + +If you are not relying on read-only transactions to reject writes that aren't +supposed to happen, setting this on some MySQL providers (such as AWS Aurora) +is safer for failovers. + +Note that ERROR 1290 can be returned for a `read-only` server and this option will +cause a retry for that error. However the same error number is used for some +other cases. You should ensure your application will never cause an ERROR 1290 +except for `read-only` mode when enabling this option. -By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes. ##### `timeout` ``` -Type: decimal number +Type: duration Default: OS default ``` -*Driver* side connection timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout). +Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. + ##### `tls` @@ -297,16 +318,17 @@ Valid Values: true, false, skip-verify, Default: false ``` -`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](http://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). +`tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig). + ##### `writeTimeout` ``` -Type: decimal number +Type: duration Default: 0 ``` -I/O write timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. +I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*. ##### System Variables @@ -317,9 +339,9 @@ Any other parameters are interpreted as system variables: * `=%27%27`: `SET =''` Rules: -* The values for string variables must be quoted with ' +* The values for string variables must be quoted with `'`. * The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed! - (which implies values of string variables must be wrapped with `%27`) + (which implies values of string variables must be wrapped with `%27`). Examples: * `autocommit=1`: `SET autocommit=1` @@ -380,6 +402,18 @@ No Database preselected: user:password@/ ``` + +### Connection pool and timeouts +The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively. + +## `ColumnType` Support +This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported. + +## `context.Context` Support +Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts. +See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details. + + ### `LOAD DATA LOCAL INFILE` support For this feature you need direct access to the package. Therefore you must change the import path (no `_`): ```go @@ -390,17 +424,17 @@ Files must be whitelisted by registering them with `mysql.RegisterLocalFile(file To use a `io.Reader` a handler function must be registered with `mysql.RegisterReaderHandler(name, handler)` which returns a `io.Reader` or `io.ReadCloser`. The Reader is available with the filepath `Reader::` then. Choose different names for different handlers and `DeregisterReaderHandler` when you don't need it anymore. -See the [godoc of Go-MySQL-Driver](http://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. +See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/mysql "golang mysql driver documentation") for details. ### `time.Time` support -The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm. +The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program. -However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](http://golang.org/pkg/time/#Location) with the `loc` DSN parameter. +However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter. **Caution:** As of Go 1.1, this makes `time.Time` the only variable type you can scan `DATE` and `DATETIME` values into. This breaks for example [`sql.RawBytes` support](https://github.com/go-sql-driver/mysql/wiki/Examples#rawbytes). -Alternatively you can use the [`NullTime`](http://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`. +Alternatively you can use the [`NullTime`](https://godoc.org/github.com/go-sql-driver/mysql#NullTime) type as the scan destination, which works with both `time.Time` and `string` / `[]byte`. ### Unicode support @@ -412,7 +446,6 @@ Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAM See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support. - ## Testing / Development To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details. @@ -431,13 +464,13 @@ Mozilla summarizes the license scope as follows: That means: - * You can **use** the **unchanged** source code both in private and commercially - * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0) - * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged** + * You can **use** the **unchanged** source code both in private and commercially. + * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0). + * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**. -Please read the [MPL 2.0 FAQ](http://www.mozilla.org/MPL/2.0/FAQ.html) if you have further questions regarding the license. +Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license. -You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE) +You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE). ![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow") diff --git a/vendor/github.com/go-sql-driver/mysql/appengine.go b/vendor/github.com/go-sql-driver/mysql/appengine.go index 565614eef..be41f2ee6 100644 --- a/vendor/github.com/go-sql-driver/mysql/appengine.go +++ b/vendor/github.com/go-sql-driver/mysql/appengine.go @@ -11,7 +11,7 @@ package mysql import ( - "appengine/cloudsql" + "google.golang.org/appengine/cloudsql" ) func init() { diff --git a/vendor/github.com/go-sql-driver/mysql/benchmark_go18_test.go b/vendor/github.com/go-sql-driver/mysql/benchmark_go18_test.go new file mode 100644 index 000000000..d6a7e9d6e --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/benchmark_go18_test.go @@ -0,0 +1,93 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "fmt" + "runtime" + "testing" +) + +func benchmarkQueryContext(b *testing.B, db *sql.DB, p int) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0)) + + tb := (*TB)(b) + stmt := tb.checkStmt(db.PrepareContext(ctx, "SELECT val FROM foo WHERE id=?")) + defer stmt.Close() + + b.SetParallelism(p) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + var got string + for pb.Next() { + tb.check(stmt.QueryRow(1).Scan(&got)) + if got != "one" { + b.Fatalf("query = %q; want one", got) + } + } + }) +} + +func BenchmarkQueryContext(b *testing.B) { + db := initDB(b, + "DROP TABLE IF EXISTS foo", + "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", + `INSERT INTO foo VALUES (1, "one")`, + `INSERT INTO foo VALUES (2, "two")`, + ) + defer db.Close() + for _, p := range []int{1, 2, 3, 4} { + b.Run(fmt.Sprintf("%d", p), func(b *testing.B) { + benchmarkQueryContext(b, db, p) + }) + } +} + +func benchmarkExecContext(b *testing.B, db *sql.DB, p int) { + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + db.SetMaxIdleConns(p * runtime.GOMAXPROCS(0)) + + tb := (*TB)(b) + stmt := tb.checkStmt(db.PrepareContext(ctx, "DO 1")) + defer stmt.Close() + + b.SetParallelism(p) + b.ReportAllocs() + b.ResetTimer() + b.RunParallel(func(pb *testing.PB) { + for pb.Next() { + if _, err := stmt.ExecContext(ctx); err != nil { + b.Fatal(err) + } + } + }) +} + +func BenchmarkExecContext(b *testing.B) { + db := initDB(b, + "DROP TABLE IF EXISTS foo", + "CREATE TABLE foo (id INT PRIMARY KEY, val CHAR(50))", + `INSERT INTO foo VALUES (1, "one")`, + `INSERT INTO foo VALUES (2, "two")`, + ) + defer db.Close() + for _, p := range []int{1, 2, 3, 4} { + b.Run(fmt.Sprintf("%d", p), func(b *testing.B) { + benchmarkQueryContext(b, db, p) + }) + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/benchmark_test.go b/vendor/github.com/go-sql-driver/mysql/benchmark_test.go index 7da833a2a..c1de8672b 100644 --- a/vendor/github.com/go-sql-driver/mysql/benchmark_test.go +++ b/vendor/github.com/go-sql-driver/mysql/benchmark_test.go @@ -48,11 +48,7 @@ func initDB(b *testing.B, queries ...string) *sql.DB { db := tb.checkDB(sql.Open("mysql", dsn)) for _, query := range queries { if _, err := db.Exec(query); err != nil { - if w, ok := err.(MySQLWarnings); ok { - b.Logf("warning on %q: %v", query, w) - } else { - b.Fatalf("error on %q: %v", query, err) - } + b.Fatalf("error on %q: %v", query, err) } } return db diff --git a/vendor/github.com/go-sql-driver/mysql/collations.go b/vendor/github.com/go-sql-driver/mysql/collations.go index 82079cfb9..136c9e4d1 100644 --- a/vendor/github.com/go-sql-driver/mysql/collations.go +++ b/vendor/github.com/go-sql-driver/mysql/collations.go @@ -9,6 +9,7 @@ package mysql const defaultCollation = "utf8_general_ci" +const binaryCollation = "binary" // A list of available collations mapped to the internal ID. // To update this map use the following MySQL query: diff --git a/vendor/github.com/go-sql-driver/mysql/connection.go b/vendor/github.com/go-sql-driver/mysql/connection.go index d82c728f3..e57061412 100644 --- a/vendor/github.com/go-sql-driver/mysql/connection.go +++ b/vendor/github.com/go-sql-driver/mysql/connection.go @@ -10,12 +10,23 @@ package mysql import ( "database/sql/driver" + "io" "net" "strconv" "strings" "time" ) +// a copy of context.Context for Go 1.7 and earlier +type mysqlContext interface { + Done() <-chan struct{} + Err() error + + // defined in context.Context, but not used in this driver: + // Deadline() (deadline time.Time, ok bool) + // Value(key interface{}) interface{} +} + type mysqlConn struct { buf buffer netConn net.Conn @@ -29,7 +40,14 @@ type mysqlConn struct { status statusFlag sequence uint8 parseTime bool - strict bool + + // for context support (Go 1.8+) + watching bool + watcher chan<- mysqlContext + closech chan struct{} + finished chan<- struct{} + canceled atomicError // set non-nil if conn is canceled + closed atomicBool // set when conn is closed, before closech is closed } // Handles parameters set in DSN after the connection is established @@ -62,22 +80,41 @@ func (mc *mysqlConn) handleParams() (err error) { return } +func (mc *mysqlConn) markBadConn(err error) error { + if mc == nil { + return err + } + if err != errBadConnNoWrite { + return err + } + return driver.ErrBadConn +} + func (mc *mysqlConn) Begin() (driver.Tx, error) { - if mc.netConn == nil { + return mc.begin(false) +} + +func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } - err := mc.exec("START TRANSACTION") + var q string + if readOnly { + q = "START TRANSACTION READ ONLY" + } else { + q = "START TRANSACTION" + } + err := mc.exec(q) if err == nil { return &mysqlTx{mc}, err } - - return nil, err + return nil, mc.markBadConn(err) } func (mc *mysqlConn) Close() (err error) { // Makes Close idempotent - if mc.netConn != nil { + if !mc.closed.IsSet() { err = mc.writeCommandPacket(comQuit) } @@ -91,26 +128,39 @@ func (mc *mysqlConn) Close() (err error) { // is called before auth or on auth failure because MySQL will have already // closed the network connection. func (mc *mysqlConn) cleanup() { + if !mc.closed.TrySet(true) { + return + } + // Makes cleanup idempotent - if mc.netConn != nil { - if err := mc.netConn.Close(); err != nil { - errLog.Print(err) + close(mc.closech) + if mc.netConn == nil { + return + } + if err := mc.netConn.Close(); err != nil { + errLog.Print(err) + } +} + +func (mc *mysqlConn) error() error { + if mc.closed.IsSet() { + if err := mc.canceled.Value(); err != nil { + return err } - mc.netConn = nil + return ErrInvalidConn } - mc.cfg = nil - mc.buf.nc = nil + return nil } func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) { - if mc.netConn == nil { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := mc.writeCommandPacketStr(comStmtPrepare, query) if err != nil { - return nil, err + return nil, mc.markBadConn(err) } stmt := &mysqlStmt{ @@ -144,7 +194,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin if buf == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return "", driver.ErrBadConn + return "", ErrInvalidConn } buf = buf[:0] argPos := 0 @@ -257,7 +307,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin } func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) { - if mc.netConn == nil { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } @@ -271,7 +321,6 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err return nil, err } query = prepared - args = nil } mc.affectedRows = 0 mc.insertId = 0 @@ -283,32 +332,43 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err insertId: int64(mc.insertId), }, err } - return nil, err + return nil, mc.markBadConn(err) } // Internal function to execute commands func (mc *mysqlConn) exec(query string) error { // Send command - err := mc.writeCommandPacketStr(comQuery, query) - if err != nil { - return err + if err := mc.writeCommandPacketStr(comQuery, query); err != nil { + return mc.markBadConn(err) } // Read Result resLen, err := mc.readResultSetHeaderPacket() - if err == nil && resLen > 0 { - if err = mc.readUntilEOF(); err != nil { + if err != nil { + return err + } + + if resLen > 0 { + // columns + if err := mc.readUntilEOF(); err != nil { return err } - err = mc.readUntilEOF() + // rows + if err := mc.readUntilEOF(); err != nil { + return err + } } - return err + return mc.discardResults() } func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) { - if mc.netConn == nil { + return mc.query(query, args) +} + +func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) { + if mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } @@ -322,7 +382,6 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro return nil, err } query = prepared - args = nil } // Send command err := mc.writeCommandPacketStr(comQuery, query) @@ -335,15 +394,22 @@ func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, erro rows.mc = mc if resLen == 0 { - // no columns, no more data - return emptyRows{}, nil + rows.rs.done = true + + switch err := rows.NextResultSet(); err { + case nil, io.EOF: + return rows, nil + default: + return nil, err + } } + // Columns - rows.columns, err = mc.readColumns(resLen) + rows.rs.columns, err = mc.readColumns(resLen) return rows, err } } - return nil, err + return nil, mc.markBadConn(err) } // Gets the value of the given MySQL System Variable @@ -359,7 +425,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { if err == nil { rows := new(textRows) rows.mc = mc - rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}} + rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}} if resLen > 0 { // Columns @@ -375,3 +441,21 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) { } return nil, err } + +// finish is called when the query has canceled. +func (mc *mysqlConn) cancel(err error) { + mc.canceled.Set(err) + mc.cleanup() +} + +// finish is called when the query has succeeded. +func (mc *mysqlConn) finish() { + if !mc.watching || mc.finished == nil { + return + } + select { + case mc.finished <- struct{}{}: + mc.watching = false + case <-mc.closech: + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/connection_go18.go b/vendor/github.com/go-sql-driver/mysql/connection_go18.go new file mode 100644 index 000000000..1306b70b7 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection_go18.go @@ -0,0 +1,202 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "database/sql/driver" +) + +// Ping implements driver.Pinger interface +func (mc *mysqlConn) Ping(ctx context.Context) error { + if mc.closed.IsSet() { + errLog.Print(ErrInvalidConn) + return driver.ErrBadConn + } + + if err := mc.watchCancel(ctx); err != nil { + return err + } + defer mc.finish() + + if err := mc.writeCommandPacket(comPing); err != nil { + return err + } + if _, err := mc.readResultOK(); err != nil { + return err + } + + return nil +} + +// BeginTx implements driver.ConnBeginTx interface +func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault { + level, err := mapIsolationLevel(opts.Isolation) + if err != nil { + return nil, err + } + err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level) + if err != nil { + return nil, err + } + } + + return mc.begin(opts.ReadOnly) +} + +func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := mc.query(query, dargs) + if err != nil { + mc.finish() + return nil, err + } + rows.finish = mc.finish + return rows, err +} + +func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + defer mc.finish() + + return mc.Exec(query, dargs) +} + +func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { + if err := mc.watchCancel(ctx); err != nil { + return nil, err + } + + stmt, err := mc.Prepare(query) + mc.finish() + if err != nil { + return nil, err + } + + select { + default: + case <-ctx.Done(): + stmt.Close() + return nil, ctx.Err() + } + return stmt, nil +} + +func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + + rows, err := stmt.query(dargs) + if err != nil { + stmt.mc.finish() + return nil, err + } + rows.finish = stmt.mc.finish + return rows, err +} + +func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { + dargs, err := namedValueToValue(args) + if err != nil { + return nil, err + } + + if err := stmt.mc.watchCancel(ctx); err != nil { + return nil, err + } + defer stmt.mc.finish() + + return stmt.Exec(dargs) +} + +func (mc *mysqlConn) watchCancel(ctx context.Context) error { + if mc.watching { + // Reach here if canceled, + // so the connection is already invalid + mc.cleanup() + return nil + } + if ctx.Done() == nil { + return nil + } + + mc.watching = true + select { + default: + case <-ctx.Done(): + return ctx.Err() + } + if mc.watcher == nil { + return nil + } + + mc.watcher <- ctx + + return nil +} + +func (mc *mysqlConn) startWatcher() { + watcher := make(chan mysqlContext, 1) + mc.watcher = watcher + finished := make(chan struct{}) + mc.finished = finished + go func() { + for { + var ctx mysqlContext + select { + case ctx = <-watcher: + case <-mc.closech: + return + } + + select { + case <-ctx.Done(): + mc.cancel(ctx.Err()) + case <-finished: + case <-mc.closech: + return + } + } + }() +} + +func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) { + nv.Value, err = converter{}.ConvertValue(nv.Value) + return +} diff --git a/vendor/github.com/go-sql-driver/mysql/connection_go18_test.go b/vendor/github.com/go-sql-driver/mysql/connection_go18_test.go new file mode 100644 index 000000000..2719ab3b7 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/connection_go18_test.go @@ -0,0 +1,30 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "database/sql/driver" + "testing" +) + +func TestCheckNamedValue(t *testing.T) { + value := driver.NamedValue{Value: ^uint64(0)} + x := &mysqlConn{} + err := x.CheckNamedValue(&value) + + if err != nil { + t.Fatal("uint64 high-bit not convertible", err) + } + + if value.Value != "18446744073709551615" { + t.Fatalf("uint64 high-bit not converted, got %#v %T", value.Value, value.Value) + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/const.go b/vendor/github.com/go-sql-driver/mysql/const.go index 88cfff3fd..4a19ca523 100644 --- a/vendor/github.com/go-sql-driver/mysql/const.go +++ b/vendor/github.com/go-sql-driver/mysql/const.go @@ -9,7 +9,8 @@ package mysql const ( - minProtocolVersion byte = 10 + defaultMaxAllowedPacket = 4 << 20 // 4 MiB + minProtocolVersion = 10 maxPacketSize = 1<<24 - 1 timeFormat = "2006-01-02 15:04:05.999999" ) @@ -87,8 +88,10 @@ const ( ) // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType +type fieldType byte + const ( - fieldTypeDecimal byte = iota + fieldTypeDecimal fieldType = iota fieldTypeTiny fieldTypeShort fieldTypeLong @@ -107,7 +110,7 @@ const ( fieldTypeBit ) const ( - fieldTypeJSON byte = iota + 0xf5 + fieldTypeJSON fieldType = iota + 0xf5 fieldTypeNewDecimal fieldTypeEnum fieldTypeSet diff --git a/vendor/github.com/go-sql-driver/mysql/driver.go b/vendor/github.com/go-sql-driver/mysql/driver.go index 0022d1f1e..d42ce7a3d 100644 --- a/vendor/github.com/go-sql-driver/mysql/driver.go +++ b/vendor/github.com/go-sql-driver/mysql/driver.go @@ -4,7 +4,7 @@ // License, v. 2.0. If a copy of the MPL was not distributed with this file, // You can obtain one at http://mozilla.org/MPL/2.0/. -// Package mysql provides a MySQL driver for Go's database/sql package +// Package mysql provides a MySQL driver for Go's database/sql package. // // The driver should be used via the database/sql package: // @@ -22,6 +22,11 @@ import ( "net" ) +// watcher interface is used for context support (From Go 1.8) +type watcher interface { + startWatcher() +} + // MySQLDriver is exported to make the driver directly accessible. // In general the driver is used via the database/sql package. type MySQLDriver struct{} @@ -52,13 +57,13 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { mc := &mysqlConn{ maxAllowedPacket: maxPacketSize, maxWriteSize: maxPacketSize - 1, + closech: make(chan struct{}), } mc.cfg, err = ParseDSN(dsn) if err != nil { return nil, err } mc.parseTime = mc.cfg.ParseTime - mc.strict = mc.cfg.Strict // Connect to Server if dial, ok := dials[mc.cfg.Net]; ok { @@ -81,6 +86,11 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) { } } + // Call startWatcher for context support (From Go 1.8) + if s, ok := interface{}(mc).(watcher); ok { + s.startWatcher() + } + mc.buf = newBuffer(mc.netConn) // Set I/O timeouts diff --git a/vendor/github.com/go-sql-driver/mysql/driver_go18_test.go b/vendor/github.com/go-sql-driver/mysql/driver_go18_test.go new file mode 100644 index 000000000..e461455dd --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/driver_go18_test.go @@ -0,0 +1,798 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "context" + "database/sql" + "database/sql/driver" + "fmt" + "math" + "reflect" + "testing" + "time" +) + +// static interface implementation checks of mysqlConn +var ( + _ driver.ConnBeginTx = &mysqlConn{} + _ driver.ConnPrepareContext = &mysqlConn{} + _ driver.ExecerContext = &mysqlConn{} + _ driver.Pinger = &mysqlConn{} + _ driver.QueryerContext = &mysqlConn{} +) + +// static interface implementation checks of mysqlStmt +var ( + _ driver.StmtExecContext = &mysqlStmt{} + _ driver.StmtQueryContext = &mysqlStmt{} +) + +// Ensure that all the driver interfaces are implemented +var ( + // _ driver.RowsColumnTypeLength = &binaryRows{} + // _ driver.RowsColumnTypeLength = &textRows{} + _ driver.RowsColumnTypeDatabaseTypeName = &binaryRows{} + _ driver.RowsColumnTypeDatabaseTypeName = &textRows{} + _ driver.RowsColumnTypeNullable = &binaryRows{} + _ driver.RowsColumnTypeNullable = &textRows{} + _ driver.RowsColumnTypePrecisionScale = &binaryRows{} + _ driver.RowsColumnTypePrecisionScale = &textRows{} + _ driver.RowsColumnTypeScanType = &binaryRows{} + _ driver.RowsColumnTypeScanType = &textRows{} + _ driver.RowsNextResultSet = &binaryRows{} + _ driver.RowsNextResultSet = &textRows{} +) + +func TestMultiResultSet(t *testing.T) { + type result struct { + values [][]int + columns []string + } + + // checkRows is a helper test function to validate rows containing 3 result + // sets with specific values and columns. The basic query would look like this: + // + // SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; + // SELECT 0 UNION SELECT 1; + // SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; + // + // to distinguish test cases the first string argument is put in front of + // every error or fatal message. + checkRows := func(desc string, rows *sql.Rows, dbt *DBTest) { + expected := []result{ + { + values: [][]int{{1, 2}, {3, 4}}, + columns: []string{"col1", "col2"}, + }, + { + values: [][]int{{1, 2, 3}, {4, 5, 6}}, + columns: []string{"col1", "col2", "col3"}, + }, + } + + var res1 result + for rows.Next() { + var res [2]int + if err := rows.Scan(&res[0], &res[1]); err != nil { + dbt.Fatal(err) + } + res1.values = append(res1.values, res[:]) + } + + cols, err := rows.Columns() + if err != nil { + dbt.Fatal(desc, err) + } + res1.columns = cols + + if !reflect.DeepEqual(expected[0], res1) { + dbt.Error(desc, "want =", expected[0], "got =", res1) + } + + if !rows.NextResultSet() { + dbt.Fatal(desc, "expected next result set") + } + + // ignoring one result set + + if !rows.NextResultSet() { + dbt.Fatal(desc, "expected next result set") + } + + var res2 result + cols, err = rows.Columns() + if err != nil { + dbt.Fatal(desc, err) + } + res2.columns = cols + + for rows.Next() { + var res [3]int + if err := rows.Scan(&res[0], &res[1], &res[2]); err != nil { + dbt.Fatal(desc, err) + } + res2.values = append(res2.values, res[:]) + } + + if !reflect.DeepEqual(expected[1], res2) { + dbt.Error(desc, "want =", expected[1], "got =", res2) + } + + if rows.NextResultSet() { + dbt.Error(desc, "unexpected next result set") + } + + if err := rows.Err(); err != nil { + dbt.Error(desc, err) + } + } + + runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { + rows := dbt.mustQuery(`DO 1; + SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; + DO 1; + SELECT 0 UNION SELECT 1; + SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6;`) + defer rows.Close() + checkRows("query: ", rows, dbt) + }) + + runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { + queries := []string{ + ` + DROP PROCEDURE IF EXISTS test_mrss; + CREATE PROCEDURE test_mrss() + BEGIN + DO 1; + SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; + DO 1; + SELECT 0 UNION SELECT 1; + SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; + END + `, + ` + DROP PROCEDURE IF EXISTS test_mrss; + CREATE PROCEDURE test_mrss() + BEGIN + SELECT 1 AS col1, 2 AS col2 UNION SELECT 3, 4; + SELECT 0 UNION SELECT 1; + SELECT 1 AS col1, 2 AS col2, 3 AS col3 UNION SELECT 4, 5, 6; + END + `, + } + + defer dbt.mustExec("DROP PROCEDURE IF EXISTS test_mrss") + + for i, query := range queries { + dbt.mustExec(query) + + stmt, err := dbt.db.Prepare("CALL test_mrss()") + if err != nil { + dbt.Fatalf("%v (i=%d)", err, i) + } + defer stmt.Close() + + for j := 0; j < 2; j++ { + rows, err := stmt.Query() + if err != nil { + dbt.Fatalf("%v (i=%d) (j=%d)", err, i, j) + } + checkRows(fmt.Sprintf("prepared stmt query (i=%d) (j=%d): ", i, j), rows, dbt) + } + } + }) +} + +func TestMultiResultSetNoSelect(t *testing.T) { + runTestsWithMultiStatement(t, dsn, func(dbt *DBTest) { + rows := dbt.mustQuery("DO 1; DO 2;") + defer rows.Close() + + if rows.Next() { + dbt.Error("unexpected row") + } + + if rows.NextResultSet() { + dbt.Error("unexpected next result set") + } + + if err := rows.Err(); err != nil { + dbt.Error("expected nil; got ", err) + } + }) +} + +// tests if rows are set in a proper state if some results were ignored before +// calling rows.NextResultSet. +func TestSkipResults(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + rows := dbt.mustQuery("SELECT 1, 2") + defer rows.Close() + + if !rows.Next() { + dbt.Error("expected row") + } + + if rows.NextResultSet() { + dbt.Error("unexpected next result set") + } + + if err := rows.Err(); err != nil { + dbt.Error("expected nil; got ", err) + } + }) +} + +func TestPingContext(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + if err := dbt.db.PingContext(ctx); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + }) +} + +func TestContextCancelExec(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + + // Delay execution for just a bit until db.ExecContext has begun. + defer time.AfterFunc(100*time.Millisecond, cancel).Stop() + + // This query will be canceled. + startTime := time.Now() + if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + if d := time.Since(startTime); d > 500*time.Millisecond { + dbt.Errorf("too long execution time: %s", d) + } + + // Wait for the INSERT query has done. + time.Sleep(time.Second) + + // Check how many times the query is executed. + var v int + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { // TODO: need to kill the query, and v should be 0. + dbt.Errorf("expected val to be 1, got %d", v) + } + + // Context is already canceled, so error should come before execution. + if _, err := dbt.db.ExecContext(ctx, "INSERT INTO test VALUES (1)"); err == nil { + dbt.Error("expected error") + } else if err.Error() != "context canceled" { + dbt.Fatalf("unexpected error: %s", err) + } + + // The second insert query will fail, so the table has no changes. + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { + dbt.Errorf("expected val to be 1, got %d", v) + } + }) +} + +func TestContextCancelQuery(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + + // Delay execution for just a bit until db.ExecContext has begun. + defer time.AfterFunc(100*time.Millisecond, cancel).Stop() + + // This query will be canceled. + startTime := time.Now() + if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + if d := time.Since(startTime); d > 500*time.Millisecond { + dbt.Errorf("too long execution time: %s", d) + } + + // Wait for the INSERT query has done. + time.Sleep(time.Second) + + // Check how many times the query is executed. + var v int + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { // TODO: need to kill the query, and v should be 0. + dbt.Errorf("expected val to be 1, got %d", v) + } + + // Context is already canceled, so error should come before execution. + if _, err := dbt.db.QueryContext(ctx, "INSERT INTO test VALUES (1)"); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + + // The second insert query will fail, so the table has no changes. + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { + dbt.Errorf("expected val to be 1, got %d", v) + } + }) +} + +func TestContextCancelQueryRow(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + dbt.mustExec("INSERT INTO test VALUES (1), (2), (3)") + ctx, cancel := context.WithCancel(context.Background()) + + rows, err := dbt.db.QueryContext(ctx, "SELECT v FROM test") + if err != nil { + dbt.Fatalf("%s", err.Error()) + } + + // the first row will be succeed. + var v int + if !rows.Next() { + dbt.Fatalf("unexpected end") + } + if err := rows.Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + + cancel() + // make sure the driver recieve cancel request. + time.Sleep(100 * time.Millisecond) + + if rows.Next() { + dbt.Errorf("expected end, but not") + } + if err := rows.Err(); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + }) +} + +func TestContextCancelPrepare(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + ctx, cancel := context.WithCancel(context.Background()) + cancel() + if _, err := dbt.db.PrepareContext(ctx, "SELECT 1"); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + }) +} + +func TestContextCancelStmtExec(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") + if err != nil { + dbt.Fatalf("unexpected error: %v", err) + } + + // Delay execution for just a bit until db.ExecContext has begun. + defer time.AfterFunc(100*time.Millisecond, cancel).Stop() + + // This query will be canceled. + startTime := time.Now() + if _, err := stmt.ExecContext(ctx); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + if d := time.Since(startTime); d > 500*time.Millisecond { + dbt.Errorf("too long execution time: %s", d) + } + + // Wait for the INSERT query has done. + time.Sleep(time.Second) + + // Check how many times the query is executed. + var v int + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { // TODO: need to kill the query, and v should be 0. + dbt.Errorf("expected val to be 1, got %d", v) + } + }) +} + +func TestContextCancelStmtQuery(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + stmt, err := dbt.db.PrepareContext(ctx, "INSERT INTO test VALUES (SLEEP(1))") + if err != nil { + dbt.Fatalf("unexpected error: %v", err) + } + + // Delay execution for just a bit until db.ExecContext has begun. + defer time.AfterFunc(100*time.Millisecond, cancel).Stop() + + // This query will be canceled. + startTime := time.Now() + if _, err := stmt.QueryContext(ctx); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + if d := time.Since(startTime); d > 500*time.Millisecond { + dbt.Errorf("too long execution time: %s", d) + } + + // Wait for the INSERT query has done. + time.Sleep(time.Second) + + // Check how many times the query is executed. + var v int + if err := dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&v); err != nil { + dbt.Fatalf("%s", err.Error()) + } + if v != 1 { // TODO: need to kill the query, and v should be 0. + dbt.Errorf("expected val to be 1, got %d", v) + } + }) +} + +func TestContextCancelBegin(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + tx, err := dbt.db.BeginTx(ctx, nil) + if err != nil { + dbt.Fatal(err) + } + + // Delay execution for just a bit until db.ExecContext has begun. + defer time.AfterFunc(100*time.Millisecond, cancel).Stop() + + // This query will be canceled. + startTime := time.Now() + if _, err := tx.ExecContext(ctx, "INSERT INTO test VALUES (SLEEP(1))"); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + if d := time.Since(startTime); d > 500*time.Millisecond { + dbt.Errorf("too long execution time: %s", d) + } + + // Transaction is canceled, so expect an error. + switch err := tx.Commit(); err { + case sql.ErrTxDone: + // because the transaction has already been rollbacked. + // the database/sql package watches ctx + // and rollbacks when ctx is canceled. + case context.Canceled: + // the database/sql package rollbacks on another goroutine, + // so the transaction may not be rollbacked depending on goroutine scheduling. + default: + dbt.Errorf("expected sql.ErrTxDone or context.Canceled, got %v", err) + } + + // Context is canceled, so cannot begin a transaction. + if _, err := dbt.db.BeginTx(ctx, nil); err != context.Canceled { + dbt.Errorf("expected context.Canceled, got %v", err) + } + }) +} + +func TestContextBeginIsolationLevel(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + tx1, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ + Isolation: sql.LevelRepeatableRead, + }) + if err != nil { + dbt.Fatal(err) + } + + tx2, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ + Isolation: sql.LevelReadCommitted, + }) + if err != nil { + dbt.Fatal(err) + } + + _, err = tx1.ExecContext(ctx, "INSERT INTO test VALUES (1)") + if err != nil { + dbt.Fatal(err) + } + + var v int + row := tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") + if err := row.Scan(&v); err != nil { + dbt.Fatal(err) + } + // Because writer transaction wasn't commited yet, it should be available + if v != 0 { + dbt.Errorf("expected val to be 0, got %d", v) + } + + err = tx1.Commit() + if err != nil { + dbt.Fatal(err) + } + + row = tx2.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") + if err := row.Scan(&v); err != nil { + dbt.Fatal(err) + } + // Data written by writer transaction is already commited, it should be selectable + if v != 1 { + dbt.Errorf("expected val to be 1, got %d", v) + } + tx2.Commit() + }) +} + +func TestContextBeginReadOnly(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (v INTEGER)") + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + tx, err := dbt.db.BeginTx(ctx, &sql.TxOptions{ + ReadOnly: true, + }) + if _, ok := err.(*MySQLError); ok { + dbt.Skip("It seems that your MySQL does not support READ ONLY transactions") + return + } else if err != nil { + dbt.Fatal(err) + } + + // INSERT queries fail in a READ ONLY transaction. + _, err = tx.ExecContext(ctx, "INSERT INTO test VALUES (1)") + if _, ok := err.(*MySQLError); !ok { + dbt.Errorf("expected MySQLError, got %v", err) + } + + // SELECT queries can be executed. + var v int + row := tx.QueryRowContext(ctx, "SELECT COUNT(*) FROM test") + if err := row.Scan(&v); err != nil { + dbt.Fatal(err) + } + if v != 0 { + dbt.Errorf("expected val to be 0, got %d", v) + } + + if err := tx.Commit(); err != nil { + dbt.Fatal(err) + } + }) +} + +func TestRowsColumnTypes(t *testing.T) { + niNULL := sql.NullInt64{Int64: 0, Valid: false} + ni0 := sql.NullInt64{Int64: 0, Valid: true} + ni1 := sql.NullInt64{Int64: 1, Valid: true} + ni42 := sql.NullInt64{Int64: 42, Valid: true} + nfNULL := sql.NullFloat64{Float64: 0.0, Valid: false} + nf0 := sql.NullFloat64{Float64: 0.0, Valid: true} + nf1337 := sql.NullFloat64{Float64: 13.37, Valid: true} + nt0 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 0, time.UTC), Valid: true} + nt1 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 100000000, time.UTC), Valid: true} + nt2 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 110000000, time.UTC), Valid: true} + nt6 := NullTime{Time: time.Date(2006, 01, 02, 15, 04, 05, 111111000, time.UTC), Valid: true} + nd1 := NullTime{Time: time.Date(2006, 01, 02, 0, 0, 0, 0, time.UTC), Valid: true} + nd2 := NullTime{Time: time.Date(2006, 03, 04, 0, 0, 0, 0, time.UTC), Valid: true} + ndNULL := NullTime{Time: time.Time{}, Valid: false} + rbNULL := sql.RawBytes(nil) + rb0 := sql.RawBytes("0") + rb42 := sql.RawBytes("42") + rbTest := sql.RawBytes("Test") + rb0pad4 := sql.RawBytes("0\x00\x00\x00") // BINARY right-pads values with 0x00 + rbx0 := sql.RawBytes("\x00") + rbx42 := sql.RawBytes("\x42") + + var columns = []struct { + name string + fieldType string // type used when creating table schema + databaseTypeName string // actual type used by MySQL + scanType reflect.Type + nullable bool + precision int64 // 0 if not ok + scale int64 + valuesIn [3]string + valuesOut [3]interface{} + }{ + {"bit8null", "BIT(8)", "BIT", scanTypeRawBytes, true, 0, 0, [3]string{"0x0", "NULL", "0x42"}, [3]interface{}{rbx0, rbNULL, rbx42}}, + {"boolnull", "BOOL", "TINYINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "true", "0"}, [3]interface{}{niNULL, ni1, ni0}}, + {"bool", "BOOL NOT NULL", "TINYINT", scanTypeInt8, false, 0, 0, [3]string{"1", "0", "FALSE"}, [3]interface{}{int8(1), int8(0), int8(0)}}, + {"intnull", "INTEGER", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, + {"smallint", "SMALLINT NOT NULL", "SMALLINT", scanTypeInt16, false, 0, 0, [3]string{"0", "-32768", "32767"}, [3]interface{}{int16(0), int16(-32768), int16(32767)}}, + {"smallintnull", "SMALLINT", "SMALLINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, + {"int3null", "INT(3)", "INT", scanTypeNullInt, true, 0, 0, [3]string{"0", "NULL", "42"}, [3]interface{}{ni0, niNULL, ni42}}, + {"int7", "INT(7) NOT NULL", "INT", scanTypeInt32, false, 0, 0, [3]string{"0", "-1337", "42"}, [3]interface{}{int32(0), int32(-1337), int32(42)}}, + {"mediumintnull", "MEDIUMINT", "MEDIUMINT", scanTypeNullInt, true, 0, 0, [3]string{"0", "42", "NULL"}, [3]interface{}{ni0, ni42, niNULL}}, + {"bigint", "BIGINT NOT NULL", "BIGINT", scanTypeInt64, false, 0, 0, [3]string{"0", "65535", "-42"}, [3]interface{}{int64(0), int64(65535), int64(-42)}}, + {"bigintnull", "BIGINT", "BIGINT", scanTypeNullInt, true, 0, 0, [3]string{"NULL", "1", "42"}, [3]interface{}{niNULL, ni1, ni42}}, + {"tinyuint", "TINYINT UNSIGNED NOT NULL", "TINYINT", scanTypeUint8, false, 0, 0, [3]string{"0", "255", "42"}, [3]interface{}{uint8(0), uint8(255), uint8(42)}}, + {"smalluint", "SMALLINT UNSIGNED NOT NULL", "SMALLINT", scanTypeUint16, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint16(0), uint16(65535), uint16(42)}}, + {"biguint", "BIGINT UNSIGNED NOT NULL", "BIGINT", scanTypeUint64, false, 0, 0, [3]string{"0", "65535", "42"}, [3]interface{}{uint64(0), uint64(65535), uint64(42)}}, + {"uint13", "INT(13) UNSIGNED NOT NULL", "INT", scanTypeUint32, false, 0, 0, [3]string{"0", "1337", "42"}, [3]interface{}{uint32(0), uint32(1337), uint32(42)}}, + {"float", "FLOAT NOT NULL", "FLOAT", scanTypeFloat32, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float32(0), float32(42), float32(13.37)}}, + {"floatnull", "FLOAT", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, + {"float74null", "FLOAT(7,4)", "FLOAT", scanTypeNullFloat, true, math.MaxInt64, 4, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, + {"double", "DOUBLE NOT NULL", "DOUBLE", scanTypeFloat64, false, math.MaxInt64, math.MaxInt64, [3]string{"0", "42", "13.37"}, [3]interface{}{float64(0), float64(42), float64(13.37)}}, + {"doublenull", "DOUBLE", "DOUBLE", scanTypeNullFloat, true, math.MaxInt64, math.MaxInt64, [3]string{"0", "NULL", "13.37"}, [3]interface{}{nf0, nfNULL, nf1337}}, + {"decimal1", "DECIMAL(10,6) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 10, 6, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), sql.RawBytes("13.370000"), sql.RawBytes("1234.123456")}}, + {"decimal1null", "DECIMAL(10,6)", "DECIMAL", scanTypeRawBytes, true, 10, 6, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.000000"), rbNULL, sql.RawBytes("1234.123456")}}, + {"decimal2", "DECIMAL(8,4) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 8, 4, [3]string{"0", "13.37", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), sql.RawBytes("13.3700"), sql.RawBytes("1234.1235")}}, + {"decimal2null", "DECIMAL(8,4)", "DECIMAL", scanTypeRawBytes, true, 8, 4, [3]string{"0", "NULL", "1234.123456"}, [3]interface{}{sql.RawBytes("0.0000"), rbNULL, sql.RawBytes("1234.1235")}}, + {"decimal3", "DECIMAL(5,0) NOT NULL", "DECIMAL", scanTypeRawBytes, false, 5, 0, [3]string{"0", "13.37", "-12345.123456"}, [3]interface{}{rb0, sql.RawBytes("13"), sql.RawBytes("-12345")}}, + {"decimal3null", "DECIMAL(5,0)", "DECIMAL", scanTypeRawBytes, true, 5, 0, [3]string{"0", "NULL", "-12345.123456"}, [3]interface{}{rb0, rbNULL, sql.RawBytes("-12345")}}, + {"char25null", "CHAR(25)", "CHAR", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"varchar42", "VARCHAR(42) NOT NULL", "VARCHAR", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"binary4null", "BINARY(4)", "BINARY", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0pad4, rbNULL, rbTest}}, + {"varbinary42", "VARBINARY(42) NOT NULL", "VARBINARY", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"tinyblobnull", "TINYBLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"tinytextnull", "TINYTEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"blobnull", "BLOB", "BLOB", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"textnull", "TEXT", "TEXT", scanTypeRawBytes, true, 0, 0, [3]string{"0", "NULL", "'Test'"}, [3]interface{}{rb0, rbNULL, rbTest}}, + {"mediumblob", "MEDIUMBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"mediumtext", "MEDIUMTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"longblob", "LONGBLOB NOT NULL", "BLOB", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"longtext", "LONGTEXT NOT NULL", "TEXT", scanTypeRawBytes, false, 0, 0, [3]string{"0", "'Test'", "42"}, [3]interface{}{rb0, rbTest, rb42}}, + {"datetime", "DATETIME", "DATETIME", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt0, nt0}}, + {"datetime2", "DATETIME(2)", "DATETIME", scanTypeNullTime, true, 2, 2, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt2}}, + {"datetime6", "DATETIME(6)", "DATETIME", scanTypeNullTime, true, 6, 6, [3]string{"'2006-01-02 15:04:05'", "'2006-01-02 15:04:05.1'", "'2006-01-02 15:04:05.111111'"}, [3]interface{}{nt0, nt1, nt6}}, + {"date", "DATE", "DATE", scanTypeNullTime, true, 0, 0, [3]string{"'2006-01-02'", "NULL", "'2006-03-04'"}, [3]interface{}{nd1, ndNULL, nd2}}, + {"year", "YEAR NOT NULL", "YEAR", scanTypeUint16, false, 0, 0, [3]string{"2006", "2000", "1994"}, [3]interface{}{uint16(2006), uint16(2000), uint16(1994)}}, + } + + schema := "" + values1 := "" + values2 := "" + values3 := "" + for _, column := range columns { + schema += fmt.Sprintf("`%s` %s, ", column.name, column.fieldType) + values1 += column.valuesIn[0] + ", " + values2 += column.valuesIn[1] + ", " + values3 += column.valuesIn[2] + ", " + } + schema = schema[:len(schema)-2] + values1 = values1[:len(values1)-2] + values2 = values2[:len(values2)-2] + values3 = values3[:len(values3)-2] + + dsns := []string{ + dsn + "&parseTime=true", + dsn + "&parseTime=false", + } + for _, testdsn := range dsns { + runTests(t, testdsn, func(dbt *DBTest) { + dbt.mustExec("CREATE TABLE test (" + schema + ")") + dbt.mustExec("INSERT INTO test VALUES (" + values1 + "), (" + values2 + "), (" + values3 + ")") + + rows, err := dbt.db.Query("SELECT * FROM test") + if err != nil { + t.Fatalf("Query: %v", err) + } + + tt, err := rows.ColumnTypes() + if err != nil { + t.Fatalf("ColumnTypes: %v", err) + } + + if len(tt) != len(columns) { + t.Fatalf("unexpected number of columns: expected %d, got %d", len(columns), len(tt)) + } + + types := make([]reflect.Type, len(tt)) + for i, tp := range tt { + column := columns[i] + + // Name + name := tp.Name() + if name != column.name { + t.Errorf("column name mismatch %s != %s", name, column.name) + continue + } + + // DatabaseTypeName + databaseTypeName := tp.DatabaseTypeName() + if databaseTypeName != column.databaseTypeName { + t.Errorf("databasetypename name mismatch for column %q: %s != %s", name, databaseTypeName, column.databaseTypeName) + continue + } + + // ScanType + scanType := tp.ScanType() + if scanType != column.scanType { + if scanType == nil { + t.Errorf("scantype is null for column %q", name) + } else { + t.Errorf("scantype mismatch for column %q: %s != %s", name, scanType.Name(), column.scanType.Name()) + } + continue + } + types[i] = scanType + + // Nullable + nullable, ok := tp.Nullable() + if !ok { + t.Errorf("nullable not ok %q", name) + continue + } + if nullable != column.nullable { + t.Errorf("nullable mismatch for column %q: %t != %t", name, nullable, column.nullable) + } + + // Length + // length, ok := tp.Length() + // if length != column.length { + // if !ok { + // t.Errorf("length not ok for column %q", name) + // } else { + // t.Errorf("length mismatch for column %q: %d != %d", name, length, column.length) + // } + // continue + // } + + // Precision and Scale + precision, scale, ok := tp.DecimalSize() + if precision != column.precision { + if !ok { + t.Errorf("precision not ok for column %q", name) + } else { + t.Errorf("precision mismatch for column %q: %d != %d", name, precision, column.precision) + } + continue + } + if scale != column.scale { + if !ok { + t.Errorf("scale not ok for column %q", name) + } else { + t.Errorf("scale mismatch for column %q: %d != %d", name, scale, column.scale) + } + continue + } + } + + values := make([]interface{}, len(tt)) + for i := range values { + values[i] = reflect.New(types[i]).Interface() + } + i := 0 + for rows.Next() { + err = rows.Scan(values...) + if err != nil { + t.Fatalf("failed to scan values in %v", err) + } + for j := range values { + value := reflect.ValueOf(values[j]).Elem().Interface() + if !reflect.DeepEqual(value, columns[j].valuesOut[i]) { + if columns[j].scanType == scanTypeRawBytes { + t.Errorf("row %d, column %d: %v != %v", i, j, string(value.(sql.RawBytes)), string(columns[j].valuesOut[i].(sql.RawBytes))) + } else { + t.Errorf("row %d, column %d: %v != %v", i, j, value, columns[j].valuesOut[i]) + } + } + } + i++ + } + if i != 3 { + t.Errorf("expected 3 rows, got %d", i) + } + + if err := rows.Close(); err != nil { + t.Errorf("error closing rows: %s", err) + } + }) + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/driver_test.go b/vendor/github.com/go-sql-driver/mysql/driver_test.go index 78e68f5d0..7877aa979 100644 --- a/vendor/github.com/go-sql-driver/mysql/driver_test.go +++ b/vendor/github.com/go-sql-driver/mysql/driver_test.go @@ -27,6 +27,12 @@ import ( "time" ) +// Ensure that all the driver interfaces are implemented +var ( + _ driver.Rows = &binaryRows{} + _ driver.Rows = &textRows{} +) + var ( user string pass string @@ -63,7 +69,7 @@ func init() { addr = env("MYSQL_TEST_ADDR", "localhost:3306") dbname = env("MYSQL_TEST_DBNAME", "gotest") netAddr = fmt.Sprintf("%s(%s)", prot, addr) - dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s&strict=true", user, pass, netAddr, dbname) + dsn = fmt.Sprintf("%s:%s@%s/%s?timeout=30s", user, pass, netAddr, dbname) c, err := net.Dial(prot, addr) if err == nil { available = true @@ -171,6 +177,17 @@ func (dbt *DBTest) mustQuery(query string, args ...interface{}) (rows *sql.Rows) return rows } +func maybeSkip(t *testing.T, err error, skipErrno uint16) { + mySQLErr, ok := err.(*MySQLError) + if !ok { + return + } + + if mySQLErr.Number == skipErrno { + t.Skipf("skipping test for error: %v", err) + } +} + func TestEmptyQuery(t *testing.T) { runTests(t, dsn, func(dbt *DBTest) { // just a comment, no query @@ -482,6 +499,85 @@ func TestString(t *testing.T) { }) } +type testValuer struct { + value string +} + +func (tv testValuer) Value() (driver.Value, error) { + return tv.value, nil +} + +func TestValuer(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + in := testValuer{"a_value"} + var out string + var rows *sql.Rows + + dbt.mustExec("CREATE TABLE test (value VARCHAR(255)) CHARACTER SET utf8") + dbt.mustExec("INSERT INTO test VALUES (?)", in) + rows = dbt.mustQuery("SELECT value FROM test") + if rows.Next() { + rows.Scan(&out) + if in.value != out { + dbt.Errorf("Valuer: %v != %s", in, out) + } + } else { + dbt.Errorf("Valuer: no data") + } + + dbt.mustExec("DROP TABLE IF EXISTS test") + }) +} + +type testValuerWithValidation struct { + value string +} + +func (tv testValuerWithValidation) Value() (driver.Value, error) { + if len(tv.value) == 0 { + return nil, fmt.Errorf("Invalid string valuer. Value must not be empty") + } + + return tv.value, nil +} + +func TestValuerWithValidation(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + in := testValuerWithValidation{"a_value"} + var out string + var rows *sql.Rows + + dbt.mustExec("CREATE TABLE testValuer (value VARCHAR(255)) CHARACTER SET utf8") + dbt.mustExec("INSERT INTO testValuer VALUES (?)", in) + + rows = dbt.mustQuery("SELECT value FROM testValuer") + defer rows.Close() + + if rows.Next() { + rows.Scan(&out) + if in.value != out { + dbt.Errorf("Valuer: %v != %s", in, out) + } + } else { + dbt.Errorf("Valuer: no data") + } + + if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", testValuerWithValidation{""}); err == nil { + dbt.Errorf("Failed to check valuer error") + } + + if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", nil); err != nil { + dbt.Errorf("Failed to check nil") + } + + if _, err := dbt.db.Exec("INSERT INTO testValuer VALUES (?)", map[string]bool{}); err == nil { + dbt.Errorf("Failed to check not valuer") + } + + dbt.mustExec("DROP TABLE IF EXISTS testValuer") + }) +} + type timeTests struct { dbtype string tlayout string @@ -684,7 +780,7 @@ func TestDateTime(t *testing.T) { for _, setup := range setups.tests { allowBinTime := true if setup.s == "" { - // fill time string whereever Go can reliable produce it + // fill time string wherever Go can reliable produce it setup.s = setup.t.Format(setups.tlayout) } else if setup.s[0] == '!' { // skip tests using setup.t as source in queries @@ -856,14 +952,14 @@ func TestNULL(t *testing.T) { dbt.Fatal(err) } if b != nil { - dbt.Error("non-nil []byte wich should be nil") + dbt.Error("non-nil []byte which should be nil") } // Read non-nil if err = nonNullStmt.QueryRow().Scan(&b); err != nil { dbt.Fatal(err) } if b == nil { - dbt.Error("nil []byte wich should be non-nil") + dbt.Error("nil []byte which should be non-nil") } // Insert nil b = nil @@ -953,7 +1049,7 @@ func TestUint64(t *testing.T) { } func TestLongData(t *testing.T) { - runTests(t, dsn, func(dbt *DBTest) { + runTests(t, dsn+"&maxAllowedPacket=0", func(dbt *DBTest) { var maxAllowedPacketSize int err := dbt.db.QueryRow("select @@max_allowed_packet").Scan(&maxAllowedPacketSize) if err != nil { @@ -1054,22 +1150,36 @@ func TestLoadData(t *testing.T) { dbt.Fatalf("rows count mismatch. Got %d, want 4", i) } } + + dbt.db.Exec("DROP TABLE IF EXISTS test") + dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8") + + // Local File file, err := ioutil.TempFile("", "gotest") defer os.Remove(file.Name()) if err != nil { dbt.Fatal(err) } - file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n") - file.Close() + RegisterLocalFile(file.Name()) - dbt.db.Exec("DROP TABLE IF EXISTS test") - dbt.mustExec("CREATE TABLE test (id INT NOT NULL PRIMARY KEY, value TEXT NOT NULL) CHARACTER SET utf8") + // Try first with empty file + dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) + var count int + err = dbt.db.QueryRow("SELECT COUNT(*) FROM test").Scan(&count) + if err != nil { + dbt.Fatal(err.Error()) + } + if count != 0 { + dbt.Fatalf("unexpected row count: got %d, want 0", count) + } - // Local File - RegisterLocalFile(file.Name()) + // Then fille File with data and try to load it + file.WriteString("1\ta string\n2\ta string containing a \\t\n3\ta string containing a \\n\n4\ta string containing both \\t\\n\n") + file.Close() dbt.mustExec(fmt.Sprintf("LOAD DATA LOCAL INFILE %q INTO TABLE test", file.Name())) verifyLoadDataResult() - // negative test + + // Try with non-existing file _, err = dbt.db.Exec("LOAD DATA LOCAL INFILE 'doesnotexist' INTO TABLE test") if err == nil { dbt.Fatal("load non-existent file didn't fail") @@ -1145,84 +1255,6 @@ func TestFoundRows(t *testing.T) { }) } -func TestStrict(t *testing.T) { - // ALLOW_INVALID_DATES to get rid of stricter modes - we want to test for warnings, not errors - relaxedDsn := dsn + "&sql_mode='ALLOW_INVALID_DATES,NO_AUTO_CREATE_USER'" - // make sure the MySQL version is recent enough with a separate connection - // before running the test - conn, err := MySQLDriver{}.Open(relaxedDsn) - if conn != nil { - conn.Close() - } - if me, ok := err.(*MySQLError); ok && me.Number == 1231 { - // Error 1231: Variable 'sql_mode' can't be set to the value of 'ALLOW_INVALID_DATES' - // => skip test, MySQL server version is too old - return - } - runTests(t, relaxedDsn, func(dbt *DBTest) { - dbt.mustExec("CREATE TABLE test (a TINYINT NOT NULL, b CHAR(4))") - - var queries = [...]struct { - in string - codes []string - }{ - {"DROP TABLE IF EXISTS no_such_table", []string{"1051"}}, - {"INSERT INTO test VALUES(10,'mysql'),(NULL,'test'),(300,'Open Source')", []string{"1265", "1048", "1264", "1265"}}, - } - var err error - - var checkWarnings = func(err error, mode string, idx int) { - if err == nil { - dbt.Errorf("expected STRICT error on query [%s] %s", mode, queries[idx].in) - } - - if warnings, ok := err.(MySQLWarnings); ok { - var codes = make([]string, len(warnings)) - for i := range warnings { - codes[i] = warnings[i].Code - } - if len(codes) != len(queries[idx].codes) { - dbt.Errorf("unexpected STRICT error count on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes) - } - - for i := range warnings { - if codes[i] != queries[idx].codes[i] { - dbt.Errorf("unexpected STRICT error codes on query [%s] %s: Wanted %v, Got %v", mode, queries[idx].in, queries[idx].codes, codes) - return - } - } - - } else { - dbt.Errorf("unexpected error on query [%s] %s: %s", mode, queries[idx].in, err.Error()) - } - } - - // text protocol - for i := range queries { - _, err = dbt.db.Exec(queries[i].in) - checkWarnings(err, "text", i) - } - - var stmt *sql.Stmt - - // binary protocol - for i := range queries { - stmt, err = dbt.db.Prepare(queries[i].in) - if err != nil { - dbt.Errorf("error on preparing query %s: %s", queries[i].in, err.Error()) - } - - _, err = stmt.Exec() - checkWarnings(err, "binary", i) - - err = stmt.Close() - if err != nil { - dbt.Errorf("error on closing stmt for query %s: %s", queries[i].in, err.Error()) - } - } - }) -} - func TestTLS(t *testing.T) { tlsTest := func(dbt *DBTest) { if err := dbt.db.Ping(); err != nil { @@ -1422,7 +1454,6 @@ func TestTimezoneConversion(t *testing.T) { // Regression test for timezone handling tzTest := func(dbt *DBTest) { - // Create table dbt.mustExec("CREATE TABLE test (ts TIMESTAMP)") @@ -1638,8 +1669,9 @@ func TestStmtMultiRows(t *testing.T) { // Regression test for // * more than 32 NULL parameters (issue 209) // * more parameters than fit into the buffer (issue 201) +// * parameters * 64 > max_allowed_packet (issue 734) func TestPreparedManyCols(t *testing.T) { - const numParams = defaultBufSize + numParams := 65535 runTests(t, dsn, func(dbt *DBTest) { query := "SELECT ?" + strings.Repeat(",?", numParams-1) stmt, err := dbt.db.Prepare(query) @@ -1647,15 +1679,25 @@ func TestPreparedManyCols(t *testing.T) { dbt.Fatal(err) } defer stmt.Close() + // create more parameters than fit into the buffer // which will take nil-values params := make([]interface{}, numParams) rows, err := stmt.Query(params...) if err != nil { - stmt.Close() dbt.Fatal(err) } - defer rows.Close() + rows.Close() + + // Create 0byte string which we can't send via STMT_LONG_DATA. + for i := 0; i < numParams; i++ { + params[i] = "" + } + rows, err = stmt.Query(params...) + if err != nil { + dbt.Fatal(err) + } + rows.Close() }) } @@ -1739,7 +1781,7 @@ func TestCustomDial(t *testing.T) { return net.Dial(prot, addr) }) - db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s&strict=true", user, pass, addr, dbname)) + db, err := sql.Open("mysql", fmt.Sprintf("%s:%s@mydial(%s)/%s?timeout=30s", user, pass, addr, dbname)) if err != nil { t.Fatalf("error connecting: %s", err.Error()) } @@ -1836,7 +1878,7 @@ func TestUnixSocketAuthFail(t *testing.T) { } } t.Logf("socket: %s", socket) - badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s&strict=true", user, badPass, socket, dbname) + badDSN := fmt.Sprintf("%s:%s@unix(%s)/%s?timeout=30s", user, badPass, socket, dbname) db, err := sql.Open("mysql", badDSN) if err != nil { t.Fatalf("error connecting: %s", err.Error()) @@ -1902,3 +1944,77 @@ func TestInterruptBySignal(t *testing.T) { } }) } + +func TestColumnsReusesSlice(t *testing.T) { + rows := mysqlRows{ + rs: resultSet{ + columns: []mysqlField{ + { + tableName: "test", + name: "A", + }, + { + tableName: "test", + name: "B", + }, + }, + }, + } + + allocs := testing.AllocsPerRun(1, func() { + cols := rows.Columns() + + if len(cols) != 2 { + t.Fatalf("expected 2 columns, got %d", len(cols)) + } + }) + + if allocs != 0 { + t.Fatalf("expected 0 allocations, got %d", int(allocs)) + } + + if rows.rs.columnNames == nil { + t.Fatalf("expected columnNames to be set, got nil") + } +} + +func TestRejectReadOnly(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + // Create Table + dbt.mustExec("CREATE TABLE test (value BOOL)") + // Set the session to read-only. We didn't set the `rejectReadOnly` + // option, so any writes after this should fail. + _, err := dbt.db.Exec("SET SESSION TRANSACTION READ ONLY") + // Error 1193: Unknown system variable 'TRANSACTION' => skip test, + // MySQL server version is too old + maybeSkip(t, err, 1193) + if _, err := dbt.db.Exec("DROP TABLE test"); err == nil { + t.Fatalf("writing to DB in read-only session without " + + "rejectReadOnly did not error") + } + // Set the session back to read-write so runTests() can properly clean + // up the table `test`. + dbt.mustExec("SET SESSION TRANSACTION READ WRITE") + }) + + // Enable the `rejectReadOnly` option. + runTests(t, dsn+"&rejectReadOnly=true", func(dbt *DBTest) { + // Create Table + dbt.mustExec("CREATE TABLE test (value BOOL)") + // Set the session to read only. Any writes after this should error on + // a driver.ErrBadConn, and cause `database/sql` to initiate a new + // connection. + dbt.mustExec("SET SESSION TRANSACTION READ ONLY") + // This would error, but `database/sql` should automatically retry on a + // new connection which is not read-only, and eventually succeed. + dbt.mustExec("DROP TABLE test") + }) +} + +func TestPing(t *testing.T) { + runTests(t, dsn, func(dbt *DBTest) { + if err := dbt.db.Ping(); err != nil { + dbt.fail("Ping", "Ping", err) + } + }) +} diff --git a/vendor/github.com/go-sql-driver/mysql/dsn.go b/vendor/github.com/go-sql-driver/mysql/dsn.go index ac00dcedd..47eab6945 100644 --- a/vendor/github.com/go-sql-driver/mysql/dsn.go +++ b/vendor/github.com/go-sql-driver/mysql/dsn.go @@ -15,6 +15,7 @@ import ( "fmt" "net" "net/url" + "sort" "strconv" "strings" "time" @@ -27,7 +28,9 @@ var ( errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations") ) -// Config is a configuration parsed from a DSN string +// Config is a configuration parsed from a DSN string. +// If a new Config is created instead of being parsed from a DSN string, +// the NewConfig function should be used, which sets default values. type Config struct { User string // Username Passwd string // Password (requires User) @@ -53,7 +56,54 @@ type Config struct { InterpolateParams bool // Interpolate placeholders into query string MultiStatements bool // Allow multiple statements in one query ParseTime bool // Parse time values to time.Time - Strict bool // Return warnings as errors + RejectReadOnly bool // Reject read-only connections +} + +// NewConfig creates a new Config and sets default values. +func NewConfig() *Config { + return &Config{ + Collation: defaultCollation, + Loc: time.UTC, + MaxAllowedPacket: defaultMaxAllowedPacket, + AllowNativePasswords: true, + } +} + +func (cfg *Config) normalize() error { + if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { + return errInvalidDSNUnsafeCollation + } + + // Set default network if empty + if cfg.Net == "" { + cfg.Net = "tcp" + } + + // Set default address if empty + if cfg.Addr == "" { + switch cfg.Net { + case "tcp": + cfg.Addr = "127.0.0.1:3306" + case "unix": + cfg.Addr = "/tmp/mysql.sock" + default: + return errors.New("default addr for network '" + cfg.Net + "' unknown") + } + + } else if cfg.Net == "tcp" { + cfg.Addr = ensureHavePort(cfg.Addr) + } + + if cfg.tls != nil { + if cfg.tls.ServerName == "" && !cfg.tls.InsecureSkipVerify { + host, _, err := net.SplitHostPort(cfg.Addr) + if err == nil { + cfg.tls.ServerName = host + } + } + } + + return nil } // FormatDSN formats the given Config into a DSN string which can be passed to @@ -102,12 +152,12 @@ func (cfg *Config) FormatDSN() string { } } - if cfg.AllowNativePasswords { + if !cfg.AllowNativePasswords { if hasParam { - buf.WriteString("&allowNativePasswords=true") + buf.WriteString("&allowNativePasswords=false") } else { hasParam = true - buf.WriteString("?allowNativePasswords=true") + buf.WriteString("?allowNativePasswords=false") } } @@ -195,12 +245,12 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(cfg.ReadTimeout.String()) } - if cfg.Strict { + if cfg.RejectReadOnly { if hasParam { - buf.WriteString("&strict=true") + buf.WriteString("&rejectReadOnly=true") } else { hasParam = true - buf.WriteString("?strict=true") + buf.WriteString("?rejectReadOnly=true") } } @@ -234,7 +284,7 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(cfg.WriteTimeout.String()) } - if cfg.MaxAllowedPacket > 0 { + if cfg.MaxAllowedPacket != defaultMaxAllowedPacket { if hasParam { buf.WriteString("&maxAllowedPacket=") } else { @@ -247,7 +297,12 @@ func (cfg *Config) FormatDSN() string { // other params if cfg.Params != nil { - for param, value := range cfg.Params { + var params []string + for param := range cfg.Params { + params = append(params, param) + } + sort.Strings(params) + for _, param := range params { if hasParam { buf.WriteByte('&') } else { @@ -257,7 +312,7 @@ func (cfg *Config) FormatDSN() string { buf.WriteString(param) buf.WriteByte('=') - buf.WriteString(url.QueryEscape(value)) + buf.WriteString(url.QueryEscape(cfg.Params[param])) } } @@ -267,10 +322,7 @@ func (cfg *Config) FormatDSN() string { // ParseDSN parses the DSN string to a Config func ParseDSN(dsn string) (cfg *Config, err error) { // New config with some default values - cfg = &Config{ - Loc: time.UTC, - Collation: defaultCollation, - } + cfg = NewConfig() // [user[:password]@][net[(addr)]]/dbname[?param1=value1¶mN=valueN] // Find the last '/' (since the password or the net addr might contain a '/') @@ -338,28 +390,9 @@ func ParseDSN(dsn string) (cfg *Config, err error) { return nil, errInvalidDSNNoSlash } - if cfg.InterpolateParams && unsafeCollations[cfg.Collation] { - return nil, errInvalidDSNUnsafeCollation - } - - // Set default network if empty - if cfg.Net == "" { - cfg.Net = "tcp" + if err = cfg.normalize(); err != nil { + return nil, err } - - // Set default address if empty - if cfg.Addr == "" { - switch cfg.Net { - case "tcp": - cfg.Addr = "127.0.0.1:3306" - case "unix": - cfg.Addr = "/tmp/mysql.sock" - default: - return nil, errors.New("default addr for network '" + cfg.Net + "' unknown") - } - - } - return } @@ -374,7 +407,6 @@ func parseDSNParams(cfg *Config, params string) (err error) { // cfg params switch value := param[1]; param[0] { - // Disable INFILE whitelist / enable all files case "allowAllFiles": var isBool bool @@ -472,14 +504,18 @@ func parseDSNParams(cfg *Config, params string) (err error) { return } - // Strict mode - case "strict": + // Reject read-only connections + case "rejectReadOnly": var isBool bool - cfg.Strict, isBool = readBool(value) + cfg.RejectReadOnly, isBool = readBool(value) if !isBool { return errors.New("invalid bool value: " + value) } + // Strict mode + case "strict": + panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode") + // Dial Timeout case "timeout": cfg.Timeout, err = time.ParseDuration(value) @@ -506,14 +542,7 @@ func parseDSNParams(cfg *Config, params string) (err error) { return fmt.Errorf("invalid value for TLS config name: %v", err) } - if tlsConfig, ok := tlsConfigRegister[name]; ok { - if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify { - host, _, err := net.SplitHostPort(cfg.Addr) - if err == nil { - tlsConfig.ServerName = host - } - } - + if tlsConfig := getTLSConfigClone(name); tlsConfig != nil { cfg.TLSConfig = name cfg.tls = tlsConfig } else { @@ -546,3 +575,10 @@ func parseDSNParams(cfg *Config, params string) (err error) { return } + +func ensureHavePort(addr string) string { + if _, _, err := net.SplitHostPort(addr); err != nil { + return net.JoinHostPort(addr, "3306") + } + return addr +} diff --git a/vendor/github.com/go-sql-driver/mysql/dsn_test.go b/vendor/github.com/go-sql-driver/mysql/dsn_test.go index 0693192ad..7507d1201 100644 --- a/vendor/github.com/go-sql-driver/mysql/dsn_test.go +++ b/vendor/github.com/go-sql-driver/mysql/dsn_test.go @@ -22,47 +22,57 @@ var testDSNs = []struct { out *Config }{{ "username:password@protocol(address)/dbname?param=value", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "username:password@protocol(address)/dbname?param=value&columnsWithAlias=true", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, ColumnsWithAlias: true}, + &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, ColumnsWithAlias: true}, }, { "username:password@protocol(address)/dbname?param=value&columnsWithAlias=true&multiStatements=true", - &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, ColumnsWithAlias: true, MultiStatements: true}, + &Config{User: "username", Passwd: "password", Net: "protocol", Addr: "address", DBName: "dbname", Params: map[string]string{"param": "value"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, ColumnsWithAlias: true, MultiStatements: true}, }, { "user@unix(/path/to/socket)/dbname?charset=utf8", - &Config{User: "user", Net: "unix", Addr: "/path/to/socket", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{User: "user", Net: "unix", Addr: "/path/to/socket", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "user:password@tcp(localhost:5555)/dbname?charset=utf8&tls=true", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, TLSConfig: "true"}, + &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, TLSConfig: "true"}, }, { "user:password@tcp(localhost:5555)/dbname?charset=utf8mb4,utf8&tls=skip-verify", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8mb4,utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, TLSConfig: "skip-verify"}, + &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "localhost:5555", DBName: "dbname", Params: map[string]string{"charset": "utf8mb4,utf8"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true, TLSConfig: "skip-verify"}, }, { "user:password@/dbname?loc=UTC&timeout=30s&readTimeout=1s&writeTimeout=1s&allowAllFiles=1&clientFoundRows=true&allowOldPasswords=TRUE&collation=utf8mb4_unicode_ci&maxAllowedPacket=16777216", - &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_unicode_ci", Loc: time.UTC, Timeout: 30 * time.Second, ReadTimeout: time.Second, WriteTimeout: time.Second, AllowAllFiles: true, AllowOldPasswords: true, ClientFoundRows: true, MaxAllowedPacket: 16777216}, + &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8mb4_unicode_ci", Loc: time.UTC, AllowNativePasswords: true, Timeout: 30 * time.Second, ReadTimeout: time.Second, WriteTimeout: time.Second, AllowAllFiles: true, AllowOldPasswords: true, ClientFoundRows: true, MaxAllowedPacket: 16777216}, +}, { + "user:password@/dbname?allowNativePasswords=false&maxAllowedPacket=0", + &Config{User: "user", Passwd: "password", Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: 0, AllowNativePasswords: false}, }, { "user:p@ss(word)@tcp([de:ad:be:ef::ca:fe]:80)/dbname?loc=Local", - &Config{User: "user", Passwd: "p@ss(word)", Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:80", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.Local}, + &Config{User: "user", Passwd: "p@ss(word)", Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:80", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.Local, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "/dbname", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "@/", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "/", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "", - &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "user:p@/ssword@/", - &Config{User: "user", Passwd: "p@/ssword", Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC}, + &Config{User: "user", Passwd: "p@/ssword", Net: "tcp", Addr: "127.0.0.1:3306", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, }, { "unix/?arg=%2Fsome%2Fpath.ext", - &Config{Net: "unix", Addr: "/tmp/mysql.sock", Params: map[string]string{"arg": "/some/path.ext"}, Collation: "utf8_general_ci", Loc: time.UTC}, -}} + &Config{Net: "unix", Addr: "/tmp/mysql.sock", Params: map[string]string{"arg": "/some/path.ext"}, Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, +}, { + "tcp(127.0.0.1)/dbname", + &Config{Net: "tcp", Addr: "127.0.0.1:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, +}, { + "tcp(de:ad:be:ef::ca:fe)/dbname", + &Config{Net: "tcp", Addr: "[de:ad:be:ef::ca:fe]:3306", DBName: "dbname", Collation: "utf8_general_ci", Loc: time.UTC, MaxAllowedPacket: defaultMaxAllowedPacket, AllowNativePasswords: true}, +}, +} func TestDSNParser(t *testing.T) { for i, tst := range testDSNs { @@ -88,6 +98,7 @@ func TestDSNParserInvalid(t *testing.T) { "(/", // no closing brace "net(addr)//", // unescaped "User:pass@tcp(1.2.3.4:3306)", // no trailing slash + "net()/", // unknown default addr //"/dbname?arg=/some/unescaped/path", } @@ -159,11 +170,41 @@ func TestDSNWithCustomTLS(t *testing.T) { t.Error(err.Error()) } else if cfg.tls.ServerName != name { t.Errorf("did not get the correct ServerName (%s) parsing DSN (%s).", name, tst) + } else if tlsCfg.ServerName != "" { + t.Errorf("tlsCfg was mutated ServerName (%s) should be empty parsing DSN (%s).", name, tst) } DeregisterTLSConfig("utils_test") } +func TestDSNTLSConfig(t *testing.T) { + expectedServerName := "example.com" + dsn := "tcp(example.com:1234)/?tls=true" + + cfg, err := ParseDSN(dsn) + if err != nil { + t.Error(err.Error()) + } + if cfg.tls == nil { + t.Error("cfg.tls should not be nil") + } + if cfg.tls.ServerName != expectedServerName { + t.Errorf("cfg.tls.ServerName should be %q, got %q (host with port)", expectedServerName, cfg.tls.ServerName) + } + + dsn = "tcp(example.com)/?tls=true" + cfg, err = ParseDSN(dsn) + if err != nil { + t.Error(err.Error()) + } + if cfg.tls == nil { + t.Error("cfg.tls should not be nil") + } + if cfg.tls.ServerName != expectedServerName { + t.Errorf("cfg.tls.ServerName should be %q, got %q (host without port)", expectedServerName, cfg.tls.ServerName) + } +} + func TestDSNWithCustomTLSQueryEscape(t *testing.T) { const configKey = "&%!:" dsn := "User:password@tcp(localhost:5555)/dbname?tls=" + url.QueryEscape(configKey) @@ -218,6 +259,21 @@ func TestDSNUnsafeCollation(t *testing.T) { } } +func TestParamsAreSorted(t *testing.T) { + expected := "/dbname?interpolateParams=true&foobar=baz&quux=loo" + cfg := NewConfig() + cfg.DBName = "dbname" + cfg.InterpolateParams = true + cfg.Params = map[string]string{ + "quux": "loo", + "foobar": "baz", + } + actual := cfg.FormatDSN() + if actual != expected { + t.Errorf("generic Config.Params were not sorted: want %#v, got %#v", expected, actual) + } +} + func BenchmarkParseDSN(b *testing.B) { b.ReportAllocs() diff --git a/vendor/github.com/go-sql-driver/mysql/errors.go b/vendor/github.com/go-sql-driver/mysql/errors.go index 857854e14..760782ff2 100644 --- a/vendor/github.com/go-sql-driver/mysql/errors.go +++ b/vendor/github.com/go-sql-driver/mysql/errors.go @@ -9,10 +9,8 @@ package mysql import ( - "database/sql/driver" "errors" "fmt" - "io" "log" "os" ) @@ -31,6 +29,12 @@ var ( ErrPktSyncMul = errors.New("commands out of sync. Did you run multiple statements at once?") ErrPktTooLarge = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server") ErrBusyBuffer = errors.New("busy buffer") + + // errBadConnNoWrite is used for connection errors where nothing was sent to the database yet. + // If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn + // to trigger a resend. + // See https://github.com/go-sql-driver/mysql/pull/302 + errBadConnNoWrite = errors.New("bad connection") ) var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile)) @@ -59,74 +63,3 @@ type MySQLError struct { func (me *MySQLError) Error() string { return fmt.Sprintf("Error %d: %s", me.Number, me.Message) } - -// MySQLWarnings is an error type which represents a group of one or more MySQL -// warnings -type MySQLWarnings []MySQLWarning - -func (mws MySQLWarnings) Error() string { - var msg string - for i, warning := range mws { - if i > 0 { - msg += "\r\n" - } - msg += fmt.Sprintf( - "%s %s: %s", - warning.Level, - warning.Code, - warning.Message, - ) - } - return msg -} - -// MySQLWarning is an error type which represents a single MySQL warning. -// Warnings are returned in groups only. See MySQLWarnings -type MySQLWarning struct { - Level string - Code string - Message string -} - -func (mc *mysqlConn) getWarnings() (err error) { - rows, err := mc.Query("SHOW WARNINGS", nil) - if err != nil { - return - } - - var warnings = MySQLWarnings{} - var values = make([]driver.Value, 3) - - for { - err = rows.Next(values) - switch err { - case nil: - warning := MySQLWarning{} - - if raw, ok := values[0].([]byte); ok { - warning.Level = string(raw) - } else { - warning.Level = fmt.Sprintf("%s", values[0]) - } - if raw, ok := values[1].([]byte); ok { - warning.Code = string(raw) - } else { - warning.Code = fmt.Sprintf("%s", values[1]) - } - if raw, ok := values[2].([]byte); ok { - warning.Message = string(raw) - } else { - warning.Message = fmt.Sprintf("%s", values[0]) - } - - warnings = append(warnings, warning) - - case io.EOF: - return warnings - - default: - rows.Close() - return - } - } -} diff --git a/vendor/github.com/go-sql-driver/mysql/fields.go b/vendor/github.com/go-sql-driver/mysql/fields.go new file mode 100644 index 000000000..e1e2ece4b --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/fields.go @@ -0,0 +1,194 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "database/sql" + "reflect" +) + +func (mf *mysqlField) typeDatabaseName() string { + switch mf.fieldType { + case fieldTypeBit: + return "BIT" + case fieldTypeBLOB: + if mf.charSet != collations[binaryCollation] { + return "TEXT" + } + return "BLOB" + case fieldTypeDate: + return "DATE" + case fieldTypeDateTime: + return "DATETIME" + case fieldTypeDecimal: + return "DECIMAL" + case fieldTypeDouble: + return "DOUBLE" + case fieldTypeEnum: + return "ENUM" + case fieldTypeFloat: + return "FLOAT" + case fieldTypeGeometry: + return "GEOMETRY" + case fieldTypeInt24: + return "MEDIUMINT" + case fieldTypeJSON: + return "JSON" + case fieldTypeLong: + return "INT" + case fieldTypeLongBLOB: + if mf.charSet != collations[binaryCollation] { + return "LONGTEXT" + } + return "LONGBLOB" + case fieldTypeLongLong: + return "BIGINT" + case fieldTypeMediumBLOB: + if mf.charSet != collations[binaryCollation] { + return "MEDIUMTEXT" + } + return "MEDIUMBLOB" + case fieldTypeNewDate: + return "DATE" + case fieldTypeNewDecimal: + return "DECIMAL" + case fieldTypeNULL: + return "NULL" + case fieldTypeSet: + return "SET" + case fieldTypeShort: + return "SMALLINT" + case fieldTypeString: + if mf.charSet == collations[binaryCollation] { + return "BINARY" + } + return "CHAR" + case fieldTypeTime: + return "TIME" + case fieldTypeTimestamp: + return "TIMESTAMP" + case fieldTypeTiny: + return "TINYINT" + case fieldTypeTinyBLOB: + if mf.charSet != collations[binaryCollation] { + return "TINYTEXT" + } + return "TINYBLOB" + case fieldTypeVarChar: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeVarString: + if mf.charSet == collations[binaryCollation] { + return "VARBINARY" + } + return "VARCHAR" + case fieldTypeYear: + return "YEAR" + default: + return "" + } +} + +var ( + scanTypeFloat32 = reflect.TypeOf(float32(0)) + scanTypeFloat64 = reflect.TypeOf(float64(0)) + scanTypeInt8 = reflect.TypeOf(int8(0)) + scanTypeInt16 = reflect.TypeOf(int16(0)) + scanTypeInt32 = reflect.TypeOf(int32(0)) + scanTypeInt64 = reflect.TypeOf(int64(0)) + scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{}) + scanTypeNullInt = reflect.TypeOf(sql.NullInt64{}) + scanTypeNullTime = reflect.TypeOf(NullTime{}) + scanTypeUint8 = reflect.TypeOf(uint8(0)) + scanTypeUint16 = reflect.TypeOf(uint16(0)) + scanTypeUint32 = reflect.TypeOf(uint32(0)) + scanTypeUint64 = reflect.TypeOf(uint64(0)) + scanTypeRawBytes = reflect.TypeOf(sql.RawBytes{}) + scanTypeUnknown = reflect.TypeOf(new(interface{})) +) + +type mysqlField struct { + tableName string + name string + length uint32 + flags fieldFlag + fieldType fieldType + decimals byte + charSet uint8 +} + +func (mf *mysqlField) scanType() reflect.Type { + switch mf.fieldType { + case fieldTypeTiny: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint8 + } + return scanTypeInt8 + } + return scanTypeNullInt + + case fieldTypeShort, fieldTypeYear: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint16 + } + return scanTypeInt16 + } + return scanTypeNullInt + + case fieldTypeInt24, fieldTypeLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint32 + } + return scanTypeInt32 + } + return scanTypeNullInt + + case fieldTypeLongLong: + if mf.flags&flagNotNULL != 0 { + if mf.flags&flagUnsigned != 0 { + return scanTypeUint64 + } + return scanTypeInt64 + } + return scanTypeNullInt + + case fieldTypeFloat: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat32 + } + return scanTypeNullFloat + + case fieldTypeDouble: + if mf.flags&flagNotNULL != 0 { + return scanTypeFloat64 + } + return scanTypeNullFloat + + case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar, + fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB, + fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB, + fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON, + fieldTypeTime: + return scanTypeRawBytes + + case fieldTypeDate, fieldTypeNewDate, + fieldTypeTimestamp, fieldTypeDateTime: + // NullTime is always returned for more consistent behavior as it can + // handle both cases of parseTime regardless if the field is nullable. + return scanTypeNullTime + + default: + return scanTypeUnknown + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/infile.go b/vendor/github.com/go-sql-driver/mysql/infile.go index 547357cfa..4020f9192 100644 --- a/vendor/github.com/go-sql-driver/mysql/infile.go +++ b/vendor/github.com/go-sql-driver/mysql/infile.go @@ -147,7 +147,8 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) { } // send content packets - if err == nil { + // if packetSize == 0, the Reader contains no data + if err == nil && packetSize > 0 { data := make([]byte, 4+packetSize) var n int for err == nil { diff --git a/vendor/github.com/go-sql-driver/mysql/packets.go b/vendor/github.com/go-sql-driver/mysql/packets.go index aafe9793e..afc3fcc46 100644 --- a/vendor/github.com/go-sql-driver/mysql/packets.go +++ b/vendor/github.com/go-sql-driver/mysql/packets.go @@ -30,9 +30,12 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // read packet header data, err := mc.buf.readNext(4) if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } errLog.Print(err) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } // packet length [24 bit] @@ -54,7 +57,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { if prevData == nil { errLog.Print(ErrMalformPkt) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } return prevData, nil @@ -63,9 +66,12 @@ func (mc *mysqlConn) readPacket() ([]byte, error) { // read packet body [pktLen bytes] data, err = mc.buf.readNext(pktLen) if err != nil { + if cerr := mc.canceled.Value(); cerr != nil { + return nil, cerr + } errLog.Print(err) mc.Close() - return nil, driver.ErrBadConn + return nil, ErrInvalidConn } // return data if this was the last packet @@ -125,11 +131,20 @@ func (mc *mysqlConn) writePacket(data []byte) error { // Handle error if err == nil { // n != len(data) + mc.cleanup() errLog.Print(ErrMalformPkt) } else { + if cerr := mc.canceled.Value(); cerr != nil { + return cerr + } + if n == 0 && pktLen == len(data)-4 { + // only for the first loop iteration when nothing was written yet + return errBadConnNoWrite + } + mc.cleanup() errLog.Print(err) } - return driver.ErrBadConn + return ErrInvalidConn } } @@ -142,6 +157,11 @@ func (mc *mysqlConn) writePacket(data []byte) error { func (mc *mysqlConn) readInitPacket() ([]byte, error) { data, err := mc.readPacket() if err != nil { + // for init we can rewrite this to ErrBadConn for sql.Driver to retry, since + // in connection initialization we don't risk retrying non-idempotent actions. + if err == ErrInvalidConn { + return nil, driver.ErrBadConn + } return nil, err } @@ -263,7 +283,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // ClientFlags [32 bit] @@ -341,7 +361,9 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error { // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error { // User password - scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.Passwd)) + // https://dev.mysql.com/doc/internals/en/old-password-authentication.html + // Old password authentication only need and will need 8-byte challenge. + scrambleBuff := scrambleOldPassword(cipher[:8], []byte(mc.cfg.Passwd)) // Calculate the packet length and add a tailing 0 pktLen := len(scrambleBuff) + 1 @@ -349,7 +371,7 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the scrambled password [null terminated string] @@ -368,7 +390,7 @@ func (mc *mysqlConn) writeClearAuthPacket() error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the clear password [null terminated string] @@ -381,7 +403,9 @@ func (mc *mysqlConn) writeClearAuthPacket() error { // Native password authentication method // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error { - scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd)) + // https://dev.mysql.com/doc/internals/en/secure-password-authentication.html + // Native password authentication only need and will need 20-byte challenge. + scrambleBuff := scramblePassword(cipher[0:20], []byte(mc.cfg.Passwd)) // Calculate the packet length and add a tailing 0 pktLen := len(scrambleBuff) @@ -389,7 +413,7 @@ func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add the scramble @@ -410,7 +434,7 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -429,7 +453,7 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -450,7 +474,7 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // Add command byte @@ -484,25 +508,26 @@ func (mc *mysqlConn) readResultOK() ([]byte, error) { if len(data) > 1 { pluginEndIndex := bytes.IndexByte(data, 0x00) plugin := string(data[1:pluginEndIndex]) - cipher := data[pluginEndIndex+1 : len(data)-1] + cipher := data[pluginEndIndex+1:] - if plugin == "mysql_old_password" { + switch plugin { + case "mysql_old_password": // using old_passwords return cipher, ErrOldPassword - } else if plugin == "mysql_clear_password" { + case "mysql_clear_password": // using clear text password return cipher, ErrCleartextPassword - } else if plugin == "mysql_native_password" { + case "mysql_native_password": // using mysql default authentication method return cipher, ErrNativePassword - } else { + default: return cipher, ErrUnknownPlugin } - } else { - // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest - return nil, ErrOldPassword } + // https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest + return nil, ErrOldPassword + default: // Error otherwise return nil, mc.handleErrorPacket(data) } @@ -550,6 +575,22 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error { // Error Number [16 bit uint] errno := binary.LittleEndian.Uint16(data[1:3]) + // 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION + // 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover) + if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly { + // Oops; we are connected to a read-only connection, and won't be able + // to issue any write statements. Since RejectReadOnly is configured, + // we throw away this connection hoping this one would have write + // permission. This is specifically for a possible race condition + // during failover (e.g. on AWS Aurora). See README.md for more. + // + // We explicitly close the connection before returning + // driver.ErrBadConn to ensure that `database/sql` purges this + // connection and initiates a new one for next statement next time. + mc.Close() + return driver.ErrBadConn + } + pos := 3 // SQL State [optional: # + 5bytes string] @@ -584,19 +625,12 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error { // server_status [2 bytes] mc.status = readStatus(data[1+n+m : 1+n+m+2]) - if err := mc.discardResults(); err != nil { - return err + if mc.status&statusMoreResultsExists != 0 { + return nil } // warning count [2 bytes] - if !mc.strict { - return nil - } - pos := 1 + n + m + 2 - if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 { - return mc.getWarnings() - } return nil } @@ -668,14 +702,21 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { if err != nil { return nil, err } + pos += n // Filler [uint8] + pos++ + // Charset [charset, collation uint8] + columns[i].charSet = data[pos] + pos += 2 + // Length [uint32] - pos += n + 1 + 2 + 4 + columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4]) + pos += 4 // Field type [uint8] - columns[i].fieldType = data[pos] + columns[i].fieldType = fieldType(data[pos]) pos++ // Flags [uint16] @@ -698,6 +739,10 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) { func (rows *textRows) readRow(dest []driver.Value) error { mc := rows.mc + if rows.rs.done { + return io.EOF + } + data, err := mc.readPacket() if err != nil { return err @@ -707,15 +752,11 @@ func (rows *textRows) readRow(dest []driver.Value) error { if data[0] == iEOF && len(data) == 5 { // server_status [2 bytes] rows.mc.status = readStatus(data[3:]) - err = rows.mc.discardResults() - if err == nil { - err = io.EOF - } else { - // connection unusable - rows.mc.Close() + rows.rs.done = true + if !rows.HasNextResultSet() { + rows.mc = nil } - rows.mc = nil - return err + return io.EOF } if data[0] == iERR { rows.mc = nil @@ -736,7 +777,7 @@ func (rows *textRows) readRow(dest []driver.Value) error { if !mc.parseTime { continue } else { - switch rows.columns[i].fieldType { + switch rows.rs.columns[i].fieldType { case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeDate, fieldTypeNewDate: dest[i], err = parseDateTime( @@ -808,14 +849,7 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) { // Reserved [8 bit] // Warning count [16 bit uint] - if !stmt.mc.strict { - return columnCount, nil - } - // Check for warnings count > 0, only available in MySQL > 4.1 - if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 { - return columnCount, stmt.mc.getWarnings() - } return columnCount, nil } return 0, err @@ -887,6 +921,12 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { const minPktLen = 4 + 1 + 4 + 1 + 4 mc := stmt.mc + // Determine threshould dynamically to avoid packet size shortage. + longDataSize := mc.maxAllowedPacket / (stmt.paramCount + 1) + if longDataSize < 64 { + longDataSize = 64 + } + // Reset packet-sequence mc.sequence = 0 @@ -900,7 +940,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { if data == nil { // can not take the buffer. Something must be wrong with the connection errLog.Print(ErrBusyBuffer) - return driver.ErrBadConn + return errBadConnNoWrite } // command [1 byte] @@ -959,7 +999,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // build NULL-bitmap if arg == nil { nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = fieldTypeNULL + paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 continue } @@ -967,7 +1007,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // cache types and values switch v := arg.(type) { case int64: - paramTypes[i+i] = fieldTypeLongLong + paramTypes[i+i] = byte(fieldTypeLongLong) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { @@ -983,7 +1023,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case float64: - paramTypes[i+i] = fieldTypeDouble + paramTypes[i+i] = byte(fieldTypeDouble) paramTypes[i+i+1] = 0x00 if cap(paramValues)-len(paramValues)-8 >= 0 { @@ -999,7 +1039,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case bool: - paramTypes[i+i] = fieldTypeTiny + paramTypes[i+i] = byte(fieldTypeTiny) paramTypes[i+i+1] = 0x00 if v { @@ -1011,10 +1051,10 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { case []byte: // Common case (non-nil value) first if v != nil { - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) @@ -1029,14 +1069,14 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { // Handle []byte(nil) as a NULL value nullMask[i/8] |= 1 << (uint(i) & 7) - paramTypes[i+i] = fieldTypeNULL + paramTypes[i+i] = byte(fieldTypeNULL) paramTypes[i+i+1] = 0x00 case string: - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 { + if len(v) < longDataSize { paramValues = appendLengthEncodedInteger(paramValues, uint64(len(v)), ) @@ -1048,20 +1088,22 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error { } case time.Time: - paramTypes[i+i] = fieldTypeString + paramTypes[i+i] = byte(fieldTypeString) paramTypes[i+i+1] = 0x00 - var val []byte + var a [64]byte + var b = a[:0] + if v.IsZero() { - val = []byte("0000-00-00") + b = append(b, "0000-00-00"...) } else { - val = []byte(v.In(mc.cfg.Loc).Format(timeFormat)) + b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat) } paramValues = appendLengthEncodedInteger(paramValues, - uint64(len(val)), + uint64(len(b)), ) - paramValues = append(paramValues, val...) + paramValues = append(paramValues, b...) default: return fmt.Errorf("can not convert type: %T", arg) @@ -1097,8 +1139,6 @@ func (mc *mysqlConn) discardResults() error { if err := mc.readUntilEOF(); err != nil { return err } - } else { - mc.status &^= statusMoreResultsExists } } return nil @@ -1116,20 +1156,17 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { // EOF Packet if data[0] == iEOF && len(data) == 5 { rows.mc.status = readStatus(data[3:]) - err = rows.mc.discardResults() - if err == nil { - err = io.EOF - } else { - // connection unusable - rows.mc.Close() + rows.rs.done = true + if !rows.HasNextResultSet() { + rows.mc = nil } - rows.mc = nil - return err + return io.EOF } + mc := rows.mc rows.mc = nil // Error otherwise - return rows.mc.handleErrorPacket(data) + return mc.handleErrorPacket(data) } // NULL-bitmap, [(column-count + 7 + 2) / 8 bytes] @@ -1145,14 +1182,14 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { } // Convert to byte-coded string - switch rows.columns[i].fieldType { + switch rows.rs.columns[i].fieldType { case fieldTypeNULL: dest[i] = nil continue // Numeric Types case fieldTypeTiny: - if rows.columns[i].flags&flagUnsigned != 0 { + if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(data[pos]) } else { dest[i] = int64(int8(data[pos])) @@ -1161,7 +1198,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { continue case fieldTypeShort, fieldTypeYear: - if rows.columns[i].flags&flagUnsigned != 0 { + if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2])) } else { dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2]))) @@ -1170,7 +1207,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { continue case fieldTypeInt24, fieldTypeLong: - if rows.columns[i].flags&flagUnsigned != 0 { + if rows.rs.columns[i].flags&flagUnsigned != 0 { dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4])) } else { dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4]))) @@ -1179,7 +1216,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { continue case fieldTypeLongLong: - if rows.columns[i].flags&flagUnsigned != 0 { + if rows.rs.columns[i].flags&flagUnsigned != 0 { val := binary.LittleEndian.Uint64(data[pos : pos+8]) if val > math.MaxInt64 { dest[i] = uint64ToString(val) @@ -1193,7 +1230,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { continue case fieldTypeFloat: - dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))) + dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])) pos += 4 continue @@ -1233,10 +1270,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { case isNull: dest[i] = nil continue - case rows.columns[i].fieldType == fieldTypeTime: + case rows.rs.columns[i].fieldType == fieldTypeTime: // database/sql does not support an equivalent to TIME, return a string var dstlen uint8 - switch decimals := rows.columns[i].decimals; decimals { + switch decimals := rows.rs.columns[i].decimals; decimals { case 0x00, 0x1f: dstlen = 8 case 1, 2, 3, 4, 5, 6: @@ -1244,7 +1281,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { default: return fmt.Errorf( "protocol error, illegal decimals value %d", - rows.columns[i].decimals, + rows.rs.columns[i].decimals, ) } dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true) @@ -1252,10 +1289,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc) default: var dstlen uint8 - if rows.columns[i].fieldType == fieldTypeDate { + if rows.rs.columns[i].fieldType == fieldTypeDate { dstlen = 10 } else { - switch decimals := rows.columns[i].decimals; decimals { + switch decimals := rows.rs.columns[i].decimals; decimals { case 0x00, 0x1f: dstlen = 19 case 1, 2, 3, 4, 5, 6: @@ -1263,7 +1300,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { default: return fmt.Errorf( "protocol error, illegal decimals value %d", - rows.columns[i].decimals, + rows.rs.columns[i].decimals, ) } } @@ -1279,7 +1316,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error { // Please report if this happens! default: - return fmt.Errorf("unknown field type %d", rows.columns[i].fieldType) + return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType) } } diff --git a/vendor/github.com/go-sql-driver/mysql/packets_test.go b/vendor/github.com/go-sql-driver/mysql/packets_test.go index 98404586a..2f8207511 100644 --- a/vendor/github.com/go-sql-driver/mysql/packets_test.go +++ b/vendor/github.com/go-sql-driver/mysql/packets_test.go @@ -9,7 +9,6 @@ package mysql import ( - "database/sql/driver" "errors" "net" "testing" @@ -101,7 +100,7 @@ func TestReadPacketSingleByte(t *testing.T) { t.Fatal(err) } if len(packet) != 1 { - t.Fatalf("unexpected packet lenght: expected %d, got %d", 1, len(packet)) + t.Fatalf("unexpected packet length: expected %d, got %d", 1, len(packet)) } if packet[0] != 0xff { t.Fatalf("unexpected packet content: expected %x, got %x", 0xff, packet[0]) @@ -171,7 +170,7 @@ func TestReadPacketSplit(t *testing.T) { t.Fatal(err) } if len(packet) != maxPacketSize { - t.Fatalf("unexpected packet lenght: expected %d, got %d", maxPacketSize, len(packet)) + t.Fatalf("unexpected packet length: expected %d, got %d", maxPacketSize, len(packet)) } if packet[0] != 0x11 { t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) @@ -205,7 +204,7 @@ func TestReadPacketSplit(t *testing.T) { t.Fatal(err) } if len(packet) != 2*maxPacketSize { - t.Fatalf("unexpected packet lenght: expected %d, got %d", 2*maxPacketSize, len(packet)) + t.Fatalf("unexpected packet length: expected %d, got %d", 2*maxPacketSize, len(packet)) } if packet[0] != 0x11 { t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) @@ -231,7 +230,7 @@ func TestReadPacketSplit(t *testing.T) { t.Fatal(err) } if len(packet) != maxPacketSize+42 { - t.Fatalf("unexpected packet lenght: expected %d, got %d", maxPacketSize+42, len(packet)) + t.Fatalf("unexpected packet length: expected %d, got %d", maxPacketSize+42, len(packet)) } if packet[0] != 0x11 { t.Fatalf("unexpected payload start: expected %x, got %x", 0x11, packet[0]) @@ -244,15 +243,16 @@ func TestReadPacketSplit(t *testing.T) { func TestReadPacketFail(t *testing.T) { conn := new(mockConn) mc := &mysqlConn{ - buf: newBuffer(conn), + buf: newBuffer(conn), + closech: make(chan struct{}), } // illegal empty (stand-alone) packet conn.data = []byte{0x00, 0x00, 0x00, 0x00} conn.maxReads = 1 _, err := mc.readPacket() - if err != driver.ErrBadConn { - t.Errorf("expected ErrBadConn, got %v", err) + if err != ErrInvalidConn { + t.Errorf("expected ErrInvalidConn, got %v", err) } // reset @@ -263,8 +263,8 @@ func TestReadPacketFail(t *testing.T) { // fail to read header conn.closed = true _, err = mc.readPacket() - if err != driver.ErrBadConn { - t.Errorf("expected ErrBadConn, got %v", err) + if err != ErrInvalidConn { + t.Errorf("expected ErrInvalidConn, got %v", err) } // reset @@ -276,7 +276,7 @@ func TestReadPacketFail(t *testing.T) { // fail to read body conn.maxReads = 1 _, err = mc.readPacket() - if err != driver.ErrBadConn { - t.Errorf("expected ErrBadConn, got %v", err) + if err != ErrInvalidConn { + t.Errorf("expected ErrInvalidConn, got %v", err) } } diff --git a/vendor/github.com/go-sql-driver/mysql/rows.go b/vendor/github.com/go-sql-driver/mysql/rows.go index c08255eee..d3b1e2822 100644 --- a/vendor/github.com/go-sql-driver/mysql/rows.go +++ b/vendor/github.com/go-sql-driver/mysql/rows.go @@ -11,19 +11,20 @@ package mysql import ( "database/sql/driver" "io" + "math" + "reflect" ) -type mysqlField struct { - tableName string - name string - flags fieldFlag - fieldType byte - decimals byte +type resultSet struct { + columns []mysqlField + columnNames []string + done bool } type mysqlRows struct { - mc *mysqlConn - columns []mysqlField + mc *mysqlConn + rs resultSet + finish func() } type binaryRows struct { @@ -34,37 +35,86 @@ type textRows struct { mysqlRows } -type emptyRows struct{} - func (rows *mysqlRows) Columns() []string { - columns := make([]string, len(rows.columns)) + if rows.rs.columnNames != nil { + return rows.rs.columnNames + } + + columns := make([]string, len(rows.rs.columns)) if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias { for i := range columns { - if tableName := rows.columns[i].tableName; len(tableName) > 0 { - columns[i] = tableName + "." + rows.columns[i].name + if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 { + columns[i] = tableName + "." + rows.rs.columns[i].name } else { - columns[i] = rows.columns[i].name + columns[i] = rows.rs.columns[i].name } } } else { for i := range columns { - columns[i] = rows.columns[i].name + columns[i] = rows.rs.columns[i].name } } + + rows.rs.columnNames = columns return columns } -func (rows *mysqlRows) Close() error { +func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string { + return rows.rs.columns[i].typeDatabaseName() +} + +// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) { +// return int64(rows.rs.columns[i].length), true +// } + +func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) { + return rows.rs.columns[i].flags&flagNotNULL == 0, true +} + +func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) { + column := rows.rs.columns[i] + decimals := int64(column.decimals) + + switch column.fieldType { + case fieldTypeDecimal, fieldTypeNewDecimal: + if decimals > 0 { + return int64(column.length) - 2, decimals, true + } + return int64(column.length) - 1, decimals, true + case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime: + return decimals, decimals, true + case fieldTypeFloat, fieldTypeDouble: + if decimals == 0x1f { + return math.MaxInt64, math.MaxInt64, true + } + return math.MaxInt64, decimals, true + } + + return 0, 0, false +} + +func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type { + return rows.rs.columns[i].scanType() +} + +func (rows *mysqlRows) Close() (err error) { + if f := rows.finish; f != nil { + f() + rows.finish = nil + } + mc := rows.mc if mc == nil { return nil } - if mc.netConn == nil { - return ErrInvalidConn + if err := mc.error(); err != nil { + return err } // Remove unread packets from stream - err := mc.readUntilEOF() + if !rows.rs.done { + err = mc.readUntilEOF() + } if err == nil { if err = mc.discardResults(); err != nil { return err @@ -75,22 +125,66 @@ func (rows *mysqlRows) Close() error { return err } -func (rows *binaryRows) Next(dest []driver.Value) error { - if mc := rows.mc; mc != nil { - if mc.netConn == nil { - return ErrInvalidConn +func (rows *mysqlRows) HasNextResultSet() (b bool) { + if rows.mc == nil { + return false + } + return rows.mc.status&statusMoreResultsExists != 0 +} + +func (rows *mysqlRows) nextResultSet() (int, error) { + if rows.mc == nil { + return 0, io.EOF + } + if err := rows.mc.error(); err != nil { + return 0, err + } + + // Remove unread packets from stream + if !rows.rs.done { + if err := rows.mc.readUntilEOF(); err != nil { + return 0, err } + rows.rs.done = true + } - // Fetch next row from stream - return rows.readRow(dest) + if !rows.HasNextResultSet() { + rows.mc = nil + return 0, io.EOF } - return io.EOF + rows.rs = resultSet{} + return rows.mc.readResultSetHeaderPacket() } -func (rows *textRows) Next(dest []driver.Value) error { +func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) { + for { + resLen, err := rows.nextResultSet() + if err != nil { + return 0, err + } + + if resLen > 0 { + return resLen, nil + } + + rows.rs.done = true + } +} + +func (rows *binaryRows) NextResultSet() error { + resLen, err := rows.nextNotEmptyResultSet() + if err != nil { + return err + } + + rows.rs.columns, err = rows.mc.readColumns(resLen) + return err +} + +func (rows *binaryRows) Next(dest []driver.Value) error { if mc := rows.mc; mc != nil { - if mc.netConn == nil { - return ErrInvalidConn + if err := mc.error(); err != nil { + return err } // Fetch next row from stream @@ -99,14 +193,24 @@ func (rows *textRows) Next(dest []driver.Value) error { return io.EOF } -func (rows emptyRows) Columns() []string { - return nil -} +func (rows *textRows) NextResultSet() (err error) { + resLen, err := rows.nextNotEmptyResultSet() + if err != nil { + return err + } -func (rows emptyRows) Close() error { - return nil + rows.rs.columns, err = rows.mc.readColumns(resLen) + return err } -func (rows emptyRows) Next(dest []driver.Value) error { +func (rows *textRows) Next(dest []driver.Value) error { + if mc := rows.mc; mc != nil { + if err := mc.error(); err != nil { + return err + } + + // Fetch next row from stream + return rows.readRow(dest) + } return io.EOF } diff --git a/vendor/github.com/go-sql-driver/mysql/statement.go b/vendor/github.com/go-sql-driver/mysql/statement.go index 7f9b04585..98e57bcd8 100644 --- a/vendor/github.com/go-sql-driver/mysql/statement.go +++ b/vendor/github.com/go-sql-driver/mysql/statement.go @@ -11,6 +11,7 @@ package mysql import ( "database/sql/driver" "fmt" + "io" "reflect" "strconv" ) @@ -19,11 +20,10 @@ type mysqlStmt struct { mc *mysqlConn id uint32 paramCount int - columns []mysqlField // cached from the first query } func (stmt *mysqlStmt) Close() error { - if stmt.mc == nil || stmt.mc.netConn == nil { + if stmt.mc == nil || stmt.mc.closed.IsSet() { // driver.Stmt.Close can be called more than once, thus this function // has to be idempotent. // See also Issue #450 and golang/go#16019. @@ -45,14 +45,14 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter { } func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { - if stmt.mc.netConn == nil { + if stmt.mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { - return nil, err + return nil, stmt.mc.markBadConn(err) } mc := stmt.mc @@ -62,37 +62,45 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) { // Read Result resLen, err := mc.readResultSetHeaderPacket() - if err == nil { - if resLen > 0 { - // Columns - err = mc.readUntilEOF() - if err != nil { - return nil, err - } - - // Rows - err = mc.readUntilEOF() + if err != nil { + return nil, err + } + + if resLen > 0 { + // Columns + if err = mc.readUntilEOF(); err != nil { + return nil, err } - if err == nil { - return &mysqlResult{ - affectedRows: int64(mc.affectedRows), - insertId: int64(mc.insertId), - }, nil + + // Rows + if err := mc.readUntilEOF(); err != nil { + return nil, err } } - return nil, err + if err := mc.discardResults(); err != nil { + return nil, err + } + + return &mysqlResult{ + affectedRows: int64(mc.affectedRows), + insertId: int64(mc.insertId), + }, nil } func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { - if stmt.mc.netConn == nil { + return stmt.query(args) +} + +func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) { + if stmt.mc.closed.IsSet() { errLog.Print(ErrInvalidConn) return nil, driver.ErrBadConn } // Send command err := stmt.writeExecutePacket(args) if err != nil { - return nil, err + return nil, stmt.mc.markBadConn(err) } mc := stmt.mc @@ -107,14 +115,15 @@ func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) { if resLen > 0 { rows.mc = mc - // Columns - // If not cached, read them and cache them - if stmt.columns == nil { - rows.columns, err = mc.readColumns(resLen) - stmt.columns = rows.columns - } else { - rows.columns = stmt.columns - err = mc.readUntilEOF() + rows.rs.columns, err = mc.readColumns(resLen) + } else { + rows.rs.done = true + + switch err := rows.NextResultSet(); err { + case nil, io.EOF: + return rows, nil + default: + return nil, err } } @@ -128,6 +137,12 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) { return v, nil } + if v != nil { + if valuer, ok := v.(driver.Valuer); ok { + return valuer.Value() + } + } + rv := reflect.ValueOf(v) switch rv.Kind() { case reflect.Ptr: @@ -148,6 +163,16 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) { return int64(u64), nil case reflect.Float32, reflect.Float64: return rv.Float(), nil + case reflect.Bool: + return rv.Bool(), nil + case reflect.Slice: + ek := rv.Type().Elem().Kind() + if ek == reflect.Uint8 { + return rv.Bytes(), nil + } + return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek) + case reflect.String: + return rv.String(), nil } return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind()) } diff --git a/vendor/github.com/go-sql-driver/mysql/statement_test.go b/vendor/github.com/go-sql-driver/mysql/statement_test.go new file mode 100644 index 000000000..98a6c1933 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/statement_test.go @@ -0,0 +1,126 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +package mysql + +import ( + "bytes" + "testing" +) + +func TestConvertDerivedString(t *testing.T) { + type derived string + + output, err := converter{}.ConvertValue(derived("value")) + if err != nil { + t.Fatal("Derived string type not convertible", err) + } + + if output != "value" { + t.Fatalf("Derived string type not converted, got %#v %T", output, output) + } +} + +func TestConvertDerivedByteSlice(t *testing.T) { + type derived []uint8 + + output, err := converter{}.ConvertValue(derived("value")) + if err != nil { + t.Fatal("Byte slice not convertible", err) + } + + if bytes.Compare(output.([]byte), []byte("value")) != 0 { + t.Fatalf("Byte slice not converted, got %#v %T", output, output) + } +} + +func TestConvertDerivedUnsupportedSlice(t *testing.T) { + type derived []int + + _, err := converter{}.ConvertValue(derived{1}) + if err == nil || err.Error() != "unsupported type mysql.derived, a slice of int" { + t.Fatal("Unexpected error", err) + } +} + +func TestConvertDerivedBool(t *testing.T) { + type derived bool + + output, err := converter{}.ConvertValue(derived(true)) + if err != nil { + t.Fatal("Derived bool type not convertible", err) + } + + if output != true { + t.Fatalf("Derived bool type not converted, got %#v %T", output, output) + } +} + +func TestConvertPointer(t *testing.T) { + str := "value" + + output, err := converter{}.ConvertValue(&str) + if err != nil { + t.Fatal("Pointer type not convertible", err) + } + + if output != "value" { + t.Fatalf("Pointer type not converted, got %#v %T", output, output) + } +} + +func TestConvertSignedIntegers(t *testing.T) { + values := []interface{}{ + int8(-42), + int16(-42), + int32(-42), + int64(-42), + int(-42), + } + + for _, value := range values { + output, err := converter{}.ConvertValue(value) + if err != nil { + t.Fatalf("%T type not convertible %s", value, err) + } + + if output != int64(-42) { + t.Fatalf("%T type not converted, got %#v %T", value, output, output) + } + } +} + +func TestConvertUnsignedIntegers(t *testing.T) { + values := []interface{}{ + uint8(42), + uint16(42), + uint32(42), + uint64(42), + uint(42), + } + + for _, value := range values { + output, err := converter{}.ConvertValue(value) + if err != nil { + t.Fatalf("%T type not convertible %s", value, err) + } + + if output != int64(42) { + t.Fatalf("%T type not converted, got %#v %T", value, output, output) + } + } + + output, err := converter{}.ConvertValue(^uint64(0)) + if err != nil { + t.Fatal("uint64 high-bit not convertible", err) + } + + if output != "18446744073709551615" { + t.Fatalf("uint64 high-bit not converted, got %#v %T", output, output) + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/transaction.go b/vendor/github.com/go-sql-driver/mysql/transaction.go index 33c749b35..417d72793 100644 --- a/vendor/github.com/go-sql-driver/mysql/transaction.go +++ b/vendor/github.com/go-sql-driver/mysql/transaction.go @@ -13,7 +13,7 @@ type mysqlTx struct { } func (tx *mysqlTx) Commit() (err error) { - if tx.mc == nil || tx.mc.netConn == nil { + if tx.mc == nil || tx.mc.closed.IsSet() { return ErrInvalidConn } err = tx.mc.exec("COMMIT") @@ -22,7 +22,7 @@ func (tx *mysqlTx) Commit() (err error) { } func (tx *mysqlTx) Rollback() (err error) { - if tx.mc == nil || tx.mc.netConn == nil { + if tx.mc == nil || tx.mc.closed.IsSet() { return ErrInvalidConn } err = tx.mc.exec("ROLLBACK") diff --git a/vendor/github.com/go-sql-driver/mysql/utils.go b/vendor/github.com/go-sql-driver/mysql/utils.go index d523b7ffd..a92a4029b 100644 --- a/vendor/github.com/go-sql-driver/mysql/utils.go +++ b/vendor/github.com/go-sql-driver/mysql/utils.go @@ -16,16 +16,21 @@ import ( "fmt" "io" "strings" + "sync" + "sync/atomic" "time" ) var ( + tlsConfigLock sync.RWMutex tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs ) // RegisterTLSConfig registers a custom tls.Config to be used with sql.Open. // Use the key as a value in the DSN where tls=value. // +// Note: The tls.Config provided to needs to be exclusively owned by the driver after registering. +// // rootCertPool := x509.NewCertPool() // pem, err := ioutil.ReadFile("/path/ca-cert.pem") // if err != nil { @@ -51,19 +56,32 @@ func RegisterTLSConfig(key string, config *tls.Config) error { return fmt.Errorf("key '%s' is reserved", key) } + tlsConfigLock.Lock() if tlsConfigRegister == nil { tlsConfigRegister = make(map[string]*tls.Config) } tlsConfigRegister[key] = config + tlsConfigLock.Unlock() return nil } // DeregisterTLSConfig removes the tls.Config associated with key. func DeregisterTLSConfig(key string) { + tlsConfigLock.Lock() if tlsConfigRegister != nil { delete(tlsConfigRegister, key) } + tlsConfigLock.Unlock() +} + +func getTLSConfigClone(key string) (config *tls.Config) { + tlsConfigLock.RLock() + if v, ok := tlsConfigRegister[key]; ok { + config = cloneTLSConfig(v) + } + tlsConfigLock.RUnlock() + return } // Returns the bool value of the input. @@ -548,8 +566,8 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) { if len(b) == 0 { return 0, true, 1 } - switch b[0] { + switch b[0] { // 251: NULL case 0xfb: return 0, true, 1 @@ -738,3 +756,67 @@ func escapeStringQuotes(buf []byte, v string) []byte { return buf[:pos] } + +/****************************************************************************** +* Sync utils * +******************************************************************************/ + +// noCopy may be embedded into structs which must not be copied +// after the first use. +// +// See https://github.com/golang/go/issues/8005#issuecomment-190753527 +// for details. +type noCopy struct{} + +// Lock is a no-op used by -copylocks checker from `go vet`. +func (*noCopy) Lock() {} + +// atomicBool is a wrapper around uint32 for usage as a boolean value with +// atomic access. +type atomicBool struct { + _noCopy noCopy + value uint32 +} + +// IsSet returns wether the current boolean value is true +func (ab *atomicBool) IsSet() bool { + return atomic.LoadUint32(&ab.value) > 0 +} + +// Set sets the value of the bool regardless of the previous value +func (ab *atomicBool) Set(value bool) { + if value { + atomic.StoreUint32(&ab.value, 1) + } else { + atomic.StoreUint32(&ab.value, 0) + } +} + +// TrySet sets the value of the bool and returns wether the value changed +func (ab *atomicBool) TrySet(value bool) bool { + if value { + return atomic.SwapUint32(&ab.value, 1) == 0 + } + return atomic.SwapUint32(&ab.value, 0) > 0 +} + +// atomicBool is a wrapper for atomically accessed error values +type atomicError struct { + _noCopy noCopy + value atomic.Value +} + +// Set sets the error value regardless of the previous value. +// The value must not be nil +func (ae *atomicError) Set(value error) { + ae.value.Store(value) +} + +// Value returns the current error value +func (ae *atomicError) Value() error { + if v := ae.value.Load(); v != nil { + // this will panic if the value doesn't implement the error interface + return v.(error) + } + return nil +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go17.go b/vendor/github.com/go-sql-driver/mysql/utils_go17.go new file mode 100644 index 000000000..f59563456 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go17.go @@ -0,0 +1,40 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.7 +// +build !go1.8 + +package mysql + +import "crypto/tls" + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return &tls.Config{ + Rand: c.Rand, + Time: c.Time, + Certificates: c.Certificates, + NameToCertificate: c.NameToCertificate, + GetCertificate: c.GetCertificate, + RootCAs: c.RootCAs, + NextProtos: c.NextProtos, + ServerName: c.ServerName, + ClientAuth: c.ClientAuth, + ClientCAs: c.ClientCAs, + InsecureSkipVerify: c.InsecureSkipVerify, + CipherSuites: c.CipherSuites, + PreferServerCipherSuites: c.PreferServerCipherSuites, + SessionTicketsDisabled: c.SessionTicketsDisabled, + SessionTicketKey: c.SessionTicketKey, + ClientSessionCache: c.ClientSessionCache, + MinVersion: c.MinVersion, + MaxVersion: c.MaxVersion, + CurvePreferences: c.CurvePreferences, + DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled, + Renegotiation: c.Renegotiation, + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go18.go b/vendor/github.com/go-sql-driver/mysql/utils_go18.go new file mode 100644 index 000000000..7d8c9b16e --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go18.go @@ -0,0 +1,49 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "crypto/tls" + "database/sql" + "database/sql/driver" + "errors" +) + +func cloneTLSConfig(c *tls.Config) *tls.Config { + return c.Clone() +} + +func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) { + dargs := make([]driver.Value, len(named)) + for n, param := range named { + if len(param.Name) > 0 { + // TODO: support the use of Named Parameters #561 + return nil, errors.New("mysql: driver does not support the use of Named Parameters") + } + dargs[n] = param.Value + } + return dargs, nil +} + +func mapIsolationLevel(level driver.IsolationLevel) (string, error) { + switch sql.IsolationLevel(level) { + case sql.LevelRepeatableRead: + return "REPEATABLE READ", nil + case sql.LevelReadCommitted: + return "READ COMMITTED", nil + case sql.LevelReadUncommitted: + return "READ UNCOMMITTED", nil + case sql.LevelSerializable: + return "SERIALIZABLE", nil + default: + return "", errors.New("mysql: unsupported isolation level: " + string(level)) + } +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_go18_test.go b/vendor/github.com/go-sql-driver/mysql/utils_go18_test.go new file mode 100644 index 000000000..856c25f56 --- /dev/null +++ b/vendor/github.com/go-sql-driver/mysql/utils_go18_test.go @@ -0,0 +1,54 @@ +// Go MySQL Driver - A MySQL-Driver for Go's database/sql package +// +// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved. +// +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this file, +// You can obtain one at http://mozilla.org/MPL/2.0/. + +// +build go1.8 + +package mysql + +import ( + "database/sql" + "database/sql/driver" + "testing" +) + +func TestIsolationLevelMapping(t *testing.T) { + + data := []struct { + level driver.IsolationLevel + expected string + }{ + { + level: driver.IsolationLevel(sql.LevelReadCommitted), + expected: "READ COMMITTED", + }, + { + level: driver.IsolationLevel(sql.LevelRepeatableRead), + expected: "REPEATABLE READ", + }, + { + level: driver.IsolationLevel(sql.LevelReadUncommitted), + expected: "READ UNCOMMITTED", + }, + { + level: driver.IsolationLevel(sql.LevelSerializable), + expected: "SERIALIZABLE", + }, + } + + for i, td := range data { + if actual, err := mapIsolationLevel(td.level); actual != td.expected || err != nil { + t.Fatal(i, td.expected, actual, err) + } + } + + // check unsupported mapping + if actual, err := mapIsolationLevel(driver.IsolationLevel(sql.LevelLinearizable)); actual != "" || err == nil { + t.Fatal("Expected error on unsupported isolation level") + } + +} diff --git a/vendor/github.com/go-sql-driver/mysql/utils_test.go b/vendor/github.com/go-sql-driver/mysql/utils_test.go index 0d6c6684f..0041892db 100644 --- a/vendor/github.com/go-sql-driver/mysql/utils_test.go +++ b/vendor/github.com/go-sql-driver/mysql/utils_test.go @@ -195,3 +195,83 @@ func TestEscapeQuotes(t *testing.T) { expect("foo''bar", "foo'bar") // affected expect("foo\"bar", "foo\"bar") // not affected } + +func TestAtomicBool(t *testing.T) { + var ab atomicBool + if ab.IsSet() { + t.Fatal("Expected value to be false") + } + + ab.Set(true) + if ab.value != 1 { + t.Fatal("Set(true) did not set value to 1") + } + if !ab.IsSet() { + t.Fatal("Expected value to be true") + } + + ab.Set(true) + if !ab.IsSet() { + t.Fatal("Expected value to be true") + } + + ab.Set(false) + if ab.value != 0 { + t.Fatal("Set(false) did not set value to 0") + } + if ab.IsSet() { + t.Fatal("Expected value to be false") + } + + ab.Set(false) + if ab.IsSet() { + t.Fatal("Expected value to be false") + } + if ab.TrySet(false) { + t.Fatal("Expected TrySet(false) to fail") + } + if !ab.TrySet(true) { + t.Fatal("Expected TrySet(true) to succeed") + } + if !ab.IsSet() { + t.Fatal("Expected value to be true") + } + + ab.Set(true) + if !ab.IsSet() { + t.Fatal("Expected value to be true") + } + if ab.TrySet(true) { + t.Fatal("Expected TrySet(true) to fail") + } + if !ab.TrySet(false) { + t.Fatal("Expected TrySet(false) to succeed") + } + if ab.IsSet() { + t.Fatal("Expected value to be false") + } + + ab._noCopy.Lock() // we've "tested" it ¯\_(ツ)_/¯ +} + +func TestAtomicError(t *testing.T) { + var ae atomicError + if ae.Value() != nil { + t.Fatal("Expected value to be nil") + } + + ae.Set(ErrMalformPkt) + if v := ae.Value(); v != ErrMalformPkt { + if v == nil { + t.Fatal("Value is still nil") + } + t.Fatal("Error did not match") + } + ae.Set(ErrPktSync) + if ae.Value() == ErrMalformPkt { + t.Fatal("Error still matches old error") + } + if v := ae.Value(); v != ErrPktSync { + t.Fatal("Error did not match") + } +} diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go index dfdfc5b30..110ae1384 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb.go @@ -193,7 +193,8 @@ func (m *Marshaler) marshalObject(out *errWriter, v proto.Message, indent, typeU // "Generated output always contains 3, 6, or 9 fractional digits, // depending on required precision." s, ns := s.Field(0).Int(), s.Field(1).Int() - x := fmt.Sprintf("%d.%09d", s, ns) + d := time.Duration(s)*time.Second + time.Duration(ns)*time.Nanosecond + x := fmt.Sprintf("%.9f", d.Seconds()) x = strings.TrimSuffix(x, "000") x = strings.TrimSuffix(x, "000") out.write(`"`) diff --git a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go index 4fdbde15a..2428d0566 100644 --- a/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go +++ b/vendor/github.com/golang/protobuf/jsonpb/jsonpb_test.go @@ -407,7 +407,6 @@ var marshalingTests = []struct { {"Any with WKT", marshaler, anyWellKnown, anyWellKnownJSON}, {"Any with WKT and indent", marshalerAllOptions, anyWellKnown, anyWellKnownPrettyJSON}, {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 3}}, `{"dur":"3.000s"}`}, - {"Duration", marshaler, &pb.KnownTypes{Dur: &durpb.Duration{Seconds: 100000000, Nanos: 1}}, `{"dur":"100000000.000000001s"}`}, {"Struct", marshaler, &pb.KnownTypes{St: &stpb.Struct{ Fields: map[string]*stpb.Value{ "one": {Kind: &stpb.Value_StringValue{"loneliest number"}}, diff --git a/vendor/github.com/golang/protobuf/proto/discard.go b/vendor/github.com/golang/protobuf/proto/discard.go new file mode 100644 index 000000000..bd0e3bb4c --- /dev/null +++ b/vendor/github.com/golang/protobuf/proto/discard.go @@ -0,0 +1,151 @@ +// Go support for Protocol Buffers - Google's data interchange format +// +// Copyright 2017 The Go Authors. All rights reserved. +// https://github.com/golang/protobuf +// +// 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. + +package proto + +import ( + "fmt" + "reflect" + "strings" +) + +// DiscardUnknown recursively discards all unknown fields from this message +// and all embedded messages. +// +// When unmarshaling a message with unrecognized fields, the tags and values +// of such fields are preserved in the Message. This allows a later call to +// marshal to be able to produce a message that continues to have those +// unrecognized fields. To avoid this, DiscardUnknown is used to +// explicitly clear the unknown fields after unmarshaling. +// +// For proto2 messages, the unknown fields of message extensions are only +// discarded from messages that have been accessed via GetExtension. +func DiscardUnknown(m Message) { + discardLegacy(m) +} + +func discardLegacy(m Message) { + v := reflect.ValueOf(m) + if v.Kind() != reflect.Ptr || v.IsNil() { + return + } + v = v.Elem() + if v.Kind() != reflect.Struct { + return + } + t := v.Type() + + for i := 0; i < v.NumField(); i++ { + f := t.Field(i) + if strings.HasPrefix(f.Name, "XXX_") { + continue + } + vf := v.Field(i) + tf := f.Type + + // Unwrap tf to get its most basic type. + var isPointer, isSlice bool + if tf.Kind() == reflect.Slice && tf.Elem().Kind() != reflect.Uint8 { + isSlice = true + tf = tf.Elem() + } + if tf.Kind() == reflect.Ptr { + isPointer = true + tf = tf.Elem() + } + if isPointer && isSlice && tf.Kind() != reflect.Struct { + panic(fmt.Sprintf("%T.%s cannot be a slice of pointers to primitive types", m, f.Name)) + } + + switch tf.Kind() { + case reflect.Struct: + switch { + case !isPointer: + panic(fmt.Sprintf("%T.%s cannot be a direct struct value", m, f.Name)) + case isSlice: // E.g., []*pb.T + for j := 0; j < vf.Len(); j++ { + discardLegacy(vf.Index(j).Interface().(Message)) + } + default: // E.g., *pb.T + discardLegacy(vf.Interface().(Message)) + } + case reflect.Map: + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a map or a slice of map values", m, f.Name)) + default: // E.g., map[K]V + tv := vf.Type().Elem() + if tv.Kind() == reflect.Ptr && tv.Implements(protoMessageType) { // Proto struct (e.g., *T) + for _, key := range vf.MapKeys() { + val := vf.MapIndex(key) + discardLegacy(val.Interface().(Message)) + } + } + } + case reflect.Interface: + // Must be oneof field. + switch { + case isPointer || isSlice: + panic(fmt.Sprintf("%T.%s cannot be a pointer to a interface or a slice of interface values", m, f.Name)) + default: // E.g., test_proto.isCommunique_Union interface + if !vf.IsNil() && f.Tag.Get("protobuf_oneof") != "" { + vf = vf.Elem() // E.g., *test_proto.Communique_Msg + if !vf.IsNil() { + vf = vf.Elem() // E.g., test_proto.Communique_Msg + vf = vf.Field(0) // E.g., Proto struct (e.g., *T) or primitive value + if vf.Kind() == reflect.Ptr { + discardLegacy(vf.Interface().(Message)) + } + } + } + } + } + } + + if vf := v.FieldByName("XXX_unrecognized"); vf.IsValid() { + if vf.Type() != reflect.TypeOf([]byte{}) { + panic("expected XXX_unrecognized to be of type []byte") + } + vf.Set(reflect.ValueOf([]byte(nil))) + } + + // For proto2 messages, only discard unknown fields in message extensions + // that have been accessed via GetExtension. + if em, ok := extendable(m); ok { + // Ignore lock since discardLegacy is not concurrency safe. + emm, _ := em.extensionsRead() + for _, mx := range emm { + if m, ok := mx.value.(Message); ok { + discardLegacy(m) + } + } + } +} diff --git a/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md new file mode 100644 index 000000000..232be82e4 --- /dev/null +++ b/vendor/github.com/gorilla/mux/ISSUE_TEMPLATE.md @@ -0,0 +1,11 @@ +**What version of Go are you running?** (Paste the output of `go version`) + + +**What version of gorilla/mux are you at?** (Paste the output of `git rev-parse HEAD` inside `$GOPATH/src/github.com/gorilla/mux`) + + +**Describe your problem** (and what you have tried so far) + + +**Paste a minimal, runnable, reproduction of your issue below** (use backticks to format it) + diff --git a/vendor/github.com/gorilla/mux/README.md b/vendor/github.com/gorilla/mux/README.md index 67a79e00a..f9b3103f0 100644 --- a/vendor/github.com/gorilla/mux/README.md +++ b/vendor/github.com/gorilla/mux/README.md @@ -27,6 +27,8 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv * [Static Files](#static-files) * [Registered URLs](#registered-urls) * [Walking Routes](#walking-routes) +* [Graceful Shutdown](#graceful-shutdown) +* [Middleware](#middleware) * [Full Example](#full-example) --- @@ -45,11 +47,11 @@ Let's start registering a couple of URL paths and handlers: ```go func main() { - r := mux.NewRouter() - r.HandleFunc("/", HomeHandler) - r.HandleFunc("/products", ProductsHandler) - r.HandleFunc("/articles", ArticlesHandler) - http.Handle("/", r) + r := mux.NewRouter() + r.HandleFunc("/", HomeHandler) + r.HandleFunc("/products", ProductsHandler) + r.HandleFunc("/articles", ArticlesHandler) + http.Handle("/", r) } ``` @@ -68,9 +70,9 @@ The names are used to create a map of route variables which can be retrieved cal ```go func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { - vars := mux.Vars(r) - w.WriteHeader(http.StatusOK) - fmt.Fprintf(w, "Category: %v\n", vars["category"]) + vars := mux.Vars(r) + w.WriteHeader(http.StatusOK) + fmt.Fprintf(w, "Category: %v\n", vars["category"]) } ``` @@ -122,7 +124,7 @@ r.Queries("key", "value") ```go r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { - return r.ProtoMajor == 0 + return r.ProtoMajor == 0 }) ``` @@ -243,24 +245,24 @@ request that matches "/static/*". This makes it easy to serve static files with ```go func main() { - var dir string + var dir string - flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") - flag.Parse() - r := mux.NewRouter() + flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") + flag.Parse() + r := mux.NewRouter() - // This will serve files under http://localhost:8000/static/ - r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) + // This will serve files under http://localhost:8000/static/ + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) - srv := &http.Server{ - Handler: r, - Addr: "127.0.0.1:8000", - // Good practice: enforce timeouts for servers you create! - WriteTimeout: 15 * time.Second, - ReadTimeout: 15 * time.Second, - } + srv := &http.Server{ + Handler: r, + Addr: "127.0.0.1:8000", + // Good practice: enforce timeouts for servers you create! + WriteTimeout: 15 * time.Second, + ReadTimeout: 15 * time.Second, + } - log.Fatal(srv.ListenAndServe()) + log.Fatal(srv.ListenAndServe()) } ``` @@ -383,6 +385,149 @@ r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error }) ``` +### Graceful Shutdown + +Go 1.8 introduced the ability to [gracefully shutdown](https://golang.org/doc/go1.8#http_shutdown) a `*http.Server`. Here's how to do that alongside `mux`: + +```go +package main + +import ( + "context" + "flag" + "log" + "net/http" + "os" + "os/signal" + + "github.com/gorilla/mux" +) + +func main() { + var wait time.Duration + flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m") + flag.Parse() + + r := mux.NewRouter() + // Add your routes as needed + + srv := &http.Server{ + Addr: "0.0.0.0:8080", + // Good practice to set timeouts to avoid Slowloris attacks. + WriteTimeout: time.Second * 15, + ReadTimeout: time.Second * 15, + IdleTimeout: time.Second * 60, + Handler: r, // Pass our instance of gorilla/mux in. + } + + // Run our server in a goroutine so that it doesn't block. + go func() { + if err := srv.ListenAndServe(); err != nil { + log.Println(err) + } + }() + + c := make(chan os.Signal, 1) + // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) + // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. + signal.Notify(c, os.Interrupt) + + // Block until we receive our signal. + <-c + + // Create a deadline to wait for. + ctx, cancel := context.WithTimeout(ctx, wait) + // Doesn't block if no connections, but will otherwise wait + // until the timeout deadline. + srv.Shutdown(ctx) + // Optionally, you could run srv.Shutdown in a goroutine and block on + // <-ctx.Done() if your application should wait for other services + // to finalize based on context cancellation. + log.Println("shutting down") + os.Exit(0) +} +``` + +### Middleware + +Mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed in the order they are added if a match is found, including its subrouters. +Middlewares are (typically) small pieces of code which take one request, do something with it, and pass it down to another middleware or the final handler. Some common use cases for middleware are request logging, header manipulation, or `ResponseWriter` hijacking. + +Mux middlewares are defined using the de facto standard type: + +```go +type MiddlewareFunc func(http.Handler) http.Handler +``` + +Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc. This takes advantage of closures being able access variables from the context where they are created, while retaining the signature enforced by the receivers. + +A very basic middleware which logs the URI of the request being handled could be written as: + +```go +func simpleMw(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do stuff here + log.Println(r.RequestURI) + // Call the next handler, which can be another middleware in the chain, or the final handler. + next.ServeHTTP(w, r) + }) +} +``` + +Middlewares can be added to a router using `Router.AddMiddlewareFunc()`: + +```go +r := mux.NewRouter() +r.HandleFunc("/", handler) +r.AddMiddleware(simpleMw) +``` + +A more complex authentication middleware, which maps session token to users, could be written as: + +```go +// Define our struct +type authenticationMiddleware struct { + tokenUsers map[string]string +} + +// Initialize it somewhere +func (amw *authenticationMiddleware) Populate() { + amw.tokenUsers["00000000"] = "user0" + amw.tokenUsers["aaaaaaaa"] = "userA" + amw.tokenUsers["05f717e5"] = "randomUser" + amw.tokenUsers["deadbeef"] = "user0" +} + +// Middleware function, which will be called for each request +func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("X-Session-Token") + + if user, found := amw.tokenUsers[token]; found { + // We found the token in our map + log.Printf("Authenticated user %s\n", user) + // Pass down the request to the next middleware (or final handler) + next.ServeHTTP(w, r) + } else { + // Write an error and stop the handler chain + http.Error(w, "Forbidden", 403) + } + }) +} +``` + +```go +r := mux.NewRouter() +r.HandleFunc("/", handler) + +amw := authenticationMiddleware{} +amw.Populate() + +r.AddMiddlewareFunc(amw.Middleware) +``` + +Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. Middlewares *should* write to `ResponseWriter` if they *are* going to terminate the request, and they *should not* write to `ResponseWriter` if they *are not* going to terminate it. + ## Full Example Here's a complete, runnable example of a small `mux` based server: @@ -391,22 +536,22 @@ Here's a complete, runnable example of a small `mux` based server: package main import ( - "net/http" - "log" - "github.com/gorilla/mux" + "net/http" + "log" + "github.com/gorilla/mux" ) func YourHandler(w http.ResponseWriter, r *http.Request) { - w.Write([]byte("Gorilla!\n")) + w.Write([]byte("Gorilla!\n")) } func main() { - r := mux.NewRouter() - // Routes consist of a path and a handler function. - r.HandleFunc("/", YourHandler) + r := mux.NewRouter() + // Routes consist of a path and a handler function. + r.HandleFunc("/", YourHandler) - // Bind to a port and pass our router in - log.Fatal(http.ListenAndServe(":8000", r)) + // Bind to a port and pass our router in + log.Fatal(http.ListenAndServe(":8000", r)) } ``` diff --git a/vendor/github.com/gorilla/mux/doc.go b/vendor/github.com/gorilla/mux/doc.go index cce30b2f0..013f08898 100644 --- a/vendor/github.com/gorilla/mux/doc.go +++ b/vendor/github.com/gorilla/mux/doc.go @@ -238,5 +238,70 @@ as well: url, err := r.Get("article").URL("subdomain", "news", "category", "technology", "id", "42") + +Since **vX.Y.Z**, mux supports the addition of middlewares to a [Router](https://godoc.org/github.com/gorilla/mux#Router), which are executed if a +match is found (including subrouters). Middlewares are defined using the de facto standard type: + + type MiddlewareFunc func(http.Handler) http.Handler + +Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed to it, and then calls the handler passed as parameter to the MiddlewareFunc (closures can access variables from the context where they are created). + +A very basic middleware which logs the URI of the request being handled could be written as: + + func simpleMw(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + // Do stuff here + log.Println(r.RequestURI) + // Call the next handler, which can be another middleware in the chain, or the final handler. + next.ServeHTTP(w, r) + }) + } + +Middlewares can be added to a router using `Router.Use()`: + + r := mux.NewRouter() + r.HandleFunc("/", handler) + r.AddMiddleware(simpleMw) + +A more complex authentication middleware, which maps session token to users, could be written as: + + // Define our struct + type authenticationMiddleware struct { + tokenUsers map[string]string + } + + // Initialize it somewhere + func (amw *authenticationMiddleware) Populate() { + amw.tokenUsers["00000000"] = "user0" + amw.tokenUsers["aaaaaaaa"] = "userA" + amw.tokenUsers["05f717e5"] = "randomUser" + amw.tokenUsers["deadbeef"] = "user0" + } + + // Middleware function, which will be called for each request + func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + token := r.Header.Get("X-Session-Token") + + if user, found := amw.tokenUsers[token]; found { + // We found the token in our map + log.Printf("Authenticated user %s\n", user) + next.ServeHTTP(w, r) + } else { + http.Error(w, "Forbidden", 403) + } + }) + } + + r := mux.NewRouter() + r.HandleFunc("/", handler) + + amw := authenticationMiddleware{} + amw.Populate() + + r.Use(amw.Middleware) + +Note: The handler chain will be stopped if your middleware doesn't call `next.ServeHTTP()` with the corresponding parameters. This can be used to abort a request if the middleware writer wants to. + */ package mux diff --git a/vendor/github.com/gorilla/mux/example_route_test.go b/vendor/github.com/gorilla/mux/example_route_test.go new file mode 100644 index 000000000..112557071 --- /dev/null +++ b/vendor/github.com/gorilla/mux/example_route_test.go @@ -0,0 +1,51 @@ +package mux_test + +import ( + "fmt" + "net/http" + + "github.com/gorilla/mux" +) + +// This example demonstrates setting a regular expression matcher for +// the header value. A plain word will match any value that contains a +// matching substring as if the pattern was wrapped with `.*`. +func ExampleRoute_HeadersRegexp() { + r := mux.NewRouter() + route := r.NewRoute().HeadersRegexp("Accept", "html") + + req1, _ := http.NewRequest("GET", "example.com", nil) + req1.Header.Add("Accept", "text/plain") + req1.Header.Add("Accept", "text/html") + + req2, _ := http.NewRequest("GET", "example.com", nil) + req2.Header.Set("Accept", "application/xhtml+xml") + + matchInfo := &mux.RouteMatch{} + fmt.Printf("Match: %v %q\n", route.Match(req1, matchInfo), req1.Header["Accept"]) + fmt.Printf("Match: %v %q\n", route.Match(req2, matchInfo), req2.Header["Accept"]) + // Output: + // Match: true ["text/plain" "text/html"] + // Match: true ["application/xhtml+xml"] +} + +// This example demonstrates setting a strict regular expression matcher +// for the header value. Using the start and end of string anchors, the +// value must be an exact match. +func ExampleRoute_HeadersRegexp_exactMatch() { + r := mux.NewRouter() + route := r.NewRoute().HeadersRegexp("Origin", "^https://example.co$") + + yes, _ := http.NewRequest("GET", "example.co", nil) + yes.Header.Set("Origin", "https://example.co") + + no, _ := http.NewRequest("GET", "example.co.uk", nil) + no.Header.Set("Origin", "https://example.co.uk") + + matchInfo := &mux.RouteMatch{} + fmt.Printf("Match: %v %q\n", route.Match(yes, matchInfo), yes.Header["Origin"]) + fmt.Printf("Match: %v %q\n", route.Match(no, matchInfo), no.Header["Origin"]) + // Output: + // Match: true ["https://example.co"] + // Match: false ["https://example.co.uk"] +} diff --git a/vendor/github.com/gorilla/mux/middleware.go b/vendor/github.com/gorilla/mux/middleware.go new file mode 100644 index 000000000..8f898675e --- /dev/null +++ b/vendor/github.com/gorilla/mux/middleware.go @@ -0,0 +1,28 @@ +package mux + +import "net/http" + +// MiddlewareFunc is a function which receives an http.Handler and returns another http.Handler. +// Typically, the returned handler is a closure which does something with the http.ResponseWriter and http.Request passed +// to it, and then calls the handler passed as parameter to the MiddlewareFunc. +type MiddlewareFunc func(http.Handler) http.Handler + +// middleware interface is anything which implements a MiddlewareFunc named Middleware. +type middleware interface { + Middleware(handler http.Handler) http.Handler +} + +// MiddlewareFunc also implements the middleware interface. +func (mw MiddlewareFunc) Middleware(handler http.Handler) http.Handler { + return mw(handler) +} + +// Use appends a MiddlewareFunc to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. +func (r *Router) Use(mwf MiddlewareFunc) { + r.middlewares = append(r.middlewares, mwf) +} + +// useInterface appends a middleware to the chain. Middleware can be used to intercept or otherwise modify requests and/or responses, and are executed in the order that they are applied to the Router. +func (r *Router) useInterface(mw middleware) { + r.middlewares = append(r.middlewares, mw) +} diff --git a/vendor/github.com/gorilla/mux/middleware_test.go b/vendor/github.com/gorilla/mux/middleware_test.go new file mode 100644 index 000000000..93947e8cb --- /dev/null +++ b/vendor/github.com/gorilla/mux/middleware_test.go @@ -0,0 +1,336 @@ +package mux + +import ( + "bytes" + "net/http" + "testing" +) + +type testMiddleware struct { + timesCalled uint +} + +func (tm *testMiddleware) Middleware(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + tm.timesCalled++ + h.ServeHTTP(w, r) + }) +} + +func dummyHandler(w http.ResponseWriter, r *http.Request) {} + +func TestMiddlewareAdd(t *testing.T) { + router := NewRouter() + router.HandleFunc("/", dummyHandler).Methods("GET") + + mw := &testMiddleware{} + + router.useInterface(mw) + if len(router.middlewares) != 1 || router.middlewares[0] != mw { + t.Fatal("Middleware was not added correctly") + } + + router.Use(mw.Middleware) + if len(router.middlewares) != 2 { + t.Fatal("MiddlewareFunc method was not added correctly") + } + + banalMw := func(handler http.Handler) http.Handler { + return handler + } + router.Use(banalMw) + if len(router.middlewares) != 3 { + t.Fatal("MiddlewareFunc method was not added correctly") + } +} + +func TestMiddleware(t *testing.T) { + router := NewRouter() + router.HandleFunc("/", dummyHandler).Methods("GET") + + mw := &testMiddleware{} + router.useInterface(mw) + + rw := NewRecorder() + req := newRequest("GET", "/") + + // Test regular middleware call + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + + // Middleware should not be called for 404 + req = newRequest("GET", "/not/found") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + + // Middleware should not be called if there is a method mismatch + req = newRequest("POST", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + + // Add the middleware again as function + router.Use(mw.Middleware) + req = newRequest("GET", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 3 { + t.Fatalf("Expected %d calls, but got only %d", 3, mw.timesCalled) + } + +} + +func TestMiddlewareSubrouter(t *testing.T) { + router := NewRouter() + router.HandleFunc("/", dummyHandler).Methods("GET") + + subrouter := router.PathPrefix("/sub").Subrouter() + subrouter.HandleFunc("/x", dummyHandler).Methods("GET") + + mw := &testMiddleware{} + subrouter.useInterface(mw) + + rw := NewRecorder() + req := newRequest("GET", "/") + + router.ServeHTTP(rw, req) + if mw.timesCalled != 0 { + t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) + } + + req = newRequest("GET", "/sub/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 0 { + t.Fatalf("Expected %d calls, but got only %d", 0, mw.timesCalled) + } + + req = newRequest("GET", "/sub/x") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + + req = newRequest("GET", "/sub/not/found") + router.ServeHTTP(rw, req) + if mw.timesCalled != 1 { + t.Fatalf("Expected %d calls, but got only %d", 1, mw.timesCalled) + } + + router.useInterface(mw) + + req = newRequest("GET", "/") + router.ServeHTTP(rw, req) + if mw.timesCalled != 2 { + t.Fatalf("Expected %d calls, but got only %d", 2, mw.timesCalled) + } + + req = newRequest("GET", "/sub/x") + router.ServeHTTP(rw, req) + if mw.timesCalled != 4 { + t.Fatalf("Expected %d calls, but got only %d", 4, mw.timesCalled) + } +} + +func TestMiddlewareExecution(t *testing.T) { + mwStr := []byte("Middleware\n") + handlerStr := []byte("Logic\n") + + router := NewRouter() + router.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }) + + rw := NewRecorder() + req := newRequest("GET", "/") + + // Test handler-only call + router.ServeHTTP(rw, req) + + if bytes.Compare(rw.Body.Bytes(), handlerStr) != 0 { + t.Fatal("Handler response is not what it should be") + } + + // Test middleware call + rw = NewRecorder() + + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) + }) + + router.ServeHTTP(rw, req) + if bytes.Compare(rw.Body.Bytes(), append(mwStr, handlerStr...)) != 0 { + t.Fatal("Middleware + handler response is not what it should be") + } +} + +func TestMiddlewareNotFound(t *testing.T) { + mwStr := []byte("Middleware\n") + handlerStr := []byte("Logic\n") + + router := NewRouter() + router.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }) + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) + }) + + // Test not found call with default handler + rw := NewRecorder() + req := newRequest("GET", "/notfound") + + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a 404") + } + + // Test not found call with custom handler + rw = NewRecorder() + req = newRequest("GET", "/notfound") + + router.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Custom 404 handler")) + }) + router.ServeHTTP(rw, req) + + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a custom 404") + } +} + +func TestMiddlewareMethodMismatch(t *testing.T) { + mwStr := []byte("Middleware\n") + handlerStr := []byte("Logic\n") + + router := NewRouter() + router.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }).Methods("GET") + + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) + }) + + // Test method mismatch + rw := NewRecorder() + req := newRequest("POST", "/") + + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + + // Test not found call + rw = NewRecorder() + req = newRequest("POST", "/") + + router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Method not allowed")) + }) + router.ServeHTTP(rw, req) + + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } +} + +func TestMiddlewareNotFoundSubrouter(t *testing.T) { + mwStr := []byte("Middleware\n") + handlerStr := []byte("Logic\n") + + router := NewRouter() + router.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }) + + subrouter := router.PathPrefix("/sub/").Subrouter() + subrouter.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }) + + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) + }) + + // Test not found call for default handler + rw := NewRecorder() + req := newRequest("GET", "/sub/notfound") + + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a 404") + } + + // Test not found call with custom handler + rw = NewRecorder() + req = newRequest("GET", "/sub/notfound") + + subrouter.NotFoundHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Custom 404 handler")) + }) + router.ServeHTTP(rw, req) + + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a custom 404") + } +} + +func TestMiddlewareMethodMismatchSubrouter(t *testing.T) { + mwStr := []byte("Middleware\n") + handlerStr := []byte("Logic\n") + + router := NewRouter() + router.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }) + + subrouter := router.PathPrefix("/sub/").Subrouter() + subrouter.HandleFunc("/", func(w http.ResponseWriter, e *http.Request) { + w.Write(handlerStr) + }).Methods("GET") + + router.Use(func(h http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Write(mwStr) + h.ServeHTTP(w, r) + }) + }) + + // Test method mismatch without custom handler + rw := NewRecorder() + req := newRequest("POST", "/sub/") + + router.ServeHTTP(rw, req) + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } + + // Test method mismatch with custom handler + rw = NewRecorder() + req = newRequest("POST", "/sub/") + + router.MethodNotAllowedHandler = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.Write([]byte("Method not allowed")) + }) + router.ServeHTTP(rw, req) + + if bytes.Contains(rw.Body.Bytes(), mwStr) { + t.Fatal("Middleware was called for a method mismatch") + } +} diff --git a/vendor/github.com/gorilla/mux/mux.go b/vendor/github.com/gorilla/mux/mux.go index 49de78923..efabd2417 100644 --- a/vendor/github.com/gorilla/mux/mux.go +++ b/vendor/github.com/gorilla/mux/mux.go @@ -63,6 +63,8 @@ type Router struct { KeepContext bool // see Router.UseEncodedPath(). This defines a flag for all routes. useEncodedPath bool + // Slice of middlewares to be called after a match is found + middlewares []middleware } // Match attempts to match the given request against the router's registered routes. @@ -79,6 +81,12 @@ type Router struct { func (r *Router) Match(req *http.Request, match *RouteMatch) bool { for _, route := range r.routes { if route.Match(req, match) { + // Build middleware chain if no error was found + if match.MatchErr == nil { + for i := len(r.middlewares) - 1; i >= 0; i-- { + match.Handler = r.middlewares[i].Middleware(match.Handler) + } + } return true } } @@ -147,6 +155,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { if !r.KeepContext { defer contextClear(req) } + handler.ServeHTTP(w, req) } @@ -164,13 +173,18 @@ func (r *Router) GetRoute(name string) *Route { // StrictSlash defines the trailing slash behavior for new routes. The initial // value is false. // -// When true, if the route path is "/path/", accessing "/path" will redirect +// When true, if the route path is "/path/", accessing "/path" will perform a redirect // to the former and vice versa. In other words, your application will always // see the path as specified in the route. // // When false, if the route path is "/path", accessing "/path/" will not match // this route and vice versa. // +// The re-direct is a HTTP 301 (Moved Permanently). Note that when this is set for +// routes with a non-idempotent method (e.g. POST, PUT), the subsequent re-directed +// request will be made as a GET by most clients. Use middleware or client settings +// to modify this behaviour as needed. +// // Special case: when a route sets a path prefix using the PathPrefix() method, // strict slash is ignored for that route because the redirect behavior can't // be determined from a prefix alone. However, any subrouters created from that @@ -196,10 +210,6 @@ func (r *Router) SkipClean(value bool) *Router { // UseEncodedPath tells the router to match the encoded original path // to the routes. // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to". -// This behavior has the drawback of needing to match routes against -// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix) -// to r.URL.Path will not affect routing when this flag is on and thus may -// induce unintended behavior. // // If not called, the router will match the unencoded path to the routes. // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to" diff --git a/vendor/github.com/gorilla/mux/mux_test.go b/vendor/github.com/gorilla/mux/mux_test.go index 6c7e30d19..9e93c9830 100644 --- a/vendor/github.com/gorilla/mux/mux_test.go +++ b/vendor/github.com/gorilla/mux/mux_test.go @@ -25,7 +25,7 @@ func (r *Route) GoString() string { } func (r *routeRegexp) GoString() string { - return fmt.Sprintf("&routeRegexp{template: %q, matchHost: %t, matchQuery: %t, strictSlash: %t, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.matchHost, r.matchQuery, r.strictSlash, r.regexp.String(), r.reverse, r.varsN, r.varsR) + return fmt.Sprintf("&routeRegexp{template: %q, regexpType: %v, options: %v, regexp: regexp.MustCompile(%q), reverse: %q, varsN: %v, varsR: %v", r.template, r.regexpType, r.options, r.regexp.String(), r.reverse, r.varsN, r.varsR) } type routeTest struct { @@ -1967,6 +1967,318 @@ func TestErrMatchNotFound(t *testing.T) { } } +// methodsSubrouterTest models the data necessary for testing handler +// matching for subrouters created after HTTP methods matcher registration. +type methodsSubrouterTest struct { + title string + wantCode int + router *Router + // method is the input into the request and expected response + method string + // input request path + path string + // redirectTo is the expected location path for strict-slash matches + redirectTo string +} + +// methodHandler writes the method string in response. +func methodHandler(method string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + w.Write([]byte(method)) + } +} + +// TestMethodsSubrouterCatchall matches handlers for subrouters where a +// catchall handler is set for a mis-matching method. +func TestMethodsSubrouterCatchall(t *testing.T) { + t.Parallel() + + router := NewRouter() + router.Methods("PATCH").Subrouter().PathPrefix("/").HandlerFunc(methodHandler("PUT")) + router.Methods("GET").Subrouter().HandleFunc("/foo", methodHandler("GET")) + router.Methods("POST").Subrouter().HandleFunc("/foo", methodHandler("POST")) + router.Methods("DELETE").Subrouter().HandleFunc("/foo", methodHandler("DELETE")) + + tests := []methodsSubrouterTest{ + { + title: "match GET handler", + router: router, + path: "http://localhost/foo", + method: "GET", + wantCode: http.StatusOK, + }, + { + title: "match POST handler", + router: router, + method: "POST", + path: "http://localhost/foo", + wantCode: http.StatusOK, + }, + { + title: "match DELETE handler", + router: router, + method: "DELETE", + path: "http://localhost/foo", + wantCode: http.StatusOK, + }, + { + title: "disallow PUT method", + router: router, + method: "PUT", + path: "http://localhost/foo", + wantCode: http.StatusMethodNotAllowed, + }, + } + + for _, test := range tests { + testMethodsSubrouter(t, test) + } +} + +// TestMethodsSubrouterStrictSlash matches handlers on subrouters with +// strict-slash matchers. +func TestMethodsSubrouterStrictSlash(t *testing.T) { + t.Parallel() + + router := NewRouter() + sub := router.PathPrefix("/").Subrouter() + sub.StrictSlash(true).Path("/foo").Methods("GET").Subrouter().HandleFunc("", methodHandler("GET")) + sub.StrictSlash(true).Path("/foo/").Methods("PUT").Subrouter().HandleFunc("/", methodHandler("PUT")) + sub.StrictSlash(true).Path("/foo/").Methods("POST").Subrouter().HandleFunc("/", methodHandler("POST")) + + tests := []methodsSubrouterTest{ + { + title: "match POST handler", + router: router, + method: "POST", + path: "http://localhost/foo/", + wantCode: http.StatusOK, + }, + { + title: "match GET handler", + router: router, + method: "GET", + path: "http://localhost/foo", + wantCode: http.StatusOK, + }, + { + title: "match POST handler, redirect strict-slash", + router: router, + method: "POST", + path: "http://localhost/foo", + redirectTo: "http://localhost/foo/", + wantCode: http.StatusMovedPermanently, + }, + { + title: "match GET handler, redirect strict-slash", + router: router, + method: "GET", + path: "http://localhost/foo/", + redirectTo: "http://localhost/foo", + wantCode: http.StatusMovedPermanently, + }, + { + title: "disallow DELETE method", + router: router, + method: "DELETE", + path: "http://localhost/foo", + wantCode: http.StatusMethodNotAllowed, + }, + } + + for _, test := range tests { + testMethodsSubrouter(t, test) + } +} + +// TestMethodsSubrouterPathPrefix matches handlers on subrouters created +// on a router with a path prefix matcher and method matcher. +func TestMethodsSubrouterPathPrefix(t *testing.T) { + t.Parallel() + + router := NewRouter() + router.PathPrefix("/1").Methods("POST").Subrouter().HandleFunc("/2", methodHandler("POST")) + router.PathPrefix("/1").Methods("DELETE").Subrouter().HandleFunc("/2", methodHandler("DELETE")) + router.PathPrefix("/1").Methods("PUT").Subrouter().HandleFunc("/2", methodHandler("PUT")) + router.PathPrefix("/1").Methods("POST").Subrouter().HandleFunc("/2", methodHandler("POST2")) + + tests := []methodsSubrouterTest{ + { + title: "match first POST handler", + router: router, + method: "POST", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "match DELETE handler", + router: router, + method: "DELETE", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "match PUT handler", + router: router, + method: "PUT", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "disallow PATCH method", + router: router, + method: "PATCH", + path: "http://localhost/1/2", + wantCode: http.StatusMethodNotAllowed, + }, + } + + for _, test := range tests { + testMethodsSubrouter(t, test) + } +} + +// TestMethodsSubrouterSubrouter matches handlers on subrouters produced +// from method matchers registered on a root subrouter. +func TestMethodsSubrouterSubrouter(t *testing.T) { + t.Parallel() + + router := NewRouter() + sub := router.PathPrefix("/1").Subrouter() + sub.Methods("POST").Subrouter().HandleFunc("/2", methodHandler("POST")) + sub.Methods("GET").Subrouter().HandleFunc("/2", methodHandler("GET")) + sub.Methods("PATCH").Subrouter().HandleFunc("/2", methodHandler("PATCH")) + sub.HandleFunc("/2", methodHandler("PUT")).Subrouter().Methods("PUT") + sub.HandleFunc("/2", methodHandler("POST2")).Subrouter().Methods("POST") + + tests := []methodsSubrouterTest{ + { + title: "match first POST handler", + router: router, + method: "POST", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "match GET handler", + router: router, + method: "GET", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "match PATCH handler", + router: router, + method: "PATCH", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "match PUT handler", + router: router, + method: "PUT", + path: "http://localhost/1/2", + wantCode: http.StatusOK, + }, + { + title: "disallow DELETE method", + router: router, + method: "DELETE", + path: "http://localhost/1/2", + wantCode: http.StatusMethodNotAllowed, + }, + } + + for _, test := range tests { + testMethodsSubrouter(t, test) + } +} + +// TestMethodsSubrouterPathVariable matches handlers on matching paths +// with path variables in them. +func TestMethodsSubrouterPathVariable(t *testing.T) { + t.Parallel() + + router := NewRouter() + router.Methods("GET").Subrouter().HandleFunc("/foo", methodHandler("GET")) + router.Methods("POST").Subrouter().HandleFunc("/{any}", methodHandler("POST")) + router.Methods("DELETE").Subrouter().HandleFunc("/1/{any}", methodHandler("DELETE")) + router.Methods("PUT").Subrouter().HandleFunc("/1/{any}", methodHandler("PUT")) + + tests := []methodsSubrouterTest{ + { + title: "match GET handler", + router: router, + method: "GET", + path: "http://localhost/foo", + wantCode: http.StatusOK, + }, + { + title: "match POST handler", + router: router, + method: "POST", + path: "http://localhost/foo", + wantCode: http.StatusOK, + }, + { + title: "match DELETE handler", + router: router, + method: "DELETE", + path: "http://localhost/1/foo", + wantCode: http.StatusOK, + }, + { + title: "match PUT handler", + router: router, + method: "PUT", + path: "http://localhost/1/foo", + wantCode: http.StatusOK, + }, + { + title: "disallow PATCH method", + router: router, + method: "PATCH", + path: "http://localhost/1/foo", + wantCode: http.StatusMethodNotAllowed, + }, + } + + for _, test := range tests { + testMethodsSubrouter(t, test) + } +} + +// testMethodsSubrouter runs an individual methodsSubrouterTest. +func testMethodsSubrouter(t *testing.T, test methodsSubrouterTest) { + // Execute request + req, _ := http.NewRequest(test.method, test.path, nil) + resp := NewRecorder() + test.router.ServeHTTP(resp, req) + + switch test.wantCode { + case http.StatusMethodNotAllowed: + if resp.Code != http.StatusMethodNotAllowed { + t.Errorf(`(%s) Expected "405 Method Not Allowed", but got %d code`, test.title, resp.Code) + } else if matchedMethod := resp.Body.String(); matchedMethod != "" { + t.Errorf(`(%s) Expected "405 Method Not Allowed", but %q handler was called`, test.title, matchedMethod) + } + + case http.StatusMovedPermanently: + if gotLocation := resp.HeaderMap.Get("Location"); gotLocation != test.redirectTo { + t.Errorf("(%s) Expected %q route-match to redirect to %q, but got %q", test.title, test.method, test.redirectTo, gotLocation) + } + + case http.StatusOK: + if matchedMethod := resp.Body.String(); matchedMethod != test.method { + t.Errorf("(%s) Expected %q handler to be called, but %q handler was called", test.title, test.method, matchedMethod) + } + + default: + expectedCodes := []int{http.StatusMethodNotAllowed, http.StatusMovedPermanently, http.StatusOK} + t.Errorf("(%s) Expected wantCode to be one of: %v, but got %d", test.title, expectedCodes, test.wantCode) + } +} + // mapToPairs converts a string map to a slice of string pairs func mapToPairs(m map[string]string) []string { var i int diff --git a/vendor/github.com/gorilla/mux/old_test.go b/vendor/github.com/gorilla/mux/old_test.go index 3751e4727..b228983c4 100644 --- a/vendor/github.com/gorilla/mux/old_test.go +++ b/vendor/github.com/gorilla/mux/old_test.go @@ -681,7 +681,7 @@ func TestNewRegexp(t *testing.T) { } for pattern, paths := range tests { - p, _ = newRouteRegexp(pattern, false, false, false, false, false) + p, _ = newRouteRegexp(pattern, regexpTypePath, routeRegexpOptions{}) for path, result := range paths { matches = p.regexp.FindStringSubmatch(path) if result == nil { diff --git a/vendor/github.com/gorilla/mux/regexp.go b/vendor/github.com/gorilla/mux/regexp.go index e83213b7d..2b57e5627 100644 --- a/vendor/github.com/gorilla/mux/regexp.go +++ b/vendor/github.com/gorilla/mux/regexp.go @@ -14,6 +14,20 @@ import ( "strings" ) +type routeRegexpOptions struct { + strictSlash bool + useEncodedPath bool +} + +type regexpType int + +const ( + regexpTypePath regexpType = 0 + regexpTypeHost regexpType = 1 + regexpTypePrefix regexpType = 2 + regexpTypeQuery regexpType = 3 +) + // newRouteRegexp parses a route template and returns a routeRegexp, // used to match a host, a path or a query string. // @@ -24,7 +38,7 @@ import ( // Previously we accepted only Python-like identifiers for variable // names ([a-zA-Z_][a-zA-Z0-9_]*), but currently the only restriction is that // name and pattern can't be empty, and names can't contain a colon. -func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, useEncodedPath bool) (*routeRegexp, error) { +func newRouteRegexp(tpl string, typ regexpType, options routeRegexpOptions) (*routeRegexp, error) { // Check if it is well-formed. idxs, errBraces := braceIndices(tpl) if errBraces != nil { @@ -34,19 +48,18 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, template := tpl // Now let's parse it. defaultPattern := "[^/]+" - if matchQuery { + if typ == regexpTypeQuery { defaultPattern = ".*" - } else if matchHost { + } else if typ == regexpTypeHost { defaultPattern = "[^.]+" - matchPrefix = false } // Only match strict slash if not matching - if matchPrefix || matchHost || matchQuery { - strictSlash = false + if typ != regexpTypePath { + options.strictSlash = false } // Set a flag for strictSlash. endSlash := false - if strictSlash && strings.HasSuffix(tpl, "/") { + if options.strictSlash && strings.HasSuffix(tpl, "/") { tpl = tpl[:len(tpl)-1] endSlash = true } @@ -88,16 +101,16 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, // Add the remaining. raw := tpl[end:] pattern.WriteString(regexp.QuoteMeta(raw)) - if strictSlash { + if options.strictSlash { pattern.WriteString("[/]?") } - if matchQuery { + if typ == regexpTypeQuery { // Add the default pattern if the query value is empty if queryVal := strings.SplitN(template, "=", 2)[1]; queryVal == "" { pattern.WriteString(defaultPattern) } } - if !matchPrefix { + if typ != regexpTypePrefix { pattern.WriteByte('$') } reverse.WriteString(raw) @@ -118,15 +131,13 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, // Done! return &routeRegexp{ - template: template, - matchHost: matchHost, - matchQuery: matchQuery, - strictSlash: strictSlash, - useEncodedPath: useEncodedPath, - regexp: reg, - reverse: reverse.String(), - varsN: varsN, - varsR: varsR, + template: template, + regexpType: typ, + options: options, + regexp: reg, + reverse: reverse.String(), + varsN: varsN, + varsR: varsR, }, nil } @@ -135,15 +146,10 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash, type routeRegexp struct { // The unmodified template. template string - // True for host match, false for path or query string match. - matchHost bool - // True for query string match, false for path and host match. - matchQuery bool - // The strictSlash value defined on the route, but disabled if PathPrefix was used. - strictSlash bool - // Determines whether to use encoded req.URL.EnscapedPath() or unencoded - // req.URL.Path for path matching - useEncodedPath bool + // The type of match + regexpType regexpType + // Options for matching + options routeRegexpOptions // Expanded regexp. regexp *regexp.Regexp // Reverse template. @@ -156,12 +162,12 @@ type routeRegexp struct { // Match matches the regexp against the URL host or path. func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool { - if !r.matchHost { - if r.matchQuery { + if r.regexpType != regexpTypeHost { + if r.regexpType == regexpTypeQuery { return r.matchQueryString(req) } path := req.URL.Path - if r.useEncodedPath { + if r.options.useEncodedPath { path = req.URL.EscapedPath() } return r.regexp.MatchString(path) @@ -178,7 +184,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) { if !ok { return "", fmt.Errorf("mux: missing route variable %q", v) } - if r.matchQuery { + if r.regexpType == regexpTypeQuery { value = url.QueryEscape(value) } urlValues[k] = value @@ -203,7 +209,7 @@ func (r *routeRegexp) url(values map[string]string) (string, error) { // For a URL with foo=bar&baz=ding, we return only the relevant key // value pair for the routeRegexp. func (r *routeRegexp) getURLQuery(req *http.Request) string { - if !r.matchQuery { + if r.regexpType != regexpTypeQuery { return "" } templateKey := strings.SplitN(r.template, "=", 2)[0] @@ -280,7 +286,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route) if len(matches) > 0 { extractVars(path, matches, v.path.varsN, m.Vars) // Check if we should redirect. - if v.path.strictSlash { + if v.path.options.strictSlash { p1 := strings.HasSuffix(path, "/") p2 := strings.HasSuffix(v.path.template, "/") if p1 != p2 { diff --git a/vendor/github.com/gorilla/mux/route.go b/vendor/github.com/gorilla/mux/route.go index 69aeae791..4ce098d4f 100644 --- a/vendor/github.com/gorilla/mux/route.go +++ b/vendor/github.com/gorilla/mux/route.go @@ -75,6 +75,8 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool { if match.MatchErr == ErrMethodMismatch { // We found a route which matches request method, clear MatchErr match.MatchErr = nil + // Then override the mis-matched handler + match.Handler = r.handler } // Yay, we have a match. Let's collect some info about it. @@ -169,12 +171,12 @@ func (r *Route) addMatcher(m matcher) *Route { } // addRegexpMatcher adds a host or path matcher and builder to a route. -func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery bool) error { +func (r *Route) addRegexpMatcher(tpl string, typ regexpType) error { if r.err != nil { return r.err } r.regexp = r.getRegexpGroup() - if !matchHost && !matchQuery { + if typ == regexpTypePath || typ == regexpTypePrefix { if len(tpl) > 0 && tpl[0] != '/' { return fmt.Errorf("mux: path must start with a slash, got %q", tpl) } @@ -182,7 +184,10 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery tpl = strings.TrimRight(r.regexp.path.template, "/") + tpl } } - rr, err := newRouteRegexp(tpl, matchHost, matchPrefix, matchQuery, r.strictSlash, r.useEncodedPath) + rr, err := newRouteRegexp(tpl, typ, routeRegexpOptions{ + strictSlash: r.strictSlash, + useEncodedPath: r.useEncodedPath, + }) if err != nil { return err } @@ -191,7 +196,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery return err } } - if matchHost { + if typ == regexpTypeHost { if r.regexp.path != nil { if err = uniqueVars(rr.varsN, r.regexp.path.varsN); err != nil { return err @@ -204,7 +209,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery return err } } - if matchQuery { + if typ == regexpTypeQuery { r.regexp.queries = append(r.regexp.queries, rr) } else { r.regexp.path = rr @@ -256,7 +261,8 @@ func (m headerRegexMatcher) Match(r *http.Request, match *RouteMatch) bool { // "X-Requested-With", "XMLHttpRequest") // // The above route will only match if both the request header matches both regular expressions. -// It the value is an empty string, it will match any value if the key is set. +// If the value is an empty string, it will match any value if the key is set. +// Use the start and end of string anchors (^ and $) to match an exact value. func (r *Route) HeadersRegexp(pairs ...string) *Route { if r.err == nil { var headers map[string]*regexp.Regexp @@ -286,7 +292,7 @@ func (r *Route) HeadersRegexp(pairs ...string) *Route { // Variable names must be unique in a given route. They can be retrieved // calling mux.Vars(request). func (r *Route) Host(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, true, false, false) + r.err = r.addRegexpMatcher(tpl, regexpTypeHost) return r } @@ -346,7 +352,7 @@ func (r *Route) Methods(methods ...string) *Route { // Variable names must be unique in a given route. They can be retrieved // calling mux.Vars(request). func (r *Route) Path(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, false, false, false) + r.err = r.addRegexpMatcher(tpl, regexpTypePath) return r } @@ -362,7 +368,7 @@ func (r *Route) Path(tpl string) *Route { // Also note that the setting of Router.StrictSlash() has no effect on routes // with a PathPrefix matcher. func (r *Route) PathPrefix(tpl string) *Route { - r.err = r.addRegexpMatcher(tpl, false, true, false) + r.err = r.addRegexpMatcher(tpl, regexpTypePrefix) return r } @@ -393,7 +399,7 @@ func (r *Route) Queries(pairs ...string) *Route { return nil } for i := 0; i < length; i += 2 { - if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], false, false, true); r.err != nil { + if r.err = r.addRegexpMatcher(pairs[i]+"="+pairs[i+1], regexpTypeQuery); r.err != nil { return r } } diff --git a/vendor/github.com/gorilla/mux/test_helpers.go b/vendor/github.com/gorilla/mux/test_helpers.go new file mode 100644 index 000000000..8b2c4a4c5 --- /dev/null +++ b/vendor/github.com/gorilla/mux/test_helpers.go @@ -0,0 +1,18 @@ +// Copyright 2012 The Gorilla Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package mux + +import "net/http" + +// SetURLVars sets the URL variables for the given request, to be accessed via +// mux.Vars for testing route behaviour. +// +// This API should only be used for testing purposes; it provides a way to +// inject variables into the request context. Alternatively, URL variables +// can be set by making a route that captures the required variables, +// starting a server and sending the request to that server. +func SetURLVars(r *http.Request, val map[string]string) *http.Request { + return setVars(r, val) +} diff --git a/vendor/github.com/gorilla/websocket/.travis.yml b/vendor/github.com/gorilla/websocket/.travis.yml index 3d8d29cf3..9f233f983 100644 --- a/vendor/github.com/gorilla/websocket/.travis.yml +++ b/vendor/github.com/gorilla/websocket/.travis.yml @@ -8,6 +8,7 @@ matrix: - go: 1.6 - go: 1.7 - go: 1.8 + - go: 1.9 - go: tip allow_failures: - go: tip diff --git a/vendor/github.com/gorilla/websocket/client.go b/vendor/github.com/gorilla/websocket/client.go index 43a87c753..934e28e96 100644 --- a/vendor/github.com/gorilla/websocket/client.go +++ b/vendor/github.com/gorilla/websocket/client.go @@ -5,10 +5,8 @@ package websocket import ( - "bufio" "bytes" "crypto/tls" - "encoding/base64" "errors" "io" "io/ioutil" @@ -88,50 +86,6 @@ type Dialer struct { var errMalformedURL = errors.New("malformed ws or wss URL") -// parseURL parses the URL. -// -// This function is a replacement for the standard library url.Parse function. -// In Go 1.4 and earlier, url.Parse loses information from the path. -func parseURL(s string) (*url.URL, error) { - // From the RFC: - // - // ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] - // wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ] - var u url.URL - switch { - case strings.HasPrefix(s, "ws://"): - u.Scheme = "ws" - s = s[len("ws://"):] - case strings.HasPrefix(s, "wss://"): - u.Scheme = "wss" - s = s[len("wss://"):] - default: - return nil, errMalformedURL - } - - if i := strings.Index(s, "?"); i >= 0 { - u.RawQuery = s[i+1:] - s = s[:i] - } - - if i := strings.Index(s, "/"); i >= 0 { - u.Opaque = s[i:] - s = s[:i] - } else { - u.Opaque = "/" - } - - u.Host = s - - if strings.Contains(u.Host, "@") { - // Don't bother parsing user information because user information is - // not allowed in websocket URIs. - return nil, errMalformedURL - } - - return &u, nil -} - func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { hostPort = u.Host hostNoPort = u.Host @@ -150,7 +104,7 @@ func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { return hostPort, hostNoPort } -// DefaultDialer is a dialer with all fields set to the default zero values. +// DefaultDialer is a dialer with all fields set to the default values. var DefaultDialer = &Dialer{ Proxy: http.ProxyFromEnvironment, } @@ -177,7 +131,7 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re return nil, nil, err } - u, err := parseURL(urlStr) + u, err := url.Parse(urlStr) if err != nil { return nil, nil, err } @@ -246,36 +200,52 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re req.Header.Set("Sec-Websocket-Extensions", "permessage-deflate; server_no_context_takeover; client_no_context_takeover") } - hostPort, hostNoPort := hostPortNoPort(u) - - var proxyURL *url.URL - // Check wether the proxy method has been configured - if d.Proxy != nil { - proxyURL, err = d.Proxy(req) - } - if err != nil { - return nil, nil, err - } - - var targetHostPort string - if proxyURL != nil { - targetHostPort, _ = hostPortNoPort(proxyURL) - } else { - targetHostPort = hostPort - } - var deadline time.Time if d.HandshakeTimeout != 0 { deadline = time.Now().Add(d.HandshakeTimeout) } + // Get network dial function. netDial := d.NetDial if netDial == nil { netDialer := &net.Dialer{Deadline: deadline} netDial = netDialer.Dial } - netConn, err := netDial("tcp", targetHostPort) + // If needed, wrap the dial function to set the connection deadline. + if !deadline.Equal(time.Time{}) { + forwardDial := netDial + netDial = func(network, addr string) (net.Conn, error) { + c, err := forwardDial(network, addr) + if err != nil { + return nil, err + } + err = c.SetDeadline(deadline) + if err != nil { + c.Close() + return nil, err + } + return c, nil + } + } + + // If needed, wrap the dial function to connect through a proxy. + if d.Proxy != nil { + proxyURL, err := d.Proxy(req) + if err != nil { + return nil, nil, err + } + if proxyURL != nil { + dialer, err := proxy_FromURL(proxyURL, netDialerFunc(netDial)) + if err != nil { + return nil, nil, err + } + netDial = dialer.Dial + } + } + + hostPort, hostNoPort := hostPortNoPort(u) + netConn, err := netDial("tcp", hostPort) if err != nil { return nil, nil, err } @@ -286,42 +256,6 @@ func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Re } }() - if err := netConn.SetDeadline(deadline); err != nil { - return nil, nil, err - } - - if proxyURL != nil { - connectHeader := make(http.Header) - if user := proxyURL.User; user != nil { - proxyUser := user.Username() - if proxyPassword, passwordSet := user.Password(); passwordSet { - credential := base64.StdEncoding.EncodeToString([]byte(proxyUser + ":" + proxyPassword)) - connectHeader.Set("Proxy-Authorization", "Basic "+credential) - } - } - connectReq := &http.Request{ - Method: "CONNECT", - URL: &url.URL{Opaque: hostPort}, - Host: hostPort, - Header: connectHeader, - } - - connectReq.Write(netConn) - - // Read response. - // Okay to use and discard buffered reader here, because - // TLS server will not speak until spoken to. - br := bufio.NewReader(netConn) - resp, err := http.ReadResponse(br, connectReq) - if err != nil { - return nil, nil, err - } - if resp.StatusCode != 200 { - f := strings.SplitN(resp.Status, " ", 2) - return nil, nil, errors.New(f[1]) - } - } - if u.Scheme == "https" { cfg := cloneTLSConfig(d.TLSClientConfig) if cfg.ServerName == "" { diff --git a/vendor/github.com/gorilla/websocket/client_server_test.go b/vendor/github.com/gorilla/websocket/client_server_test.go index 7d39da681..50063b7e0 100644 --- a/vendor/github.com/gorilla/websocket/client_server_test.go +++ b/vendor/github.com/gorilla/websocket/client_server_test.go @@ -5,11 +5,14 @@ package websocket import ( + "bytes" "crypto/tls" "crypto/x509" "encoding/base64" + "encoding/binary" "io" "io/ioutil" + "net" "net/http" "net/http/cookiejar" "net/http/httptest" @@ -31,9 +34,10 @@ var cstUpgrader = Upgrader{ } var cstDialer = Dialer{ - Subprotocols: []string{"p1", "p2"}, - ReadBufferSize: 1024, - WriteBufferSize: 1024, + Subprotocols: []string{"p1", "p2"}, + ReadBufferSize: 1024, + WriteBufferSize: 1024, + HandshakeTimeout: 30 * time.Second, } type cstHandler struct{ *testing.T } @@ -143,8 +147,9 @@ func TestProxyDial(t *testing.T) { s := newServer(t) defer s.Close() - surl, _ := url.Parse(s.URL) + surl, _ := url.Parse(s.Server.URL) + cstDialer := cstDialer // make local copy for modification on next line. cstDialer.Proxy = http.ProxyURL(surl) connect := false @@ -160,8 +165,8 @@ func TestProxyDial(t *testing.T) { } if !connect { - t.Log("connect not recieved") - http.Error(w, "connect not recieved", 405) + t.Log("connect not received") + http.Error(w, "connect not received", 405) return } origHandler.ServeHTTP(w, r) @@ -173,16 +178,16 @@ func TestProxyDial(t *testing.T) { } defer ws.Close() sendRecv(t, ws) - - cstDialer.Proxy = http.ProxyFromEnvironment } func TestProxyAuthorizationDial(t *testing.T) { s := newServer(t) defer s.Close() - surl, _ := url.Parse(s.URL) + surl, _ := url.Parse(s.Server.URL) surl.User = url.UserPassword("username", "password") + + cstDialer := cstDialer // make local copy for modification on next line. cstDialer.Proxy = http.ProxyURL(surl) connect := false @@ -200,8 +205,8 @@ func TestProxyAuthorizationDial(t *testing.T) { } if !connect { - t.Log("connect with proxy authorization not recieved") - http.Error(w, "connect with proxy authorization not recieved", 405) + t.Log("connect with proxy authorization not received") + http.Error(w, "connect with proxy authorization not received", 405) return } origHandler.ServeHTTP(w, r) @@ -213,8 +218,6 @@ func TestProxyAuthorizationDial(t *testing.T) { } defer ws.Close() sendRecv(t, ws) - - cstDialer.Proxy = http.ProxyFromEnvironment } func TestDial(t *testing.T) { @@ -237,7 +240,7 @@ func TestDialCookieJar(t *testing.T) { d := cstDialer d.Jar = jar - u, _ := parseURL(s.URL) + u, _ := url.Parse(s.URL) switch u.Scheme { case "ws": @@ -246,7 +249,7 @@ func TestDialCookieJar(t *testing.T) { u.Scheme = "https" } - cookies := []*http.Cookie{&http.Cookie{Name: "gorilla", Value: "ws", Path: "/"}} + cookies := []*http.Cookie{{Name: "gorilla", Value: "ws", Path: "/"}} d.Jar.SetCookies(u, cookies) ws, _, err := d.Dial(s.URL, nil) @@ -398,9 +401,17 @@ func TestBadMethod(t *testing.T) { })) defer s.Close() - resp, err := http.PostForm(s.URL, url.Values{}) + req, err := http.NewRequest("POST", s.URL, strings.NewReader("")) + if err != nil { + t.Fatalf("NewRequest returned error %v", err) + } + req.Header.Set("Connection", "upgrade") + req.Header.Set("Upgrade", "websocket") + req.Header.Set("Sec-Websocket-Version", "13") + + resp, err := http.DefaultClient.Do(req) if err != nil { - t.Fatalf("PostForm returned error %v", err) + t.Fatalf("Do returned error %v", err) } resp.Body.Close() if resp.StatusCode != http.StatusMethodNotAllowed { @@ -510,3 +521,82 @@ func TestDialCompression(t *testing.T) { defer ws.Close() sendRecv(t, ws) } + +func TestSocksProxyDial(t *testing.T) { + s := newServer(t) + defer s.Close() + + proxyListener, err := net.Listen("tcp", "127.0.0.1:0") + if err != nil { + t.Fatalf("listen failed: %v", err) + } + defer proxyListener.Close() + go func() { + c1, err := proxyListener.Accept() + if err != nil { + t.Errorf("proxy accept failed: %v", err) + return + } + defer c1.Close() + + c1.SetDeadline(time.Now().Add(30 * time.Second)) + + buf := make([]byte, 32) + if _, err := io.ReadFull(c1, buf[:3]); err != nil { + t.Errorf("read failed: %v", err) + return + } + if want := []byte{5, 1, 0}; !bytes.Equal(want, buf[:len(want)]) { + t.Errorf("read %x, want %x", buf[:len(want)], want) + } + if _, err := c1.Write([]byte{5, 0}); err != nil { + t.Errorf("write failed: %v", err) + return + } + if _, err := io.ReadFull(c1, buf[:10]); err != nil { + t.Errorf("read failed: %v", err) + return + } + if want := []byte{5, 1, 0, 1}; !bytes.Equal(want, buf[:len(want)]) { + t.Errorf("read %x, want %x", buf[:len(want)], want) + return + } + buf[1] = 0 + if _, err := c1.Write(buf[:10]); err != nil { + t.Errorf("write failed: %v", err) + return + } + + ip := net.IP(buf[4:8]) + port := binary.BigEndian.Uint16(buf[8:10]) + + c2, err := net.DialTCP("tcp", nil, &net.TCPAddr{IP: ip, Port: int(port)}) + if err != nil { + t.Errorf("dial failed; %v", err) + return + } + defer c2.Close() + done := make(chan struct{}) + go func() { + io.Copy(c1, c2) + close(done) + }() + io.Copy(c2, c1) + <-done + }() + + purl, err := url.Parse("socks5://" + proxyListener.Addr().String()) + if err != nil { + t.Fatalf("parse failed: %v", err) + } + + cstDialer := cstDialer // make local copy for modification on next line. + cstDialer.Proxy = http.ProxyURL(purl) + + ws, _, err := cstDialer.Dial(s.URL, nil) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + sendRecv(t, ws) +} diff --git a/vendor/github.com/gorilla/websocket/client_test.go b/vendor/github.com/gorilla/websocket/client_test.go index 7d2b0844f..5aa27b37d 100644 --- a/vendor/github.com/gorilla/websocket/client_test.go +++ b/vendor/github.com/gorilla/websocket/client_test.go @@ -6,49 +6,9 @@ package websocket import ( "net/url" - "reflect" "testing" ) -var parseURLTests = []struct { - s string - u *url.URL - rui string -}{ - {"ws://example.com/", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"}, - {"ws://example.com", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}, "/"}, - {"ws://example.com:7777/", &url.URL{Scheme: "ws", Host: "example.com:7777", Opaque: "/"}, "/"}, - {"wss://example.com/", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/"}, "/"}, - {"wss://example.com/a/b", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b"}, "/a/b"}, - {"ss://example.com/a/b", nil, ""}, - {"ws://webmaster@example.com/", nil, ""}, - {"wss://example.com/a/b?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b", RawQuery: "x=y"}, "/a/b?x=y"}, - {"wss://example.com?x=y", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/", RawQuery: "x=y"}, "/?x=y"}, -} - -func TestParseURL(t *testing.T) { - for _, tt := range parseURLTests { - u, err := parseURL(tt.s) - if tt.u != nil && err != nil { - t.Errorf("parseURL(%q) returned error %v", tt.s, err) - continue - } - if tt.u == nil { - if err == nil { - t.Errorf("parseURL(%q) did not return error", tt.s) - } - continue - } - if !reflect.DeepEqual(u, tt.u) { - t.Errorf("parseURL(%q) = %v, want %v", tt.s, u, tt.u) - continue - } - if u.RequestURI() != tt.rui { - t.Errorf("parseURL(%q).RequestURI() = %v, want %v", tt.s, u.RequestURI(), tt.rui) - } - } -} - var hostPortNoPortTests = []struct { u *url.URL hostPort, hostNoPort string diff --git a/vendor/github.com/gorilla/websocket/conn.go b/vendor/github.com/gorilla/websocket/conn.go index 97e1dbacb..cd3569d53 100644 --- a/vendor/github.com/gorilla/websocket/conn.go +++ b/vendor/github.com/gorilla/websocket/conn.go @@ -76,7 +76,7 @@ const ( // is UTF-8 encoded text. PingMessage = 9 - // PongMessage denotes a ping control message. The optional message payload + // PongMessage denotes a pong control message. The optional message payload // is UTF-8 encoded text. PongMessage = 10 ) @@ -100,9 +100,8 @@ func (e *netError) Error() string { return e.msg } func (e *netError) Temporary() bool { return e.temporary } func (e *netError) Timeout() bool { return e.timeout } -// CloseError represents close frame. +// CloseError represents a close message. type CloseError struct { - // Code is defined in RFC 6455, section 11.7. Code int @@ -343,7 +342,8 @@ func (c *Conn) Subprotocol() string { return c.subprotocol } -// Close closes the underlying network connection without sending or waiting for a close frame. +// Close closes the underlying network connection without sending or waiting +// for a close message. func (c *Conn) Close() error { return c.conn.Close() } @@ -484,6 +484,9 @@ func (c *Conn) prepWrite(messageType int) error { // // There can be at most one open writer on a connection. NextWriter closes the // previous writer if the application has not already done so. +// +// All message types (TextMessage, BinaryMessage, CloseMessage, PingMessage and +// PongMessage) are supported. func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { if err := c.prepWrite(messageType); err != nil { return nil, err @@ -764,7 +767,6 @@ func (c *Conn) SetWriteDeadline(t time.Time) error { // Read methods func (c *Conn) advanceFrame() (int, error) { - // 1. Skip remainder of previous frame. if c.readRemaining > 0 { @@ -1033,7 +1035,7 @@ func (c *Conn) SetReadDeadline(t time.Time) error { } // SetReadLimit sets the maximum size for a message read from the peer. If a -// message exceeds the limit, the connection sends a close frame to the peer +// message exceeds the limit, the connection sends a close message to the peer // and returns ErrReadLimit to the application. func (c *Conn) SetReadLimit(limit int64) { c.readLimit = limit @@ -1046,24 +1048,21 @@ func (c *Conn) CloseHandler() func(code int, text string) error { // SetCloseHandler sets the handler for close messages received from the peer. // The code argument to h is the received close code or CloseNoStatusReceived -// if the close message is empty. The default close handler sends a close frame -// back to the peer. +// if the close message is empty. The default close handler sends a close +// message back to the peer. // // The application must read the connection to process close messages as -// described in the section on Control Frames above. +// described in the section on Control Messages above. // -// The connection read methods return a CloseError when a close frame is +// The connection read methods return a CloseError when a close message is // received. Most applications should handle close messages as part of their // normal error handling. Applications should only set a close handler when the -// application must perform some action before sending a close frame back to +// application must perform some action before sending a close message back to // the peer. func (c *Conn) SetCloseHandler(h func(code int, text string) error) { if h == nil { h = func(code int, text string) error { - message := []byte{} - if code != CloseNoStatusReceived { - message = FormatCloseMessage(code, "") - } + message := FormatCloseMessage(code, "") c.WriteControl(CloseMessage, message, time.Now().Add(writeWait)) return nil } @@ -1077,11 +1076,11 @@ func (c *Conn) PingHandler() func(appData string) error { } // SetPingHandler sets the handler for ping messages received from the peer. -// The appData argument to h is the PING frame application data. The default +// The appData argument to h is the PING message application data. The default // ping handler sends a pong to the peer. // // The application must read the connection to process ping messages as -// described in the section on Control Frames above. +// described in the section on Control Messages above. func (c *Conn) SetPingHandler(h func(appData string) error) { if h == nil { h = func(message string) error { @@ -1103,11 +1102,11 @@ func (c *Conn) PongHandler() func(appData string) error { } // SetPongHandler sets the handler for pong messages received from the peer. -// The appData argument to h is the PONG frame application data. The default +// The appData argument to h is the PONG message application data. The default // pong handler does nothing. // // The application must read the connection to process ping messages as -// described in the section on Control Frames above. +// described in the section on Control Messages above. func (c *Conn) SetPongHandler(h func(appData string) error) { if h == nil { h = func(string) error { return nil } @@ -1141,7 +1140,14 @@ func (c *Conn) SetCompressionLevel(level int) error { } // FormatCloseMessage formats closeCode and text as a WebSocket close message. +// An empty message is returned for code CloseNoStatusReceived. func FormatCloseMessage(closeCode int, text string) []byte { + if closeCode == CloseNoStatusReceived { + // Return empty message because it's illegal to send + // CloseNoStatusReceived. Return non-nil value in case application + // checks for nil. + return []byte{} + } buf := make([]byte, 2+len(text)) binary.BigEndian.PutUint16(buf, uint16(closeCode)) copy(buf[2:], text) diff --git a/vendor/github.com/gorilla/websocket/conn_test.go b/vendor/github.com/gorilla/websocket/conn_test.go index 06e9bc3f5..5fda7b5ca 100644 --- a/vendor/github.com/gorilla/websocket/conn_test.go +++ b/vendor/github.com/gorilla/websocket/conn_test.go @@ -341,7 +341,6 @@ func TestUnderlyingConn(t *testing.T) { } func TestBufioReadBytes(t *testing.T) { - // Test calling bufio.ReadBytes for value longer than read buffer size. m := make([]byte, 512) @@ -366,7 +365,7 @@ func TestBufioReadBytes(t *testing.T) { t.Fatalf("ReadBytes() returned %v", err) } if len(p) != len(m) { - t.Fatalf("read returnd %d bytes, want %d bytes", len(p), len(m)) + t.Fatalf("read returned %d bytes, want %d bytes", len(p), len(m)) } } diff --git a/vendor/github.com/gorilla/websocket/doc.go b/vendor/github.com/gorilla/websocket/doc.go index e291a952c..dcce1a63c 100644 --- a/vendor/github.com/gorilla/websocket/doc.go +++ b/vendor/github.com/gorilla/websocket/doc.go @@ -6,9 +6,8 @@ // // Overview // -// The Conn type represents a WebSocket connection. A server application uses -// the Upgrade function from an Upgrader object with a HTTP request handler -// to get a pointer to a Conn: +// The Conn type represents a WebSocket connection. A server application calls +// the Upgrader.Upgrade method from an HTTP request handler to get a *Conn: // // var upgrader = websocket.Upgrader{ // ReadBufferSize: 1024, @@ -31,10 +30,12 @@ // for { // messageType, p, err := conn.ReadMessage() // if err != nil { +// log.Println(err) // return // } -// if err = conn.WriteMessage(messageType, p); err != nil { -// return err +// if err := conn.WriteMessage(messageType, p); err != nil { +// log.Println(err) +// return // } // } // @@ -85,20 +86,26 @@ // and pong. Call the connection WriteControl, WriteMessage or NextWriter // methods to send a control message to the peer. // -// Connections handle received close messages by sending a close message to the -// peer and returning a *CloseError from the the NextReader, ReadMessage or the -// message Read method. +// Connections handle received close messages by calling the handler function +// set with the SetCloseHandler method and by returning a *CloseError from the +// NextReader, ReadMessage or the message Read method. The default close +// handler sends a close message to the peer. // -// Connections handle received ping and pong messages by invoking callback -// functions set with SetPingHandler and SetPongHandler methods. The callback -// functions are called from the NextReader, ReadMessage and the message Read -// methods. +// Connections handle received ping messages by calling the handler function +// set with the SetPingHandler method. The default ping handler sends a pong +// message to the peer. // -// The default ping handler sends a pong to the peer. The application's reading -// goroutine can block for a short time while the handler writes the pong data -// to the connection. +// Connections handle received pong messages by calling the handler function +// set with the SetPongHandler method. The default pong handler does nothing. +// If an application sends ping messages, then the application should set a +// pong handler to receive the corresponding pong. // -// The application must read the connection to process ping, pong and close +// The control message handler functions are called from the NextReader, +// ReadMessage and message reader Read methods. The default close and ping +// handlers can block these methods for a short time when the handler writes to +// the connection. +// +// The application must read the connection to process close, ping and pong // messages sent from the peer. If the application is not otherwise interested // in messages from the peer, then the application should start a goroutine to // read and discard messages from the peer. A simple example is: @@ -137,19 +144,12 @@ // method fails the WebSocket handshake with HTTP status 403. // // If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail -// the handshake if the Origin request header is present and not equal to the -// Host request header. -// -// An application can allow connections from any origin by specifying a -// function that always returns true: -// -// var upgrader = websocket.Upgrader{ -// CheckOrigin: func(r *http.Request) bool { return true }, -// } +// the handshake if the Origin request header is present and the Origin host is +// not equal to the Host request header. // -// The deprecated Upgrade function does not enforce an origin policy. It's the -// application's responsibility to check the Origin header before calling -// Upgrade. +// The deprecated package-level Upgrade function does not perform origin +// checking. The application is responsible for checking the Origin header +// before calling the Upgrade function. // // Compression EXPERIMENTAL // diff --git a/vendor/github.com/gorilla/websocket/examples/chat/README.md b/vendor/github.com/gorilla/websocket/examples/chat/README.md index 47c82f908..7baf3e328 100644 --- a/vendor/github.com/gorilla/websocket/examples/chat/README.md +++ b/vendor/github.com/gorilla/websocket/examples/chat/README.md @@ -1,6 +1,6 @@ # Chat Example -This application shows how to use use the +This application shows how to use the [websocket](https://github.com/gorilla/websocket) package to implement a simple web chat application. diff --git a/vendor/github.com/gorilla/websocket/examples/chat/client.go b/vendor/github.com/gorilla/websocket/examples/chat/client.go index ecfd9a7aa..9461c1ea0 100644 --- a/vendor/github.com/gorilla/websocket/examples/chat/client.go +++ b/vendor/github.com/gorilla/websocket/examples/chat/client.go @@ -64,7 +64,7 @@ func (c *Client) readPump() { for { _, message, err := c.conn.ReadMessage() if err != nil { - if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway) { + if websocket.IsUnexpectedCloseError(err, websocket.CloseGoingAway, websocket.CloseAbnormalClosure) { log.Printf("error: %v", err) } break @@ -113,7 +113,7 @@ func (c *Client) writePump() { } case <-ticker.C: c.conn.SetWriteDeadline(time.Now().Add(writeWait)) - if err := c.conn.WriteMessage(websocket.PingMessage, []byte{}); err != nil { + if err := c.conn.WriteMessage(websocket.PingMessage, nil); err != nil { return } } diff --git a/vendor/github.com/gorilla/websocket/examples/echo/server.go b/vendor/github.com/gorilla/websocket/examples/echo/server.go index a685b0974..ecc680c8b 100644 --- a/vendor/github.com/gorilla/websocket/examples/echo/server.go +++ b/vendor/github.com/gorilla/websocket/examples/echo/server.go @@ -55,6 +55,7 @@ func main() { var homeTemplate = template.Must(template.New("").Parse(` +