forked from TrueCloudLab/distribution
Fix GCS
Signed-off-by: Olivier Gambier <olivier@docker.com>
This commit is contained in:
parent
59401e277b
commit
d1444b56e9
141 changed files with 19483 additions and 4205 deletions
114
Godeps/Godeps.json
generated
114
Godeps/Godeps.json
generated
|
@ -136,14 +136,6 @@
|
||||||
"Comment": "v1.1.0-14-g49c3892",
|
"Comment": "v1.1.0-14-g49c3892",
|
||||||
"Rev": "49c3892b61af1d4996292a3025f36e4dfa25eaee"
|
"Rev": "49c3892b61af1d4996292a3025f36e4dfa25eaee"
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bradfitz/http2",
|
|
||||||
"Rev": "f8202bc903bda493ebba4aa54922d78430c2c42f"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"ImportPath": "github.com/bradfitz/http2/hpack",
|
|
||||||
"Rev": "f8202bc903bda493ebba4aa54922d78430c2c42f"
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/bugsnag/bugsnag-go",
|
"ImportPath": "github.com/bugsnag/bugsnag-go",
|
||||||
"Comment": "v1.0.2-5-gb1d1530",
|
"Comment": "v1.0.2-5-gb1d1530",
|
||||||
|
@ -202,7 +194,7 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/golang/protobuf/proto",
|
"ImportPath": "github.com/golang/protobuf/proto",
|
||||||
"Rev": "0f7a9caded1fb3c9cc5a9b4bcf2ff633cc8ae644"
|
"Rev": "8d92cf5fc15a4382f8964b08e1f42a75c0591aa3"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "github.com/gorilla/context",
|
"ImportPath": "github.com/gorilla/context",
|
||||||
|
@ -280,91 +272,151 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/context",
|
"ImportPath": "golang.org/x/net/context",
|
||||||
"Rev": "2cba614e8ff920c60240d2677bc019af32ee04e5"
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/context/ctxhttp",
|
||||||
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/http2",
|
||||||
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "golang.org/x/net/http2/hpack",
|
||||||
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/internal/timeseries",
|
"ImportPath": "golang.org/x/net/internal/timeseries",
|
||||||
"Rev": "2cba614e8ff920c60240d2677bc019af32ee04e5"
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/net/trace",
|
"ImportPath": "golang.org/x/net/trace",
|
||||||
"Rev": "2cba614e8ff920c60240d2677bc019af32ee04e5"
|
"Rev": "4876518f9e71663000c348837735820161a42df7"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/oauth2",
|
"ImportPath": "golang.org/x/oauth2",
|
||||||
"Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e"
|
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/oauth2/google",
|
"ImportPath": "golang.org/x/oauth2/google",
|
||||||
"Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e"
|
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/oauth2/internal",
|
"ImportPath": "golang.org/x/oauth2/internal",
|
||||||
"Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e"
|
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/oauth2/jws",
|
"ImportPath": "golang.org/x/oauth2/jws",
|
||||||
"Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e"
|
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "golang.org/x/oauth2/jwt",
|
"ImportPath": "golang.org/x/oauth2/jwt",
|
||||||
"Rev": "8914e5017ca260f2a3a1575b1e6868874050d95e"
|
"Rev": "045497edb6234273d67dbc25da3f2ddbc4c4cacf"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/api/gensupport",
|
||||||
|
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/api/googleapi",
|
"ImportPath": "google.golang.org/api/googleapi",
|
||||||
"Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121"
|
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/api/googleapi/internal/uritemplates",
|
"ImportPath": "google.golang.org/api/googleapi/internal/uritemplates",
|
||||||
"Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121"
|
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/api/storage/v1",
|
"ImportPath": "google.golang.org/api/storage/v1",
|
||||||
"Rev": "18450f4e95c7e76ce3a5dc3a8cb7178ab6d56121"
|
"Rev": "9bf6e6e569ff057f75d9604a46c52928f17d2b54"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/app_identity",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/base",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/datastore",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/log",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/modules",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/appengine/internal/remote_api",
|
||||||
|
"Rev": "12d5545dc1cfa6047a286d5e853841b6471f4c19"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud",
|
"ImportPath": "google.golang.org/cloud",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud/compute/metadata",
|
"ImportPath": "google.golang.org/cloud/compute/metadata",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud/internal",
|
"ImportPath": "google.golang.org/cloud/internal",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud/internal/opts",
|
"ImportPath": "google.golang.org/cloud/internal/opts",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/cloud/storage",
|
"ImportPath": "google.golang.org/cloud/storage",
|
||||||
"Rev": "2400193c85c3561d13880d34e0e10c4315bb02af"
|
"Rev": "975617b05ea8a58727e6c1a06b6161ff4185a9f2"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc",
|
"ImportPath": "google.golang.org/grpc",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc/codes",
|
"ImportPath": "google.golang.org/grpc/codes",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc/credentials",
|
"ImportPath": "google.golang.org/grpc/credentials",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc/grpclog",
|
"ImportPath": "google.golang.org/grpc/grpclog",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/internal",
|
||||||
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc/metadata",
|
"ImportPath": "google.golang.org/grpc/metadata",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/naming",
|
||||||
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ImportPath": "google.golang.org/grpc/peer",
|
||||||
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "google.golang.org/grpc/transport",
|
"ImportPath": "google.golang.org/grpc/transport",
|
||||||
"Rev": "91c8b79535eb6045d70ec671d302213f88a3ab95"
|
"Rev": "d3ddb4469d5a1b949fc7a7da7c1d6a0d1b6de994"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"ImportPath": "gopkg.in/check.v1",
|
"ImportPath": "gopkg.in/check.v1",
|
||||||
|
|
1
Makefile
1
Makefile
|
@ -106,3 +106,4 @@ dep-validate: dep-restore
|
||||||
@$(GODEP) save ./...
|
@$(GODEP) save ./...
|
||||||
@test -z "$$(diff -r vendor .vendor.bak 2>&1 | tee /dev/stderr)" || \
|
@test -z "$$(diff -r vendor .vendor.bak 2>&1 | tee /dev/stderr)" || \
|
||||||
(echo >&2 "+ borked dependencies! what you have in Godeps/Godeps.json does not match with what you have in vendor" && false)
|
(echo >&2 "+ borked dependencies! what you have in Godeps/Godeps.json does not match with what you have in vendor" && false)
|
||||||
|
@rm -Rf .vendor.bak
|
||||||
|
|
20
vendor/github.com/bradfitz/http2/AUTHORS
generated
vendored
20
vendor/github.com/bradfitz/http2/AUTHORS
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
# This file is like Go's AUTHORS file: it lists Copyright holders.
|
|
||||||
# The list of humans who have contributd is in the CONTRIBUTORS file.
|
|
||||||
#
|
|
||||||
# To contribute to this project, because it will eventually be folded
|
|
||||||
# back in to Go itself, you need to submit a CLA:
|
|
||||||
#
|
|
||||||
# http://golang.org/doc/contribute.html#copyright
|
|
||||||
#
|
|
||||||
# Then you get added to CONTRIBUTORS and you or your company get added
|
|
||||||
# to the AUTHORS file.
|
|
||||||
|
|
||||||
Blake Mizerany <blake.mizerany@gmail.com> github=bmizerany
|
|
||||||
Daniel Morsing <daniel.morsing@gmail.com> github=DanielMorsing
|
|
||||||
Gabriel Aszalos <gabriel.aszalos@gmail.com> github=gbbr
|
|
||||||
Google, Inc.
|
|
||||||
Keith Rarick <kr@xph.us> github=kr
|
|
||||||
Matthew Keenan <tank.en.mate@gmail.com> <github@mattkeenan.net> github=mattkeenan
|
|
||||||
Matt Layher <mdlayher@gmail.com> github=mdlayher
|
|
||||||
Perry Abbott <perry.j.abbott@gmail.com> github=pabbott0
|
|
||||||
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> github=tatsuhiro-t
|
|
20
vendor/github.com/bradfitz/http2/CONTRIBUTORS
generated
vendored
20
vendor/github.com/bradfitz/http2/CONTRIBUTORS
generated
vendored
|
@ -1,20 +0,0 @@
|
||||||
# This file is like Go's CONTRIBUTORS file: it lists humans.
|
|
||||||
# The list of copyright holders (which may be companies) are in the AUTHORS file.
|
|
||||||
#
|
|
||||||
# To contribute to this project, because it will eventually be folded
|
|
||||||
# back in to Go itself, you need to submit a CLA:
|
|
||||||
#
|
|
||||||
# http://golang.org/doc/contribute.html#copyright
|
|
||||||
#
|
|
||||||
# Then you get added to CONTRIBUTORS and you or your company get added
|
|
||||||
# to the AUTHORS file.
|
|
||||||
|
|
||||||
Blake Mizerany <blake.mizerany@gmail.com> github=bmizerany
|
|
||||||
Brad Fitzpatrick <bradfitz@golang.org> github=bradfitz
|
|
||||||
Daniel Morsing <daniel.morsing@gmail.com> github=DanielMorsing
|
|
||||||
Gabriel Aszalos <gabriel.aszalos@gmail.com> github=gbbr
|
|
||||||
Keith Rarick <kr@xph.us> github=kr
|
|
||||||
Matthew Keenan <tank.en.mate@gmail.com> <github@mattkeenan.net> github=mattkeenan
|
|
||||||
Matt Layher <mdlayher@gmail.com> github=mdlayher
|
|
||||||
Perry Abbott <perry.j.abbott@gmail.com> github=pabbott0
|
|
||||||
Tatsuhiro Tsujikawa <tatsuhiro.t@gmail.com> github=tatsuhiro-t
|
|
5
vendor/github.com/bradfitz/http2/HACKING
generated
vendored
5
vendor/github.com/bradfitz/http2/HACKING
generated
vendored
|
@ -1,5 +0,0 @@
|
||||||
We only accept contributions from users who have gone through Go's
|
|
||||||
contribution process (signed a CLA).
|
|
||||||
|
|
||||||
Please acknowledge whether you have (and use the same email) if
|
|
||||||
sending a pull request.
|
|
7
vendor/github.com/bradfitz/http2/LICENSE
generated
vendored
7
vendor/github.com/bradfitz/http2/LICENSE
generated
vendored
|
@ -1,7 +0,0 @@
|
||||||
Copyright 2014 Google & the Go AUTHORS
|
|
||||||
|
|
||||||
Go AUTHORS are:
|
|
||||||
See https://code.google.com/p/go/source/browse/AUTHORS
|
|
||||||
|
|
||||||
Licensed under the terms of Go itself:
|
|
||||||
https://code.google.com/p/go/source/browse/LICENSE
|
|
76
vendor/github.com/bradfitz/http2/buffer.go
generated
vendored
76
vendor/github.com/bradfitz/http2/buffer.go
generated
vendored
|
@ -1,76 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors.
|
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
)
|
|
||||||
|
|
||||||
// buffer is an io.ReadWriteCloser backed by a fixed size buffer.
|
|
||||||
// It never allocates, but moves old data as new data is written.
|
|
||||||
type buffer struct {
|
|
||||||
buf []byte
|
|
||||||
r, w int
|
|
||||||
closed bool
|
|
||||||
err error // err to return to reader
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
errReadEmpty = errors.New("read from empty buffer")
|
|
||||||
errWriteClosed = errors.New("write on closed buffer")
|
|
||||||
errWriteFull = errors.New("write on full buffer")
|
|
||||||
)
|
|
||||||
|
|
||||||
// Read copies bytes from the buffer into p.
|
|
||||||
// It is an error to read when no data is available.
|
|
||||||
func (b *buffer) Read(p []byte) (n int, err error) {
|
|
||||||
n = copy(p, b.buf[b.r:b.w])
|
|
||||||
b.r += n
|
|
||||||
if b.closed && b.r == b.w {
|
|
||||||
err = b.err
|
|
||||||
} else if b.r == b.w && n == 0 {
|
|
||||||
err = errReadEmpty
|
|
||||||
}
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Len returns the number of bytes of the unread portion of the buffer.
|
|
||||||
func (b *buffer) Len() int {
|
|
||||||
return b.w - b.r
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write copies bytes from p into the buffer.
|
|
||||||
// It is an error to write more data than the buffer can hold.
|
|
||||||
func (b *buffer) Write(p []byte) (n int, err error) {
|
|
||||||
if b.closed {
|
|
||||||
return 0, errWriteClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
// Slide existing data to beginning.
|
|
||||||
if b.r > 0 && len(p) > len(b.buf)-b.w {
|
|
||||||
copy(b.buf, b.buf[b.r:b.w])
|
|
||||||
b.w -= b.r
|
|
||||||
b.r = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write new data.
|
|
||||||
n = copy(b.buf[b.w:], p)
|
|
||||||
b.w += n
|
|
||||||
if n < len(p) {
|
|
||||||
err = errWriteFull
|
|
||||||
}
|
|
||||||
return n, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close marks the buffer as closed. Future calls to Write will
|
|
||||||
// return an error. Future calls to Read, once the buffer is
|
|
||||||
// empty, will return err.
|
|
||||||
func (b *buffer) Close(err error) {
|
|
||||||
if !b.closed {
|
|
||||||
b.closed = true
|
|
||||||
b.err = err
|
|
||||||
}
|
|
||||||
}
|
|
249
vendor/github.com/bradfitz/http2/http2.go
generated
vendored
249
vendor/github.com/bradfitz/http2/http2.go
generated
vendored
|
@ -1,249 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
|
||||||
// Use of this source code is governed by a BSD-style
|
|
||||||
// license that can be found in the LICENSE file.
|
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
// Package http2 implements the HTTP/2 protocol.
|
|
||||||
//
|
|
||||||
// This is a work in progress. This package is low-level and intended
|
|
||||||
// to be used directly by very few people. Most users will use it
|
|
||||||
// indirectly through integration with the net/http package. See
|
|
||||||
// ConfigureServer. That ConfigureServer call will likely be automatic
|
|
||||||
// or available via an empty import in the future.
|
|
||||||
//
|
|
||||||
// See http://http2.github.io/
|
|
||||||
package http2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
var VerboseLogs = false
|
|
||||||
|
|
||||||
const (
|
|
||||||
// ClientPreface is the string that must be sent by new
|
|
||||||
// connections from clients.
|
|
||||||
ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
|
|
||||||
|
|
||||||
// SETTINGS_MAX_FRAME_SIZE default
|
|
||||||
// http://http2.github.io/http2-spec/#rfc.section.6.5.2
|
|
||||||
initialMaxFrameSize = 16384
|
|
||||||
|
|
||||||
// NextProtoTLS is the NPN/ALPN protocol negotiated during
|
|
||||||
// HTTP/2's TLS setup.
|
|
||||||
NextProtoTLS = "h2"
|
|
||||||
|
|
||||||
// http://http2.github.io/http2-spec/#SettingValues
|
|
||||||
initialHeaderTableSize = 4096
|
|
||||||
|
|
||||||
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
|
|
||||||
|
|
||||||
defaultMaxReadFrameSize = 1 << 20
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
clientPreface = []byte(ClientPreface)
|
|
||||||
)
|
|
||||||
|
|
||||||
type streamState int
|
|
||||||
|
|
||||||
const (
|
|
||||||
stateIdle streamState = iota
|
|
||||||
stateOpen
|
|
||||||
stateHalfClosedLocal
|
|
||||||
stateHalfClosedRemote
|
|
||||||
stateResvLocal
|
|
||||||
stateResvRemote
|
|
||||||
stateClosed
|
|
||||||
)
|
|
||||||
|
|
||||||
var stateName = [...]string{
|
|
||||||
stateIdle: "Idle",
|
|
||||||
stateOpen: "Open",
|
|
||||||
stateHalfClosedLocal: "HalfClosedLocal",
|
|
||||||
stateHalfClosedRemote: "HalfClosedRemote",
|
|
||||||
stateResvLocal: "ResvLocal",
|
|
||||||
stateResvRemote: "ResvRemote",
|
|
||||||
stateClosed: "Closed",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (st streamState) String() string {
|
|
||||||
return stateName[st]
|
|
||||||
}
|
|
||||||
|
|
||||||
// Setting is a setting parameter: which setting it is, and its value.
|
|
||||||
type Setting struct {
|
|
||||||
// ID is which setting is being set.
|
|
||||||
// See http://http2.github.io/http2-spec/#SettingValues
|
|
||||||
ID SettingID
|
|
||||||
|
|
||||||
// Val is the value.
|
|
||||||
Val uint32
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s Setting) String() string {
|
|
||||||
return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Valid reports whether the setting is valid.
|
|
||||||
func (s Setting) Valid() error {
|
|
||||||
// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
|
|
||||||
switch s.ID {
|
|
||||||
case SettingEnablePush:
|
|
||||||
if s.Val != 1 && s.Val != 0 {
|
|
||||||
return ConnectionError(ErrCodeProtocol)
|
|
||||||
}
|
|
||||||
case SettingInitialWindowSize:
|
|
||||||
if s.Val > 1<<31-1 {
|
|
||||||
return ConnectionError(ErrCodeFlowControl)
|
|
||||||
}
|
|
||||||
case SettingMaxFrameSize:
|
|
||||||
if s.Val < 16384 || s.Val > 1<<24-1 {
|
|
||||||
return ConnectionError(ErrCodeProtocol)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// A SettingID is an HTTP/2 setting as defined in
|
|
||||||
// http://http2.github.io/http2-spec/#iana-settings
|
|
||||||
type SettingID uint16
|
|
||||||
|
|
||||||
const (
|
|
||||||
SettingHeaderTableSize SettingID = 0x1
|
|
||||||
SettingEnablePush SettingID = 0x2
|
|
||||||
SettingMaxConcurrentStreams SettingID = 0x3
|
|
||||||
SettingInitialWindowSize SettingID = 0x4
|
|
||||||
SettingMaxFrameSize SettingID = 0x5
|
|
||||||
SettingMaxHeaderListSize SettingID = 0x6
|
|
||||||
)
|
|
||||||
|
|
||||||
var settingName = map[SettingID]string{
|
|
||||||
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
|
|
||||||
SettingEnablePush: "ENABLE_PUSH",
|
|
||||||
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
|
|
||||||
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
|
|
||||||
SettingMaxFrameSize: "MAX_FRAME_SIZE",
|
|
||||||
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s SettingID) String() string {
|
|
||||||
if v, ok := settingName[s]; ok {
|
|
||||||
return v
|
|
||||||
}
|
|
||||||
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
|
|
||||||
}
|
|
||||||
|
|
||||||
func validHeader(v string) bool {
|
|
||||||
if len(v) == 0 {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
for _, r := range v {
|
|
||||||
// "Just as in HTTP/1.x, header field names are
|
|
||||||
// strings of ASCII characters that are compared in a
|
|
||||||
// case-insensitive fashion. However, header field
|
|
||||||
// names MUST be converted to lowercase prior to their
|
|
||||||
// encoding in HTTP/2. "
|
|
||||||
if r >= 127 || ('A' <= r && r <= 'Z') {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
|
|
||||||
|
|
||||||
func init() {
|
|
||||||
for i := 100; i <= 999; i++ {
|
|
||||||
if v := http.StatusText(i); v != "" {
|
|
||||||
httpCodeStringCommon[i] = strconv.Itoa(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func httpCodeString(code int) string {
|
|
||||||
if s, ok := httpCodeStringCommon[code]; ok {
|
|
||||||
return s
|
|
||||||
}
|
|
||||||
return strconv.Itoa(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
// from pkg io
|
|
||||||
type stringWriter interface {
|
|
||||||
WriteString(s string) (n int, err error)
|
|
||||||
}
|
|
||||||
|
|
||||||
// A gate lets two goroutines coordinate their activities.
|
|
||||||
type gate chan struct{}
|
|
||||||
|
|
||||||
func (g gate) Done() { g <- struct{}{} }
|
|
||||||
func (g gate) Wait() { <-g }
|
|
||||||
|
|
||||||
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
|
|
||||||
type closeWaiter chan struct{}
|
|
||||||
|
|
||||||
// Init makes a closeWaiter usable.
|
|
||||||
// It exists because so a closeWaiter value can be placed inside a
|
|
||||||
// larger struct and have the Mutex and Cond's memory in the same
|
|
||||||
// allocation.
|
|
||||||
func (cw *closeWaiter) Init() {
|
|
||||||
*cw = make(chan struct{})
|
|
||||||
}
|
|
||||||
|
|
||||||
// Close marks the closeWaiter as closed and unblocks any waiters.
|
|
||||||
func (cw closeWaiter) Close() {
|
|
||||||
close(cw)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait waits for the closeWaiter to become closed.
|
|
||||||
func (cw closeWaiter) Wait() {
|
|
||||||
<-cw
|
|
||||||
}
|
|
||||||
|
|
||||||
// bufferedWriter is a buffered writer that writes to w.
|
|
||||||
// Its buffered writer is lazily allocated as needed, to minimize
|
|
||||||
// idle memory usage with many connections.
|
|
||||||
type bufferedWriter struct {
|
|
||||||
w io.Writer // immutable
|
|
||||||
bw *bufio.Writer // non-nil when data is buffered
|
|
||||||
}
|
|
||||||
|
|
||||||
func newBufferedWriter(w io.Writer) *bufferedWriter {
|
|
||||||
return &bufferedWriter{w: w}
|
|
||||||
}
|
|
||||||
|
|
||||||
var bufWriterPool = sync.Pool{
|
|
||||||
New: func() interface{} {
|
|
||||||
// TODO: pick something better? this is a bit under
|
|
||||||
// (3 x typical 1500 byte MTU) at least.
|
|
||||||
return bufio.NewWriterSize(nil, 4<<10)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *bufferedWriter) Write(p []byte) (n int, err error) {
|
|
||||||
if w.bw == nil {
|
|
||||||
bw := bufWriterPool.Get().(*bufio.Writer)
|
|
||||||
bw.Reset(w.w)
|
|
||||||
w.bw = bw
|
|
||||||
}
|
|
||||||
return w.bw.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (w *bufferedWriter) Flush() error {
|
|
||||||
bw := w.bw
|
|
||||||
if bw == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
err := bw.Flush()
|
|
||||||
bw.Reset(nil)
|
|
||||||
bufWriterPool.Put(bw)
|
|
||||||
w.bw = nil
|
|
||||||
return err
|
|
||||||
}
|
|
43
vendor/github.com/bradfitz/http2/pipe.go
generated
vendored
43
vendor/github.com/bradfitz/http2/pipe.go
generated
vendored
|
@ -1,43 +0,0 @@
|
||||||
// Copyright 2014 The Go Authors.
|
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"sync"
|
|
||||||
)
|
|
||||||
|
|
||||||
type pipe struct {
|
|
||||||
b buffer
|
|
||||||
c sync.Cond
|
|
||||||
m sync.Mutex
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read waits until data is available and copies bytes
|
|
||||||
// from the buffer into p.
|
|
||||||
func (r *pipe) Read(p []byte) (n int, err error) {
|
|
||||||
r.c.L.Lock()
|
|
||||||
defer r.c.L.Unlock()
|
|
||||||
for r.b.Len() == 0 && !r.b.closed {
|
|
||||||
r.c.Wait()
|
|
||||||
}
|
|
||||||
return r.b.Read(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write copies bytes from p into the buffer and wakes a reader.
|
|
||||||
// It is an error to write more data than the buffer can hold.
|
|
||||||
func (w *pipe) Write(p []byte) (n int, err error) {
|
|
||||||
w.c.L.Lock()
|
|
||||||
defer w.c.L.Unlock()
|
|
||||||
defer w.c.Signal()
|
|
||||||
return w.b.Write(p)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (c *pipe) Close(err error) {
|
|
||||||
c.c.L.Lock()
|
|
||||||
defer c.c.L.Unlock()
|
|
||||||
defer c.c.Signal()
|
|
||||||
c.b.Close(err)
|
|
||||||
}
|
|
553
vendor/github.com/bradfitz/http2/transport.go
generated
vendored
553
vendor/github.com/bradfitz/http2/transport.go
generated
vendored
|
@ -1,553 +0,0 @@
|
||||||
// Copyright 2015 The Go Authors.
|
|
||||||
// See https://go.googlesource.com/go/+/master/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://go.googlesource.com/go/+/master/LICENSE
|
|
||||||
|
|
||||||
package http2
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"io"
|
|
||||||
"log"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/bradfitz/http2/hpack"
|
|
||||||
)
|
|
||||||
|
|
||||||
type Transport struct {
|
|
||||||
Fallback http.RoundTripper
|
|
||||||
|
|
||||||
// TODO: remove this and make more general with a TLS dial hook, like http
|
|
||||||
InsecureTLSDial bool
|
|
||||||
|
|
||||||
connMu sync.Mutex
|
|
||||||
conns map[string][]*clientConn // key is host:port
|
|
||||||
}
|
|
||||||
|
|
||||||
type clientConn struct {
|
|
||||||
t *Transport
|
|
||||||
tconn *tls.Conn
|
|
||||||
tlsState *tls.ConnectionState
|
|
||||||
connKey []string // key(s) this connection is cached in, in t.conns
|
|
||||||
|
|
||||||
readerDone chan struct{} // closed on error
|
|
||||||
readerErr error // set before readerDone is closed
|
|
||||||
hdec *hpack.Decoder
|
|
||||||
nextRes *http.Response
|
|
||||||
|
|
||||||
mu sync.Mutex
|
|
||||||
closed bool
|
|
||||||
goAway *GoAwayFrame // if non-nil, the GoAwayFrame we received
|
|
||||||
streams map[uint32]*clientStream
|
|
||||||
nextStreamID uint32
|
|
||||||
bw *bufio.Writer
|
|
||||||
werr error // first write error that has occurred
|
|
||||||
br *bufio.Reader
|
|
||||||
fr *Framer
|
|
||||||
// Settings from peer:
|
|
||||||
maxFrameSize uint32
|
|
||||||
maxConcurrentStreams uint32
|
|
||||||
initialWindowSize uint32
|
|
||||||
hbuf bytes.Buffer // HPACK encoder writes into this
|
|
||||||
henc *hpack.Encoder
|
|
||||||
}
|
|
||||||
|
|
||||||
type clientStream struct {
|
|
||||||
ID uint32
|
|
||||||
resc chan resAndError
|
|
||||||
pw *io.PipeWriter
|
|
||||||
pr *io.PipeReader
|
|
||||||
}
|
|
||||||
|
|
||||||
type stickyErrWriter struct {
|
|
||||||
w io.Writer
|
|
||||||
err *error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sew stickyErrWriter) Write(p []byte) (n int, err error) {
|
|
||||||
if *sew.err != nil {
|
|
||||||
return 0, *sew.err
|
|
||||||
}
|
|
||||||
n, err = sew.w.Write(p)
|
|
||||||
*sew.err = err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
if req.URL.Scheme != "https" {
|
|
||||||
if t.Fallback == nil {
|
|
||||||
return nil, errors.New("http2: unsupported scheme and no Fallback")
|
|
||||||
}
|
|
||||||
return t.Fallback.RoundTrip(req)
|
|
||||||
}
|
|
||||||
|
|
||||||
host, port, err := net.SplitHostPort(req.URL.Host)
|
|
||||||
if err != nil {
|
|
||||||
host = req.URL.Host
|
|
||||||
port = "443"
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
cc, err := t.getClientConn(host, port)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
res, err := cc.roundTrip(req)
|
|
||||||
if shouldRetryRequest(err) { // TODO: or clientconn is overloaded (too many outstanding requests)?
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// CloseIdleConnections closes any connections which were previously
|
|
||||||
// connected from previous requests but are now sitting idle.
|
|
||||||
// It does not interrupt any connections currently in use.
|
|
||||||
func (t *Transport) CloseIdleConnections() {
|
|
||||||
t.connMu.Lock()
|
|
||||||
defer t.connMu.Unlock()
|
|
||||||
for _, vv := range t.conns {
|
|
||||||
for _, cc := range vv {
|
|
||||||
cc.closeIfIdle()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var errClientConnClosed = errors.New("http2: client conn is closed")
|
|
||||||
|
|
||||||
func shouldRetryRequest(err error) bool {
|
|
||||||
// TODO: or GOAWAY graceful shutdown stuff
|
|
||||||
return err == errClientConnClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) removeClientConn(cc *clientConn) {
|
|
||||||
t.connMu.Lock()
|
|
||||||
defer t.connMu.Unlock()
|
|
||||||
for _, key := range cc.connKey {
|
|
||||||
vv, ok := t.conns[key]
|
|
||||||
if !ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
newList := filterOutClientConn(vv, cc)
|
|
||||||
if len(newList) > 0 {
|
|
||||||
t.conns[key] = newList
|
|
||||||
} else {
|
|
||||||
delete(t.conns, key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func filterOutClientConn(in []*clientConn, exclude *clientConn) []*clientConn {
|
|
||||||
out := in[:0]
|
|
||||||
for _, v := range in {
|
|
||||||
if v != exclude {
|
|
||||||
out = append(out, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return out
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) getClientConn(host, port string) (*clientConn, error) {
|
|
||||||
t.connMu.Lock()
|
|
||||||
defer t.connMu.Unlock()
|
|
||||||
|
|
||||||
key := net.JoinHostPort(host, port)
|
|
||||||
|
|
||||||
for _, cc := range t.conns[key] {
|
|
||||||
if cc.canTakeNewRequest() {
|
|
||||||
return cc, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if t.conns == nil {
|
|
||||||
t.conns = make(map[string][]*clientConn)
|
|
||||||
}
|
|
||||||
cc, err := t.newClientConn(host, port, key)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
t.conns[key] = append(t.conns[key], cc)
|
|
||||||
return cc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (t *Transport) newClientConn(host, port, key string) (*clientConn, error) {
|
|
||||||
cfg := &tls.Config{
|
|
||||||
ServerName: host,
|
|
||||||
NextProtos: []string{NextProtoTLS},
|
|
||||||
InsecureSkipVerify: t.InsecureTLSDial,
|
|
||||||
}
|
|
||||||
tconn, err := tls.Dial("tcp", host+":"+port, cfg)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if err := tconn.Handshake(); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if !t.InsecureTLSDial {
|
|
||||||
if err := tconn.VerifyHostname(cfg.ServerName); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
state := tconn.ConnectionState()
|
|
||||||
if p := state.NegotiatedProtocol; p != NextProtoTLS {
|
|
||||||
// TODO(bradfitz): fall back to Fallback
|
|
||||||
return nil, fmt.Errorf("bad protocol: %v", p)
|
|
||||||
}
|
|
||||||
if !state.NegotiatedProtocolIsMutual {
|
|
||||||
return nil, errors.New("could not negotiate protocol mutually")
|
|
||||||
}
|
|
||||||
if _, err := tconn.Write(clientPreface); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cc := &clientConn{
|
|
||||||
t: t,
|
|
||||||
tconn: tconn,
|
|
||||||
connKey: []string{key}, // TODO: cert's validated hostnames too
|
|
||||||
tlsState: &state,
|
|
||||||
readerDone: make(chan struct{}),
|
|
||||||
nextStreamID: 1,
|
|
||||||
maxFrameSize: 16 << 10, // spec default
|
|
||||||
initialWindowSize: 65535, // spec default
|
|
||||||
maxConcurrentStreams: 1000, // "infinite", per spec. 1000 seems good enough.
|
|
||||||
streams: make(map[uint32]*clientStream),
|
|
||||||
}
|
|
||||||
cc.bw = bufio.NewWriter(stickyErrWriter{tconn, &cc.werr})
|
|
||||||
cc.br = bufio.NewReader(tconn)
|
|
||||||
cc.fr = NewFramer(cc.bw, cc.br)
|
|
||||||
cc.henc = hpack.NewEncoder(&cc.hbuf)
|
|
||||||
|
|
||||||
cc.fr.WriteSettings()
|
|
||||||
// TODO: re-send more conn-level flow control tokens when server uses all these.
|
|
||||||
cc.fr.WriteWindowUpdate(0, 1<<30) // um, 0x7fffffff doesn't work to Google? it hangs?
|
|
||||||
cc.bw.Flush()
|
|
||||||
if cc.werr != nil {
|
|
||||||
return nil, cc.werr
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read the obligatory SETTINGS frame
|
|
||||||
f, err := cc.fr.ReadFrame()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
sf, ok := f.(*SettingsFrame)
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("expected settings frame, got: %T", f)
|
|
||||||
}
|
|
||||||
cc.fr.WriteSettingsAck()
|
|
||||||
cc.bw.Flush()
|
|
||||||
|
|
||||||
sf.ForeachSetting(func(s Setting) error {
|
|
||||||
switch s.ID {
|
|
||||||
case SettingMaxFrameSize:
|
|
||||||
cc.maxFrameSize = s.Val
|
|
||||||
case SettingMaxConcurrentStreams:
|
|
||||||
cc.maxConcurrentStreams = s.Val
|
|
||||||
case SettingInitialWindowSize:
|
|
||||||
cc.initialWindowSize = s.Val
|
|
||||||
default:
|
|
||||||
// TODO(bradfitz): handle more
|
|
||||||
log.Printf("Unhandled Setting: %v", s)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
// TODO: figure out henc size
|
|
||||||
cc.hdec = hpack.NewDecoder(initialHeaderTableSize, cc.onNewHeaderField)
|
|
||||||
|
|
||||||
go cc.readLoop()
|
|
||||||
return cc, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) setGoAway(f *GoAwayFrame) {
|
|
||||||
cc.mu.Lock()
|
|
||||||
defer cc.mu.Unlock()
|
|
||||||
cc.goAway = f
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) canTakeNewRequest() bool {
|
|
||||||
cc.mu.Lock()
|
|
||||||
defer cc.mu.Unlock()
|
|
||||||
return cc.goAway == nil &&
|
|
||||||
int64(len(cc.streams)+1) < int64(cc.maxConcurrentStreams) &&
|
|
||||||
cc.nextStreamID < 2147483647
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) closeIfIdle() {
|
|
||||||
cc.mu.Lock()
|
|
||||||
if len(cc.streams) > 0 {
|
|
||||||
cc.mu.Unlock()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cc.closed = true
|
|
||||||
// TODO: do clients send GOAWAY too? maybe? Just Close:
|
|
||||||
cc.mu.Unlock()
|
|
||||||
|
|
||||||
cc.tconn.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) roundTrip(req *http.Request) (*http.Response, error) {
|
|
||||||
cc.mu.Lock()
|
|
||||||
|
|
||||||
if cc.closed {
|
|
||||||
cc.mu.Unlock()
|
|
||||||
return nil, errClientConnClosed
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := cc.newStream()
|
|
||||||
hasBody := false // TODO
|
|
||||||
|
|
||||||
// we send: HEADERS[+CONTINUATION] + (DATA?)
|
|
||||||
hdrs := cc.encodeHeaders(req)
|
|
||||||
first := true
|
|
||||||
for len(hdrs) > 0 {
|
|
||||||
chunk := hdrs
|
|
||||||
if len(chunk) > int(cc.maxFrameSize) {
|
|
||||||
chunk = chunk[:cc.maxFrameSize]
|
|
||||||
}
|
|
||||||
hdrs = hdrs[len(chunk):]
|
|
||||||
endHeaders := len(hdrs) == 0
|
|
||||||
if first {
|
|
||||||
cc.fr.WriteHeaders(HeadersFrameParam{
|
|
||||||
StreamID: cs.ID,
|
|
||||||
BlockFragment: chunk,
|
|
||||||
EndStream: !hasBody,
|
|
||||||
EndHeaders: endHeaders,
|
|
||||||
})
|
|
||||||
first = false
|
|
||||||
} else {
|
|
||||||
cc.fr.WriteContinuation(cs.ID, endHeaders, chunk)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
cc.bw.Flush()
|
|
||||||
werr := cc.werr
|
|
||||||
cc.mu.Unlock()
|
|
||||||
|
|
||||||
if hasBody {
|
|
||||||
// TODO: write data. and it should probably be interleaved:
|
|
||||||
// go ... io.Copy(dataFrameWriter{cc, cs, ...}, req.Body) ... etc
|
|
||||||
}
|
|
||||||
|
|
||||||
if werr != nil {
|
|
||||||
return nil, werr
|
|
||||||
}
|
|
||||||
|
|
||||||
re := <-cs.resc
|
|
||||||
if re.err != nil {
|
|
||||||
return nil, re.err
|
|
||||||
}
|
|
||||||
res := re.res
|
|
||||||
res.Request = req
|
|
||||||
res.TLS = cc.tlsState
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// requires cc.mu be held.
|
|
||||||
func (cc *clientConn) encodeHeaders(req *http.Request) []byte {
|
|
||||||
cc.hbuf.Reset()
|
|
||||||
|
|
||||||
// TODO(bradfitz): figure out :authority-vs-Host stuff between http2 and Go
|
|
||||||
host := req.Host
|
|
||||||
if host == "" {
|
|
||||||
host = req.URL.Host
|
|
||||||
}
|
|
||||||
|
|
||||||
path := req.URL.Path
|
|
||||||
if path == "" {
|
|
||||||
path = "/"
|
|
||||||
}
|
|
||||||
|
|
||||||
cc.writeHeader(":authority", host) // probably not right for all sites
|
|
||||||
cc.writeHeader(":method", req.Method)
|
|
||||||
cc.writeHeader(":path", path)
|
|
||||||
cc.writeHeader(":scheme", "https")
|
|
||||||
|
|
||||||
for k, vv := range req.Header {
|
|
||||||
lowKey := strings.ToLower(k)
|
|
||||||
if lowKey == "host" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
for _, v := range vv {
|
|
||||||
cc.writeHeader(lowKey, v)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return cc.hbuf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) writeHeader(name, value string) {
|
|
||||||
log.Printf("sending %q = %q", name, value)
|
|
||||||
cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
|
|
||||||
}
|
|
||||||
|
|
||||||
type resAndError struct {
|
|
||||||
res *http.Response
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
// requires cc.mu be held.
|
|
||||||
func (cc *clientConn) newStream() *clientStream {
|
|
||||||
cs := &clientStream{
|
|
||||||
ID: cc.nextStreamID,
|
|
||||||
resc: make(chan resAndError, 1),
|
|
||||||
}
|
|
||||||
cc.nextStreamID += 2
|
|
||||||
cc.streams[cs.ID] = cs
|
|
||||||
return cs
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) streamByID(id uint32, andRemove bool) *clientStream {
|
|
||||||
cc.mu.Lock()
|
|
||||||
defer cc.mu.Unlock()
|
|
||||||
cs := cc.streams[id]
|
|
||||||
if andRemove {
|
|
||||||
delete(cc.streams, id)
|
|
||||||
}
|
|
||||||
return cs
|
|
||||||
}
|
|
||||||
|
|
||||||
// runs in its own goroutine.
|
|
||||||
func (cc *clientConn) readLoop() {
|
|
||||||
defer cc.t.removeClientConn(cc)
|
|
||||||
defer close(cc.readerDone)
|
|
||||||
|
|
||||||
activeRes := map[uint32]*clientStream{} // keyed by streamID
|
|
||||||
// Close any response bodies if the server closes prematurely.
|
|
||||||
// TODO: also do this if we've written the headers but not
|
|
||||||
// gotten a response yet.
|
|
||||||
defer func() {
|
|
||||||
err := cc.readerErr
|
|
||||||
if err == io.EOF {
|
|
||||||
err = io.ErrUnexpectedEOF
|
|
||||||
}
|
|
||||||
for _, cs := range activeRes {
|
|
||||||
cs.pw.CloseWithError(err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
// continueStreamID is the stream ID we're waiting for
|
|
||||||
// continuation frames for.
|
|
||||||
var continueStreamID uint32
|
|
||||||
|
|
||||||
for {
|
|
||||||
f, err := cc.fr.ReadFrame()
|
|
||||||
if err != nil {
|
|
||||||
cc.readerErr = err
|
|
||||||
return
|
|
||||||
}
|
|
||||||
log.Printf("Transport received %v: %#v", f.Header(), f)
|
|
||||||
|
|
||||||
streamID := f.Header().StreamID
|
|
||||||
|
|
||||||
_, isContinue := f.(*ContinuationFrame)
|
|
||||||
if isContinue {
|
|
||||||
if streamID != continueStreamID {
|
|
||||||
log.Printf("Protocol violation: got CONTINUATION with id %d; want %d", streamID, continueStreamID)
|
|
||||||
cc.readerErr = ConnectionError(ErrCodeProtocol)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
} else if continueStreamID != 0 {
|
|
||||||
// Continue frames need to be adjacent in the stream
|
|
||||||
// and we were in the middle of headers.
|
|
||||||
log.Printf("Protocol violation: got %T for stream %d, want CONTINUATION for %d", f, streamID, continueStreamID)
|
|
||||||
cc.readerErr = ConnectionError(ErrCodeProtocol)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if streamID%2 == 0 {
|
|
||||||
// Ignore streams pushed from the server for now.
|
|
||||||
// These always have an even stream id.
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
streamEnded := false
|
|
||||||
if ff, ok := f.(streamEnder); ok {
|
|
||||||
streamEnded = ff.StreamEnded()
|
|
||||||
}
|
|
||||||
|
|
||||||
cs := cc.streamByID(streamID, streamEnded)
|
|
||||||
if cs == nil {
|
|
||||||
log.Printf("Received frame for untracked stream ID %d", streamID)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
switch f := f.(type) {
|
|
||||||
case *HeadersFrame:
|
|
||||||
cc.nextRes = &http.Response{
|
|
||||||
Proto: "HTTP/2.0",
|
|
||||||
ProtoMajor: 2,
|
|
||||||
Header: make(http.Header),
|
|
||||||
}
|
|
||||||
cs.pr, cs.pw = io.Pipe()
|
|
||||||
cc.hdec.Write(f.HeaderBlockFragment())
|
|
||||||
case *ContinuationFrame:
|
|
||||||
cc.hdec.Write(f.HeaderBlockFragment())
|
|
||||||
case *DataFrame:
|
|
||||||
log.Printf("DATA: %q", f.Data())
|
|
||||||
cs.pw.Write(f.Data())
|
|
||||||
case *GoAwayFrame:
|
|
||||||
cc.t.removeClientConn(cc)
|
|
||||||
if f.ErrCode != 0 {
|
|
||||||
// TODO: deal with GOAWAY more. particularly the error code
|
|
||||||
log.Printf("transport got GOAWAY with error code = %v", f.ErrCode)
|
|
||||||
}
|
|
||||||
cc.setGoAway(f)
|
|
||||||
default:
|
|
||||||
log.Printf("Transport: unhandled response frame type %T", f)
|
|
||||||
}
|
|
||||||
headersEnded := false
|
|
||||||
if he, ok := f.(headersEnder); ok {
|
|
||||||
headersEnded = he.HeadersEnded()
|
|
||||||
if headersEnded {
|
|
||||||
continueStreamID = 0
|
|
||||||
} else {
|
|
||||||
continueStreamID = streamID
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if streamEnded {
|
|
||||||
cs.pw.Close()
|
|
||||||
delete(activeRes, streamID)
|
|
||||||
}
|
|
||||||
if headersEnded {
|
|
||||||
if cs == nil {
|
|
||||||
panic("couldn't find stream") // TODO be graceful
|
|
||||||
}
|
|
||||||
// TODO: set the Body to one which notes the
|
|
||||||
// Close and also sends the server a
|
|
||||||
// RST_STREAM
|
|
||||||
cc.nextRes.Body = cs.pr
|
|
||||||
res := cc.nextRes
|
|
||||||
activeRes[streamID] = cs
|
|
||||||
cs.resc <- resAndError{res: res}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (cc *clientConn) onNewHeaderField(f hpack.HeaderField) {
|
|
||||||
// TODO: verifiy pseudo headers come before non-pseudo headers
|
|
||||||
// TODO: verifiy the status is set
|
|
||||||
log.Printf("Header field: %+v", f)
|
|
||||||
if f.Name == ":status" {
|
|
||||||
code, err := strconv.Atoi(f.Value)
|
|
||||||
if err != nil {
|
|
||||||
panic("TODO: be graceful")
|
|
||||||
}
|
|
||||||
cc.nextRes.Status = f.Value + " " + http.StatusText(code)
|
|
||||||
cc.nextRes.StatusCode = code
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if strings.HasPrefix(f.Name, ":") {
|
|
||||||
// "Endpoints MUST NOT generate pseudo-header fields other than those defined in this document."
|
|
||||||
// TODO: treat as invalid?
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cc.nextRes.Header.Add(http.CanonicalHeaderKey(f.Name), f.Value)
|
|
||||||
}
|
|
2
vendor/github.com/golang/protobuf/proto/Makefile
generated
vendored
2
vendor/github.com/golang/protobuf/proto/Makefile
generated
vendored
|
@ -39,5 +39,5 @@ test: install generate-test-pbs
|
||||||
generate-test-pbs:
|
generate-test-pbs:
|
||||||
make install
|
make install
|
||||||
make -C testdata
|
make -C testdata
|
||||||
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata:. proto3_proto/proto3.proto
|
protoc --go_out=Mtestdata/test.proto=github.com/golang/protobuf/proto/testdata,Mgoogle/protobuf/any.proto=github.com/golang/protobuf/ptypes/any:. proto3_proto/proto3.proto
|
||||||
make
|
make
|
||||||
|
|
13
vendor/github.com/golang/protobuf/proto/clone.go
generated
vendored
13
vendor/github.com/golang/protobuf/proto/clone.go
generated
vendored
|
@ -30,7 +30,7 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Protocol buffer deep copy and merge.
|
// Protocol buffer deep copy and merge.
|
||||||
// TODO: MessageSet and RawMessage.
|
// TODO: RawMessage.
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
|
@ -120,6 +120,17 @@ func mergeAny(out, in reflect.Value, viaPtr bool, prop *Properties) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
out.Set(in)
|
out.Set(in)
|
||||||
|
case reflect.Interface:
|
||||||
|
// Probably a oneof field; copy non-nil values.
|
||||||
|
if in.IsNil() {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Allocate destination if it is not set, or set to a different type.
|
||||||
|
// Otherwise we will merge as normal.
|
||||||
|
if out.IsNil() || out.Elem().Type() != in.Elem().Type() {
|
||||||
|
out.Set(reflect.New(in.Elem().Elem().Type())) // interface -> *T -> T -> new(T)
|
||||||
|
}
|
||||||
|
mergeAny(out.Elem(), in.Elem(), false, nil)
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if in.Len() == 0 {
|
if in.Len() == 0 {
|
||||||
return
|
return
|
||||||
|
|
51
vendor/github.com/golang/protobuf/proto/decode.go
generated
vendored
51
vendor/github.com/golang/protobuf/proto/decode.go
generated
vendored
|
@ -46,6 +46,10 @@ import (
|
||||||
// errOverflow is returned when an integer is too large to be represented.
|
// errOverflow is returned when an integer is too large to be represented.
|
||||||
var errOverflow = errors.New("proto: integer overflow")
|
var errOverflow = errors.New("proto: integer overflow")
|
||||||
|
|
||||||
|
// ErrInternalBadWireType is returned by generated code when an incorrect
|
||||||
|
// wire type is encountered. It does not get returned to user code.
|
||||||
|
var ErrInternalBadWireType = errors.New("proto: internal error: bad wiretype for oneof")
|
||||||
|
|
||||||
// The fundamental decoders that interpret bytes on the wire.
|
// The fundamental decoders that interpret bytes on the wire.
|
||||||
// Those that take integer types all return uint64 and are
|
// Those that take integer types all return uint64 and are
|
||||||
// therefore of type valueDecoder.
|
// therefore of type valueDecoder.
|
||||||
|
@ -314,6 +318,24 @@ func UnmarshalMerge(buf []byte, pb Message) error {
|
||||||
return NewBuffer(buf).Unmarshal(pb)
|
return NewBuffer(buf).Unmarshal(pb)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DecodeMessage reads a count-delimited message from the Buffer.
|
||||||
|
func (p *Buffer) DecodeMessage(pb Message) error {
|
||||||
|
enc, err := p.DecodeRawBytes(false)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return NewBuffer(enc).Unmarshal(pb)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DecodeGroup reads a tag-delimited group from the Buffer.
|
||||||
|
func (p *Buffer) DecodeGroup(pb Message) error {
|
||||||
|
typ, base, err := getbase(pb)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return p.unmarshalType(typ.Elem(), GetProperties(typ.Elem()), true, base)
|
||||||
|
}
|
||||||
|
|
||||||
// Unmarshal parses the protocol buffer representation in the
|
// Unmarshal parses the protocol buffer representation in the
|
||||||
// Buffer and places the decoded result in pb. If the struct
|
// Buffer and places the decoded result in pb. If the struct
|
||||||
// underlying pb does not match the data in the buffer, the results can be
|
// underlying pb does not match the data in the buffer, the results can be
|
||||||
|
@ -377,6 +399,20 @@ func (o *Buffer) unmarshalType(st reflect.Type, prop *StructProperties, is_group
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Maybe it's a oneof?
|
||||||
|
if prop.oneofUnmarshaler != nil {
|
||||||
|
m := structPointer_Interface(base, st).(Message)
|
||||||
|
// First return value indicates whether tag is a oneof field.
|
||||||
|
ok, err = prop.oneofUnmarshaler(m, tag, wire, o)
|
||||||
|
if err == ErrInternalBadWireType {
|
||||||
|
// Map the error to something more descriptive.
|
||||||
|
// Do the formatting here to save generated code space.
|
||||||
|
err = fmt.Errorf("bad wiretype for oneof field in %T", m)
|
||||||
|
}
|
||||||
|
if ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
err = o.skipAndSave(st, tag, wire, base, prop.unrecField)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -561,9 +597,13 @@ func (o *Buffer) dec_slice_packed_bool(p *Properties, base structPointer) error
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
nb := int(nn) // number of bytes of encoded bools
|
nb := int(nn) // number of bytes of encoded bools
|
||||||
|
fin := o.index + nb
|
||||||
|
if fin < o.index {
|
||||||
|
return errOverflow
|
||||||
|
}
|
||||||
|
|
||||||
y := *v
|
y := *v
|
||||||
for i := 0; i < nb; i++ {
|
for o.index < fin {
|
||||||
u, err := p.valDec(o)
|
u, err := p.valDec(o)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -728,10 +768,11 @@ func (o *Buffer) dec_new_map(p *Properties, base structPointer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
keyelem, valelem := keyptr.Elem(), valptr.Elem()
|
keyelem, valelem := keyptr.Elem(), valptr.Elem()
|
||||||
if !keyelem.IsValid() || !valelem.IsValid() {
|
if !keyelem.IsValid() {
|
||||||
// We did not decode the key or the value in the map entry.
|
keyelem = reflect.Zero(p.mtype.Key())
|
||||||
// Either way, it's an invalid map entry.
|
}
|
||||||
return fmt.Errorf("proto: bad map data: missing key/val")
|
if !valelem.IsValid() {
|
||||||
|
valelem = reflect.Zero(p.mtype.Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
v.SetMapIndex(keyelem, valelem)
|
v.SetMapIndex(keyelem, valelem)
|
||||||
|
|
60
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
60
vendor/github.com/golang/protobuf/proto/encode.go
generated
vendored
|
@ -64,6 +64,10 @@ var (
|
||||||
// a struct with a repeated field containing a nil element.
|
// a struct with a repeated field containing a nil element.
|
||||||
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
|
errRepeatedHasNil = errors.New("proto: repeated field has nil element")
|
||||||
|
|
||||||
|
// errOneofHasNil is the error returned if Marshal is called with
|
||||||
|
// a struct with a oneof field containing a nil element.
|
||||||
|
errOneofHasNil = errors.New("proto: oneof field has nil value")
|
||||||
|
|
||||||
// ErrNil is the error returned if Marshal is called with nil.
|
// ErrNil is the error returned if Marshal is called with nil.
|
||||||
ErrNil = errors.New("proto: Marshal called with nil")
|
ErrNil = errors.New("proto: Marshal called with nil")
|
||||||
)
|
)
|
||||||
|
@ -105,6 +109,11 @@ func (p *Buffer) EncodeVarint(x uint64) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SizeVarint returns the varint encoding size of an integer.
|
||||||
|
func SizeVarint(x uint64) int {
|
||||||
|
return sizeVarint(x)
|
||||||
|
}
|
||||||
|
|
||||||
func sizeVarint(x uint64) (n int) {
|
func sizeVarint(x uint64) (n int) {
|
||||||
for {
|
for {
|
||||||
n++
|
n++
|
||||||
|
@ -228,6 +237,20 @@ func Marshal(pb Message) ([]byte, error) {
|
||||||
return p.buf, err
|
return p.buf, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EncodeMessage writes the protocol buffer to the Buffer,
|
||||||
|
// prefixed by a varint-encoded length.
|
||||||
|
func (p *Buffer) EncodeMessage(pb Message) error {
|
||||||
|
t, base, err := getbase(pb)
|
||||||
|
if structPointer_IsNil(base) {
|
||||||
|
return ErrNil
|
||||||
|
}
|
||||||
|
if err == nil {
|
||||||
|
var state errorState
|
||||||
|
err = p.enc_len_struct(GetProperties(t.Elem()), base, &state)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
// Marshal takes the protocol buffer
|
// Marshal takes the protocol buffer
|
||||||
// and encodes it into the wire format, writing the result to the
|
// and encodes it into the wire format, writing the result to the
|
||||||
// Buffer.
|
// Buffer.
|
||||||
|
@ -318,7 +341,7 @@ func size_bool(p *Properties, base structPointer) int {
|
||||||
|
|
||||||
func size_proto3_bool(p *Properties, base structPointer) int {
|
func size_proto3_bool(p *Properties, base structPointer) int {
|
||||||
v := *structPointer_BoolVal(base, p.field)
|
v := *structPointer_BoolVal(base, p.field)
|
||||||
if !v {
|
if !v && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return len(p.tagcode) + 1 // each bool takes exactly one byte
|
return len(p.tagcode) + 1 // each bool takes exactly one byte
|
||||||
|
@ -361,7 +384,7 @@ func size_int32(p *Properties, base structPointer) (n int) {
|
||||||
func size_proto3_int32(p *Properties, base structPointer) (n int) {
|
func size_proto3_int32(p *Properties, base structPointer) (n int) {
|
||||||
v := structPointer_Word32Val(base, p.field)
|
v := structPointer_Word32Val(base, p.field)
|
||||||
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
|
x := int32(word32Val_Get(v)) // permit sign extension to use full 64-bit range
|
||||||
if x == 0 {
|
if x == 0 && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -407,7 +430,7 @@ func size_uint32(p *Properties, base structPointer) (n int) {
|
||||||
func size_proto3_uint32(p *Properties, base structPointer) (n int) {
|
func size_proto3_uint32(p *Properties, base structPointer) (n int) {
|
||||||
v := structPointer_Word32Val(base, p.field)
|
v := structPointer_Word32Val(base, p.field)
|
||||||
x := word32Val_Get(v)
|
x := word32Val_Get(v)
|
||||||
if x == 0 {
|
if x == 0 && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -452,7 +475,7 @@ func size_int64(p *Properties, base structPointer) (n int) {
|
||||||
func size_proto3_int64(p *Properties, base structPointer) (n int) {
|
func size_proto3_int64(p *Properties, base structPointer) (n int) {
|
||||||
v := structPointer_Word64Val(base, p.field)
|
v := structPointer_Word64Val(base, p.field)
|
||||||
x := word64Val_Get(v)
|
x := word64Val_Get(v)
|
||||||
if x == 0 {
|
if x == 0 && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -495,7 +518,7 @@ func size_string(p *Properties, base structPointer) (n int) {
|
||||||
|
|
||||||
func size_proto3_string(p *Properties, base structPointer) (n int) {
|
func size_proto3_string(p *Properties, base structPointer) (n int) {
|
||||||
v := *structPointer_StringVal(base, p.field)
|
v := *structPointer_StringVal(base, p.field)
|
||||||
if v == "" {
|
if v == "" && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -529,7 +552,7 @@ func (o *Buffer) enc_struct_message(p *Properties, base structPointer) error {
|
||||||
}
|
}
|
||||||
o.buf = append(o.buf, p.tagcode...)
|
o.buf = append(o.buf, p.tagcode...)
|
||||||
o.EncodeRawBytes(data)
|
o.EncodeRawBytes(data)
|
||||||
return nil
|
return state.err
|
||||||
}
|
}
|
||||||
|
|
||||||
o.buf = append(o.buf, p.tagcode...)
|
o.buf = append(o.buf, p.tagcode...)
|
||||||
|
@ -667,7 +690,7 @@ func (o *Buffer) enc_proto3_slice_byte(p *Properties, base structPointer) error
|
||||||
|
|
||||||
func size_slice_byte(p *Properties, base structPointer) (n int) {
|
func size_slice_byte(p *Properties, base structPointer) (n int) {
|
||||||
s := *structPointer_Bytes(base, p.field)
|
s := *structPointer_Bytes(base, p.field)
|
||||||
if s == nil {
|
if s == nil && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -677,7 +700,7 @@ func size_slice_byte(p *Properties, base structPointer) (n int) {
|
||||||
|
|
||||||
func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
|
func size_proto3_slice_byte(p *Properties, base structPointer) (n int) {
|
||||||
s := *structPointer_Bytes(base, p.field)
|
s := *structPointer_Bytes(base, p.field)
|
||||||
if len(s) == 0 {
|
if len(s) == 0 && !p.oneof {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
n += len(p.tagcode)
|
n += len(p.tagcode)
|
||||||
|
@ -1101,9 +1124,8 @@ func (o *Buffer) enc_new_map(p *Properties, base structPointer) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
keys := v.MapKeys()
|
// Don't sort map keys. It is not required by the spec, and C++ doesn't do it.
|
||||||
sort.Sort(mapKeys(keys))
|
for _, key := range v.MapKeys() {
|
||||||
for _, key := range keys {
|
|
||||||
val := v.MapIndex(key)
|
val := v.MapIndex(key)
|
||||||
|
|
||||||
// The only illegal map entry values are nil message pointers.
|
// The only illegal map entry values are nil message pointers.
|
||||||
|
@ -1201,6 +1223,16 @@ func (o *Buffer) enc_struct(prop *StructProperties, base structPointer) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Do oneof fields.
|
||||||
|
if prop.oneofMarshaler != nil {
|
||||||
|
m := structPointer_Interface(base, prop.stype).(Message)
|
||||||
|
if err := prop.oneofMarshaler(m, o); err == ErrNil {
|
||||||
|
return errOneofHasNil
|
||||||
|
} else if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Add unrecognized fields at the end.
|
// Add unrecognized fields at the end.
|
||||||
if prop.unrecField.IsValid() {
|
if prop.unrecField.IsValid() {
|
||||||
v := *structPointer_Bytes(base, prop.unrecField)
|
v := *structPointer_Bytes(base, prop.unrecField)
|
||||||
|
@ -1226,6 +1258,12 @@ func size_struct(prop *StructProperties, base structPointer) (n int) {
|
||||||
n += len(v)
|
n += len(v)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Factor in any oneof fields.
|
||||||
|
if prop.oneofSizer != nil {
|
||||||
|
m := structPointer_Interface(base, prop.stype).(Message)
|
||||||
|
n += prop.oneofSizer(m)
|
||||||
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
38
vendor/github.com/golang/protobuf/proto/equal.go
generated
vendored
38
vendor/github.com/golang/protobuf/proto/equal.go
generated
vendored
|
@ -30,7 +30,6 @@
|
||||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
|
||||||
// Protocol buffer comparison.
|
// Protocol buffer comparison.
|
||||||
// TODO: MessageSet.
|
|
||||||
|
|
||||||
package proto
|
package proto
|
||||||
|
|
||||||
|
@ -51,7 +50,9 @@ Equality is defined in this way:
|
||||||
are equal, and extensions sets are equal.
|
are equal, and extensions sets are equal.
|
||||||
- Two set scalar fields are equal iff their values are equal.
|
- Two set scalar fields are equal iff their values are equal.
|
||||||
If the fields are of a floating-point type, remember that
|
If the fields are of a floating-point type, remember that
|
||||||
NaN != x for all x, including NaN.
|
NaN != x for all x, including NaN. If the message is defined
|
||||||
|
in a proto3 .proto file, fields are not "set"; specifically,
|
||||||
|
zero length proto3 "bytes" fields are equal (nil == {}).
|
||||||
- Two repeated fields are equal iff their lengths are the same,
|
- Two repeated fields are equal iff their lengths are the same,
|
||||||
and their corresponding elements are equal (a "bytes" field,
|
and their corresponding elements are equal (a "bytes" field,
|
||||||
although represented by []byte, is not a repeated field)
|
although represented by []byte, is not a repeated field)
|
||||||
|
@ -89,6 +90,7 @@ func Equal(a, b Message) bool {
|
||||||
|
|
||||||
// v1 and v2 are known to have the same type.
|
// v1 and v2 are known to have the same type.
|
||||||
func equalStruct(v1, v2 reflect.Value) bool {
|
func equalStruct(v1, v2 reflect.Value) bool {
|
||||||
|
sprop := GetProperties(v1.Type())
|
||||||
for i := 0; i < v1.NumField(); i++ {
|
for i := 0; i < v1.NumField(); i++ {
|
||||||
f := v1.Type().Field(i)
|
f := v1.Type().Field(i)
|
||||||
if strings.HasPrefix(f.Name, "XXX_") {
|
if strings.HasPrefix(f.Name, "XXX_") {
|
||||||
|
@ -114,7 +116,7 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
||||||
}
|
}
|
||||||
f1, f2 = f1.Elem(), f2.Elem()
|
f1, f2 = f1.Elem(), f2.Elem()
|
||||||
}
|
}
|
||||||
if !equalAny(f1, f2) {
|
if !equalAny(f1, f2, sprop.Prop[i]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -141,7 +143,8 @@ func equalStruct(v1, v2 reflect.Value) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
// v1 and v2 are known to have the same type.
|
// v1 and v2 are known to have the same type.
|
||||||
func equalAny(v1, v2 reflect.Value) bool {
|
// prop may be nil.
|
||||||
|
func equalAny(v1, v2 reflect.Value, prop *Properties) bool {
|
||||||
if v1.Type() == protoMessageType {
|
if v1.Type() == protoMessageType {
|
||||||
m1, _ := v1.Interface().(Message)
|
m1, _ := v1.Interface().(Message)
|
||||||
m2, _ := v2.Interface().(Message)
|
m2, _ := v2.Interface().(Message)
|
||||||
|
@ -154,6 +157,17 @@ func equalAny(v1, v2 reflect.Value) bool {
|
||||||
return v1.Float() == v2.Float()
|
return v1.Float() == v2.Float()
|
||||||
case reflect.Int32, reflect.Int64:
|
case reflect.Int32, reflect.Int64:
|
||||||
return v1.Int() == v2.Int()
|
return v1.Int() == v2.Int()
|
||||||
|
case reflect.Interface:
|
||||||
|
// Probably a oneof field; compare the inner values.
|
||||||
|
n1, n2 := v1.IsNil(), v2.IsNil()
|
||||||
|
if n1 || n2 {
|
||||||
|
return n1 == n2
|
||||||
|
}
|
||||||
|
e1, e2 := v1.Elem(), v2.Elem()
|
||||||
|
if e1.Type() != e2.Type() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return equalAny(e1, e2, nil)
|
||||||
case reflect.Map:
|
case reflect.Map:
|
||||||
if v1.Len() != v2.Len() {
|
if v1.Len() != v2.Len() {
|
||||||
return false
|
return false
|
||||||
|
@ -164,16 +178,22 @@ func equalAny(v1, v2 reflect.Value) bool {
|
||||||
// This key was not found in the second map.
|
// This key was not found in the second map.
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !equalAny(v1.MapIndex(key), val2) {
|
if !equalAny(v1.MapIndex(key), val2, nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return equalAny(v1.Elem(), v2.Elem())
|
return equalAny(v1.Elem(), v2.Elem(), prop)
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
if v1.Type().Elem().Kind() == reflect.Uint8 {
|
||||||
// short circuit: []byte
|
// short circuit: []byte
|
||||||
|
|
||||||
|
// Edge case: if this is in a proto3 message, a zero length
|
||||||
|
// bytes field is considered the zero value.
|
||||||
|
if prop != nil && prop.proto3 && v1.Len() == 0 && v2.Len() == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if v1.IsNil() != v2.IsNil() {
|
if v1.IsNil() != v2.IsNil() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -184,7 +204,7 @@ func equalAny(v1, v2 reflect.Value) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := 0; i < v1.Len(); i++ {
|
for i := 0; i < v1.Len(); i++ {
|
||||||
if !equalAny(v1.Index(i), v2.Index(i)) {
|
if !equalAny(v1.Index(i), v2.Index(i), prop) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -219,7 +239,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
||||||
|
|
||||||
if m1 != nil && m2 != nil {
|
if m1 != nil && m2 != nil {
|
||||||
// Both are unencoded.
|
// Both are unencoded.
|
||||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
|
@ -247,7 +267,7 @@ func equalExtensions(base reflect.Type, em1, em2 map[int32]Extension) bool {
|
||||||
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
log.Printf("proto: badly encoded extension %d of %v: %v", extNum, base, err)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2)) {
|
if !equalAny(reflect.ValueOf(m1), reflect.ValueOf(m2), nil) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
3
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
3
vendor/github.com/golang/protobuf/proto/extensions.go
generated
vendored
|
@ -301,7 +301,6 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||||
o := NewBuffer(b)
|
o := NewBuffer(b)
|
||||||
|
|
||||||
t := reflect.TypeOf(extension.ExtensionType)
|
t := reflect.TypeOf(extension.ExtensionType)
|
||||||
rep := extension.repeated()
|
|
||||||
|
|
||||||
props := extensionProperties(extension)
|
props := extensionProperties(extension)
|
||||||
|
|
||||||
|
@ -323,7 +322,7 @@ func decodeExtension(b []byte, extension *ExtensionDesc) (interface{}, error) {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if !rep || o.index >= len(o.buf) {
|
if o.index >= len(o.buf) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
123
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
123
vendor/github.com/golang/protobuf/proto/lib.go
generated
vendored
|
@ -66,8 +66,16 @@ for a protocol buffer variable v:
|
||||||
that contain it (if any) followed by the CamelCased name of the
|
that contain it (if any) followed by the CamelCased name of the
|
||||||
extension field itself. HasExtension, ClearExtension, GetExtension
|
extension field itself. HasExtension, ClearExtension, GetExtension
|
||||||
and SetExtension are functions for manipulating extensions.
|
and SetExtension are functions for manipulating extensions.
|
||||||
|
- Oneof field sets are given a single field in their message,
|
||||||
|
with distinguished wrapper types for each possible field value.
|
||||||
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
- Marshal and Unmarshal are functions to encode and decode the wire format.
|
||||||
|
|
||||||
|
When the .proto file specifies `syntax="proto3"`, there are some differences:
|
||||||
|
|
||||||
|
- Non-repeated fields of non-message type are values instead of pointers.
|
||||||
|
- Getters are only generated for message and oneof fields.
|
||||||
|
- Enum types do not get an Enum method.
|
||||||
|
|
||||||
The simplest way to describe this is to see an example.
|
The simplest way to describe this is to see an example.
|
||||||
Given file test.proto, containing
|
Given file test.proto, containing
|
||||||
|
|
||||||
|
@ -82,6 +90,10 @@ Given file test.proto, containing
|
||||||
optional group OptionalGroup = 4 {
|
optional group OptionalGroup = 4 {
|
||||||
required string RequiredField = 5;
|
required string RequiredField = 5;
|
||||||
}
|
}
|
||||||
|
oneof union {
|
||||||
|
int32 number = 6;
|
||||||
|
string name = 7;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The resulting file, test.pb.go, is:
|
The resulting file, test.pb.go, is:
|
||||||
|
@ -120,15 +132,40 @@ The resulting file, test.pb.go, is:
|
||||||
}
|
}
|
||||||
|
|
||||||
type Test struct {
|
type Test struct {
|
||||||
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
Label *string `protobuf:"bytes,1,req,name=label" json:"label,omitempty"`
|
||||||
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
Type *int32 `protobuf:"varint,2,opt,name=type,def=77" json:"type,omitempty"`
|
||||||
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
Reps []int64 `protobuf:"varint,3,rep,name=reps" json:"reps,omitempty"`
|
||||||
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
Optionalgroup *Test_OptionalGroup `protobuf:"group,4,opt,name=OptionalGroup" json:"optionalgroup,omitempty"`
|
||||||
XXX_unrecognized []byte `json:"-"`
|
// Types that are valid to be assigned to Union:
|
||||||
|
// *Test_Number
|
||||||
|
// *Test_Name
|
||||||
|
Union isTest_Union `protobuf_oneof:"union"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
}
|
}
|
||||||
func (m *Test) Reset() { *m = Test{} }
|
func (m *Test) Reset() { *m = Test{} }
|
||||||
func (m *Test) String() string { return proto.CompactTextString(m) }
|
func (m *Test) String() string { return proto.CompactTextString(m) }
|
||||||
func (*Test) ProtoMessage() {}
|
func (*Test) ProtoMessage() {}
|
||||||
|
|
||||||
|
type isTest_Union interface {
|
||||||
|
isTest_Union()
|
||||||
|
}
|
||||||
|
|
||||||
|
type Test_Number struct {
|
||||||
|
Number int32 `protobuf:"varint,6,opt,name=number"`
|
||||||
|
}
|
||||||
|
type Test_Name struct {
|
||||||
|
Name string `protobuf:"bytes,7,opt,name=name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*Test_Number) isTest_Union() {}
|
||||||
|
func (*Test_Name) isTest_Union() {}
|
||||||
|
|
||||||
|
func (m *Test) GetUnion() isTest_Union {
|
||||||
|
if m != nil {
|
||||||
|
return m.Union
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
const Default_Test_Type int32 = 77
|
const Default_Test_Type int32 = 77
|
||||||
|
|
||||||
func (m *Test) GetLabel() string {
|
func (m *Test) GetLabel() string {
|
||||||
|
@ -165,13 +202,27 @@ The resulting file, test.pb.go, is:
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetNumber() int32 {
|
||||||
|
if x, ok := m.GetUnion().(*Test_Number); ok {
|
||||||
|
return x.Number
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Test) GetName() string {
|
||||||
|
if x, ok := m.GetUnion().(*Test_Name); ok {
|
||||||
|
return x.Name
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
proto.RegisterEnum("example.FOO", FOO_name, FOO_value)
|
||||||
}
|
}
|
||||||
|
|
||||||
To create and play with a Test object:
|
To create and play with a Test object:
|
||||||
|
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"log"
|
"log"
|
||||||
|
@ -184,9 +235,11 @@ package main
|
||||||
test := &pb.Test{
|
test := &pb.Test{
|
||||||
Label: proto.String("hello"),
|
Label: proto.String("hello"),
|
||||||
Type: proto.Int32(17),
|
Type: proto.Int32(17),
|
||||||
|
Reps: []int64{1, 2, 3},
|
||||||
Optionalgroup: &pb.Test_OptionalGroup{
|
Optionalgroup: &pb.Test_OptionalGroup{
|
||||||
RequiredField: proto.String("good bye"),
|
RequiredField: proto.String("good bye"),
|
||||||
},
|
},
|
||||||
|
Union: &pb.Test_Name{"fred"},
|
||||||
}
|
}
|
||||||
data, err := proto.Marshal(test)
|
data, err := proto.Marshal(test)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -201,6 +254,11 @@ package main
|
||||||
if test.GetLabel() != newTest.GetLabel() {
|
if test.GetLabel() != newTest.GetLabel() {
|
||||||
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
|
log.Fatalf("data mismatch %q != %q", test.GetLabel(), newTest.GetLabel())
|
||||||
}
|
}
|
||||||
|
// Use a type switch to determine which oneof was set.
|
||||||
|
switch u := test.Union.(type) {
|
||||||
|
case *pb.Test_Number: // u.Number contains the number.
|
||||||
|
case *pb.Test_Name: // u.Name contains the string.
|
||||||
|
}
|
||||||
// etc.
|
// etc.
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
|
@ -211,6 +269,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -459,7 +518,6 @@ out:
|
||||||
break out
|
break out
|
||||||
}
|
}
|
||||||
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
fmt.Printf("%3d: t=%3d fix64 %d\n", index, tag, u)
|
||||||
break
|
|
||||||
|
|
||||||
case WireVarint:
|
case WireVarint:
|
||||||
u, err = p.DecodeVarint()
|
u, err = p.DecodeVarint()
|
||||||
|
@ -470,19 +528,11 @@ out:
|
||||||
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
fmt.Printf("%3d: t=%3d varint %d\n", index, tag, u)
|
||||||
|
|
||||||
case WireStartGroup:
|
case WireStartGroup:
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%3d: t=%3d start err %v\n", index, tag, err)
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
fmt.Printf("%3d: t=%3d start\n", index, tag)
|
||||||
depth++
|
depth++
|
||||||
|
|
||||||
case WireEndGroup:
|
case WireEndGroup:
|
||||||
depth--
|
depth--
|
||||||
if err != nil {
|
|
||||||
fmt.Printf("%3d: t=%3d end err %v\n", index, tag, err)
|
|
||||||
break out
|
|
||||||
}
|
|
||||||
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
fmt.Printf("%3d: t=%3d end\n", index, tag)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -787,12 +837,39 @@ func fieldDefault(ft reflect.Type, prop *Properties) (sf *scalarField, nestedMes
|
||||||
// If this turns out to be inefficient we can always consider other options,
|
// If this turns out to be inefficient we can always consider other options,
|
||||||
// such as doing a Schwartzian transform.
|
// such as doing a Schwartzian transform.
|
||||||
|
|
||||||
type mapKeys []reflect.Value
|
func mapKeys(vs []reflect.Value) sort.Interface {
|
||||||
|
s := mapKeySorter{
|
||||||
|
vs: vs,
|
||||||
|
// default Less function: textual comparison
|
||||||
|
less: func(a, b reflect.Value) bool {
|
||||||
|
return fmt.Sprint(a.Interface()) < fmt.Sprint(b.Interface())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
func (s mapKeys) Len() int { return len(s) }
|
// Type specialization per https://developers.google.com/protocol-buffers/docs/proto#maps;
|
||||||
func (s mapKeys) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
// numeric keys are sorted numerically.
|
||||||
func (s mapKeys) Less(i, j int) bool {
|
if len(vs) == 0 {
|
||||||
return fmt.Sprint(s[i].Interface()) < fmt.Sprint(s[j].Interface())
|
return s
|
||||||
|
}
|
||||||
|
switch vs[0].Kind() {
|
||||||
|
case reflect.Int32, reflect.Int64:
|
||||||
|
s.less = func(a, b reflect.Value) bool { return a.Int() < b.Int() }
|
||||||
|
case reflect.Uint32, reflect.Uint64:
|
||||||
|
s.less = func(a, b reflect.Value) bool { return a.Uint() < b.Uint() }
|
||||||
|
}
|
||||||
|
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
type mapKeySorter struct {
|
||||||
|
vs []reflect.Value
|
||||||
|
less func(a, b reflect.Value) bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s mapKeySorter) Len() int { return len(s.vs) }
|
||||||
|
func (s mapKeySorter) Swap(i, j int) { s.vs[i], s.vs[j] = s.vs[j], s.vs[i] }
|
||||||
|
func (s mapKeySorter) Less(i, j int) bool {
|
||||||
|
return s.less(s.vs[i], s.vs[j])
|
||||||
}
|
}
|
||||||
|
|
||||||
// isProto3Zero reports whether v is a zero proto3 value.
|
// isProto3Zero reports whether v is a zero proto3 value.
|
||||||
|
@ -811,3 +888,7 @@ func isProto3Zero(v reflect.Value) bool {
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProtoPackageIsVersion1 is referenced from generated protocol buffer files
|
||||||
|
// to assert that that code is compatible with this version of the proto package.
|
||||||
|
const ProtoPackageIsVersion1 = true
|
||||||
|
|
41
vendor/github.com/golang/protobuf/proto/message_set.go
generated
vendored
41
vendor/github.com/golang/protobuf/proto/message_set.go
generated
vendored
|
@ -44,11 +44,11 @@ import (
|
||||||
"sort"
|
"sort"
|
||||||
)
|
)
|
||||||
|
|
||||||
// ErrNoMessageTypeId occurs when a protocol buffer does not have a message type ID.
|
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
|
||||||
// A message type ID is required for storing a protocol buffer in a message set.
|
// A message type ID is required for storing a protocol buffer in a message set.
|
||||||
var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
|
var errNoMessageTypeID = errors.New("proto does not have a message type ID")
|
||||||
|
|
||||||
// The first two types (_MessageSet_Item and MessageSet)
|
// The first two types (_MessageSet_Item and messageSet)
|
||||||
// model what the protocol compiler produces for the following protocol message:
|
// model what the protocol compiler produces for the following protocol message:
|
||||||
// message MessageSet {
|
// message MessageSet {
|
||||||
// repeated group Item = 1 {
|
// repeated group Item = 1 {
|
||||||
|
@ -58,27 +58,20 @@ var ErrNoMessageTypeId = errors.New("proto does not have a message type ID")
|
||||||
// }
|
// }
|
||||||
// That is the MessageSet wire format. We can't use a proto to generate these
|
// That is the MessageSet wire format. We can't use a proto to generate these
|
||||||
// because that would introduce a circular dependency between it and this package.
|
// because that would introduce a circular dependency between it and this package.
|
||||||
//
|
|
||||||
// When a proto1 proto has a field that looks like:
|
|
||||||
// optional message<MessageSet> info = 3;
|
|
||||||
// the protocol compiler produces a field in the generated struct that looks like:
|
|
||||||
// Info *_proto_.MessageSet `protobuf:"bytes,3,opt,name=info"`
|
|
||||||
// The package is automatically inserted so there is no need for that proto file to
|
|
||||||
// import this package.
|
|
||||||
|
|
||||||
type _MessageSet_Item struct {
|
type _MessageSet_Item struct {
|
||||||
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
TypeId *int32 `protobuf:"varint,2,req,name=type_id"`
|
||||||
Message []byte `protobuf:"bytes,3,req,name=message"`
|
Message []byte `protobuf:"bytes,3,req,name=message"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type MessageSet struct {
|
type messageSet struct {
|
||||||
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
Item []*_MessageSet_Item `protobuf:"group,1,rep"`
|
||||||
XXX_unrecognized []byte
|
XXX_unrecognized []byte
|
||||||
// TODO: caching?
|
// TODO: caching?
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make sure MessageSet is a Message.
|
// Make sure messageSet is a Message.
|
||||||
var _ Message = (*MessageSet)(nil)
|
var _ Message = (*messageSet)(nil)
|
||||||
|
|
||||||
// messageTypeIder is an interface satisfied by a protocol buffer type
|
// messageTypeIder is an interface satisfied by a protocol buffer type
|
||||||
// that may be stored in a MessageSet.
|
// that may be stored in a MessageSet.
|
||||||
|
@ -86,7 +79,7 @@ type messageTypeIder interface {
|
||||||
MessageTypeId() int32
|
MessageTypeId() int32
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
|
func (ms *messageSet) find(pb Message) *_MessageSet_Item {
|
||||||
mti, ok := pb.(messageTypeIder)
|
mti, ok := pb.(messageTypeIder)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
|
@ -100,24 +93,24 @@ func (ms *MessageSet) find(pb Message) *_MessageSet_Item {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Has(pb Message) bool {
|
func (ms *messageSet) Has(pb Message) bool {
|
||||||
if ms.find(pb) != nil {
|
if ms.find(pb) != nil {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Unmarshal(pb Message) error {
|
func (ms *messageSet) Unmarshal(pb Message) error {
|
||||||
if item := ms.find(pb); item != nil {
|
if item := ms.find(pb); item != nil {
|
||||||
return Unmarshal(item.Message, pb)
|
return Unmarshal(item.Message, pb)
|
||||||
}
|
}
|
||||||
if _, ok := pb.(messageTypeIder); !ok {
|
if _, ok := pb.(messageTypeIder); !ok {
|
||||||
return ErrNoMessageTypeId
|
return errNoMessageTypeID
|
||||||
}
|
}
|
||||||
return nil // TODO: return error instead?
|
return nil // TODO: return error instead?
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Marshal(pb Message) error {
|
func (ms *messageSet) Marshal(pb Message) error {
|
||||||
msg, err := Marshal(pb)
|
msg, err := Marshal(pb)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -130,7 +123,7 @@ func (ms *MessageSet) Marshal(pb Message) error {
|
||||||
|
|
||||||
mti, ok := pb.(messageTypeIder)
|
mti, ok := pb.(messageTypeIder)
|
||||||
if !ok {
|
if !ok {
|
||||||
return ErrNoMessageTypeId
|
return errNoMessageTypeID
|
||||||
}
|
}
|
||||||
|
|
||||||
mtid := mti.MessageTypeId()
|
mtid := mti.MessageTypeId()
|
||||||
|
@ -141,9 +134,9 @@ func (ms *MessageSet) Marshal(pb Message) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ms *MessageSet) Reset() { *ms = MessageSet{} }
|
func (ms *messageSet) Reset() { *ms = messageSet{} }
|
||||||
func (ms *MessageSet) String() string { return CompactTextString(ms) }
|
func (ms *messageSet) String() string { return CompactTextString(ms) }
|
||||||
func (*MessageSet) ProtoMessage() {}
|
func (*messageSet) ProtoMessage() {}
|
||||||
|
|
||||||
// Support for the message_set_wire_format message option.
|
// Support for the message_set_wire_format message option.
|
||||||
|
|
||||||
|
@ -169,7 +162,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
||||||
}
|
}
|
||||||
sort.Ints(ids)
|
sort.Ints(ids)
|
||||||
|
|
||||||
ms := &MessageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
ms := &messageSet{Item: make([]*_MessageSet_Item, 0, len(m))}
|
||||||
for _, id := range ids {
|
for _, id := range ids {
|
||||||
e := m[int32(id)]
|
e := m[int32(id)]
|
||||||
// Remove the wire type and field number varint, as well as the length varint.
|
// Remove the wire type and field number varint, as well as the length varint.
|
||||||
|
@ -186,7 +179,7 @@ func MarshalMessageSet(m map[int32]Extension) ([]byte, error) {
|
||||||
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
|
||||||
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
// It is called by generated Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
|
||||||
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
func UnmarshalMessageSet(buf []byte, m map[int32]Extension) error {
|
||||||
ms := new(MessageSet)
|
ms := new(messageSet)
|
||||||
if err := Unmarshal(buf, ms); err != nil {
|
if err := Unmarshal(buf, ms); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
110
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
110
vendor/github.com/golang/protobuf/proto/properties.go
generated
vendored
|
@ -37,6 +37,7 @@ package proto
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -84,6 +85,15 @@ type decoder func(p *Buffer, prop *Properties, base structPointer) error
|
||||||
// A valueDecoder decodes a single integer in a particular encoding.
|
// A valueDecoder decodes a single integer in a particular encoding.
|
||||||
type valueDecoder func(o *Buffer) (x uint64, err error)
|
type valueDecoder func(o *Buffer) (x uint64, err error)
|
||||||
|
|
||||||
|
// A oneofMarshaler does the marshaling for all oneof fields in a message.
|
||||||
|
type oneofMarshaler func(Message, *Buffer) error
|
||||||
|
|
||||||
|
// A oneofUnmarshaler does the unmarshaling for a oneof field in a message.
|
||||||
|
type oneofUnmarshaler func(Message, int, int, *Buffer) (bool, error)
|
||||||
|
|
||||||
|
// A oneofSizer does the sizing for all oneof fields in a message.
|
||||||
|
type oneofSizer func(Message) int
|
||||||
|
|
||||||
// tagMap is an optimization over map[int]int for typical protocol buffer
|
// tagMap is an optimization over map[int]int for typical protocol buffer
|
||||||
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
// use-cases. Encoded protocol buffers are often in tag order with small tag
|
||||||
// numbers.
|
// numbers.
|
||||||
|
@ -132,6 +142,22 @@ type StructProperties struct {
|
||||||
order []int // list of struct field numbers in tag order
|
order []int // list of struct field numbers in tag order
|
||||||
unrecField field // field id of the XXX_unrecognized []byte field
|
unrecField field // field id of the XXX_unrecognized []byte field
|
||||||
extendable bool // is this an extendable proto
|
extendable bool // is this an extendable proto
|
||||||
|
|
||||||
|
oneofMarshaler oneofMarshaler
|
||||||
|
oneofUnmarshaler oneofUnmarshaler
|
||||||
|
oneofSizer oneofSizer
|
||||||
|
stype reflect.Type
|
||||||
|
|
||||||
|
// OneofTypes contains information about the oneof fields in this message.
|
||||||
|
// It is keyed by the original name of a field.
|
||||||
|
OneofTypes map[string]*OneofProperties
|
||||||
|
}
|
||||||
|
|
||||||
|
// OneofProperties represents information about a specific field in a oneof.
|
||||||
|
type OneofProperties struct {
|
||||||
|
Type reflect.Type // pointer to generated struct type for this oneof field
|
||||||
|
Field int // struct field number of the containing oneof in the message
|
||||||
|
Prop *Properties
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
|
// Implement the sorting interface so we can sort the fields in tag order, as recommended by the spec.
|
||||||
|
@ -147,6 +173,7 @@ func (sp *StructProperties) Swap(i, j int) { sp.order[i], sp.order[j] = sp.order
|
||||||
type Properties struct {
|
type Properties struct {
|
||||||
Name string // name of the field, for error messages
|
Name string // name of the field, for error messages
|
||||||
OrigName string // original name before protocol compiler (always set)
|
OrigName string // original name before protocol compiler (always set)
|
||||||
|
JSONName string // name to use for JSON; determined by protoc
|
||||||
Wire string
|
Wire string
|
||||||
WireType int
|
WireType int
|
||||||
Tag int
|
Tag int
|
||||||
|
@ -156,6 +183,7 @@ type Properties struct {
|
||||||
Packed bool // relevant for repeated primitives only
|
Packed bool // relevant for repeated primitives only
|
||||||
Enum string // set for enum types only
|
Enum string // set for enum types only
|
||||||
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
proto3 bool // whether this is known to be a proto3 field; set for []byte only
|
||||||
|
oneof bool // whether this is a oneof field
|
||||||
|
|
||||||
Default string // default value
|
Default string // default value
|
||||||
HasDefault bool // whether an explicit default was provided
|
HasDefault bool // whether an explicit default was provided
|
||||||
|
@ -202,12 +230,16 @@ func (p *Properties) String() string {
|
||||||
if p.Packed {
|
if p.Packed {
|
||||||
s += ",packed"
|
s += ",packed"
|
||||||
}
|
}
|
||||||
if p.OrigName != p.Name {
|
s += ",name=" + p.OrigName
|
||||||
s += ",name=" + p.OrigName
|
if p.JSONName != p.OrigName {
|
||||||
|
s += ",json=" + p.JSONName
|
||||||
}
|
}
|
||||||
if p.proto3 {
|
if p.proto3 {
|
||||||
s += ",proto3"
|
s += ",proto3"
|
||||||
}
|
}
|
||||||
|
if p.oneof {
|
||||||
|
s += ",oneof"
|
||||||
|
}
|
||||||
if len(p.Enum) > 0 {
|
if len(p.Enum) > 0 {
|
||||||
s += ",enum=" + p.Enum
|
s += ",enum=" + p.Enum
|
||||||
}
|
}
|
||||||
|
@ -280,10 +312,14 @@ func (p *Properties) Parse(s string) {
|
||||||
p.Packed = true
|
p.Packed = true
|
||||||
case strings.HasPrefix(f, "name="):
|
case strings.HasPrefix(f, "name="):
|
||||||
p.OrigName = f[5:]
|
p.OrigName = f[5:]
|
||||||
|
case strings.HasPrefix(f, "json="):
|
||||||
|
p.JSONName = f[5:]
|
||||||
case strings.HasPrefix(f, "enum="):
|
case strings.HasPrefix(f, "enum="):
|
||||||
p.Enum = f[5:]
|
p.Enum = f[5:]
|
||||||
case f == "proto3":
|
case f == "proto3":
|
||||||
p.proto3 = true
|
p.proto3 = true
|
||||||
|
case f == "oneof":
|
||||||
|
p.oneof = true
|
||||||
case strings.HasPrefix(f, "def="):
|
case strings.HasPrefix(f, "def="):
|
||||||
p.HasDefault = true
|
p.HasDefault = true
|
||||||
p.Default = f[4:] // rest of string
|
p.Default = f[4:] // rest of string
|
||||||
|
@ -665,6 +701,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
if f.Name == "XXX_unrecognized" { // special case
|
if f.Name == "XXX_unrecognized" { // special case
|
||||||
prop.unrecField = toField(&f)
|
prop.unrecField = toField(&f)
|
||||||
}
|
}
|
||||||
|
oneof := f.Tag.Get("protobuf_oneof") != "" // special case
|
||||||
prop.Prop[i] = p
|
prop.Prop[i] = p
|
||||||
prop.order[i] = i
|
prop.order[i] = i
|
||||||
if debug {
|
if debug {
|
||||||
|
@ -674,7 +711,7 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
}
|
}
|
||||||
print("\n")
|
print("\n")
|
||||||
}
|
}
|
||||||
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") {
|
if p.enc == nil && !strings.HasPrefix(f.Name, "XXX_") && !oneof {
|
||||||
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
fmt.Fprintln(os.Stderr, "proto: no encoder for", f.Name, f.Type.String(), "[GetProperties]")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -682,6 +719,41 @@ func getPropertiesLocked(t reflect.Type) *StructProperties {
|
||||||
// Re-order prop.order.
|
// Re-order prop.order.
|
||||||
sort.Sort(prop)
|
sort.Sort(prop)
|
||||||
|
|
||||||
|
type oneofMessage interface {
|
||||||
|
XXX_OneofFuncs() (func(Message, *Buffer) error, func(Message, int, int, *Buffer) (bool, error), func(Message) int, []interface{})
|
||||||
|
}
|
||||||
|
if om, ok := reflect.Zero(reflect.PtrTo(t)).Interface().(oneofMessage); ok {
|
||||||
|
var oots []interface{}
|
||||||
|
prop.oneofMarshaler, prop.oneofUnmarshaler, prop.oneofSizer, oots = om.XXX_OneofFuncs()
|
||||||
|
prop.stype = t
|
||||||
|
|
||||||
|
// Interpret oneof metadata.
|
||||||
|
prop.OneofTypes = make(map[string]*OneofProperties)
|
||||||
|
for _, oot := range oots {
|
||||||
|
oop := &OneofProperties{
|
||||||
|
Type: reflect.ValueOf(oot).Type(), // *T
|
||||||
|
Prop: new(Properties),
|
||||||
|
}
|
||||||
|
sft := oop.Type.Elem().Field(0)
|
||||||
|
oop.Prop.Name = sft.Name
|
||||||
|
oop.Prop.Parse(sft.Tag.Get("protobuf"))
|
||||||
|
// There will be exactly one interface field that
|
||||||
|
// this new value is assignable to.
|
||||||
|
for i := 0; i < t.NumField(); i++ {
|
||||||
|
f := t.Field(i)
|
||||||
|
if f.Type.Kind() != reflect.Interface {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if !oop.Type.AssignableTo(f.Type) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
oop.Field = i
|
||||||
|
break
|
||||||
|
}
|
||||||
|
prop.OneofTypes[oop.Prop.OrigName] = oop
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// build required counts
|
// build required counts
|
||||||
// build tags
|
// build tags
|
||||||
reqCount := 0
|
reqCount := 0
|
||||||
|
@ -740,3 +812,35 @@ func RegisterEnum(typeName string, unusedNameMap map[int32]string, valueMap map[
|
||||||
}
|
}
|
||||||
enumValueMaps[typeName] = valueMap
|
enumValueMaps[typeName] = valueMap
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnumValueMap returns the mapping from names to integers of the
|
||||||
|
// enum type enumType, or a nil if not found.
|
||||||
|
func EnumValueMap(enumType string) map[string]int32 {
|
||||||
|
return enumValueMaps[enumType]
|
||||||
|
}
|
||||||
|
|
||||||
|
// A registry of all linked message types.
|
||||||
|
// The string is a fully-qualified proto name ("pkg.Message").
|
||||||
|
var (
|
||||||
|
protoTypes = make(map[string]reflect.Type)
|
||||||
|
revProtoTypes = make(map[reflect.Type]string)
|
||||||
|
)
|
||||||
|
|
||||||
|
// RegisterType is called from generated code and maps from the fully qualified
|
||||||
|
// proto name to the type (pointer to struct) of the protocol buffer.
|
||||||
|
func RegisterType(x Message, name string) {
|
||||||
|
if _, ok := protoTypes[name]; ok {
|
||||||
|
// TODO: Some day, make this a panic.
|
||||||
|
log.Printf("proto: duplicate proto type registered: %s", name)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
t := reflect.TypeOf(x)
|
||||||
|
protoTypes[name] = t
|
||||||
|
revProtoTypes[t] = name
|
||||||
|
}
|
||||||
|
|
||||||
|
// MessageName returns the fully-qualified proto name for the given message type.
|
||||||
|
func MessageName(x Message) string { return revProtoTypes[reflect.TypeOf(x)] }
|
||||||
|
|
||||||
|
// MessageType returns the message type (pointer to struct) for a named message.
|
||||||
|
func MessageType(name string) reflect.Type { return protoTypes[name] }
|
||||||
|
|
238
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
238
vendor/github.com/golang/protobuf/proto/text.go
generated
vendored
|
@ -37,6 +37,7 @@ import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding"
|
"encoding"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"log"
|
"log"
|
||||||
|
@ -169,20 +170,98 @@ func writeName(w *textWriter, props *Properties) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
messageSetType = reflect.TypeOf((*MessageSet)(nil)).Elem()
|
|
||||||
)
|
|
||||||
|
|
||||||
// raw is the interface satisfied by RawMessage.
|
// raw is the interface satisfied by RawMessage.
|
||||||
type raw interface {
|
type raw interface {
|
||||||
Bytes() []byte
|
Bytes() []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeStruct(w *textWriter, sv reflect.Value) error {
|
func requiresQuotes(u string) bool {
|
||||||
if sv.Type() == messageSetType {
|
// When type URL contains any characters except [0-9A-Za-z./\-]*, it must be quoted.
|
||||||
return writeMessageSet(w, sv.Addr().Interface().(*MessageSet))
|
for _, ch := range u {
|
||||||
|
switch {
|
||||||
|
case ch == '.' || ch == '/' || ch == '_':
|
||||||
|
continue
|
||||||
|
case '0' <= ch && ch <= '9':
|
||||||
|
continue
|
||||||
|
case 'A' <= ch && ch <= 'Z':
|
||||||
|
continue
|
||||||
|
case 'a' <= ch && ch <= 'z':
|
||||||
|
continue
|
||||||
|
default:
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// isAny reports whether sv is a google.protobuf.Any message
|
||||||
|
func isAny(sv reflect.Value) bool {
|
||||||
|
type wkt interface {
|
||||||
|
XXX_WellKnownType() string
|
||||||
|
}
|
||||||
|
t, ok := sv.Addr().Interface().(wkt)
|
||||||
|
return ok && t.XXX_WellKnownType() == "Any"
|
||||||
|
}
|
||||||
|
|
||||||
|
// writeProto3Any writes an expanded google.protobuf.Any message.
|
||||||
|
//
|
||||||
|
// It returns (false, nil) if sv value can't be unmarshaled (e.g. because
|
||||||
|
// required messages are not linked in).
|
||||||
|
//
|
||||||
|
// It returns (true, error) when sv was written in expanded format or an error
|
||||||
|
// was encountered.
|
||||||
|
func (tm *TextMarshaler) writeProto3Any(w *textWriter, sv reflect.Value) (bool, error) {
|
||||||
|
turl := sv.FieldByName("TypeUrl")
|
||||||
|
val := sv.FieldByName("Value")
|
||||||
|
if !turl.IsValid() || !val.IsValid() {
|
||||||
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b, ok := val.Interface().([]byte)
|
||||||
|
if !ok {
|
||||||
|
return true, errors.New("proto: invalid google.protobuf.Any message")
|
||||||
|
}
|
||||||
|
|
||||||
|
parts := strings.Split(turl.String(), "/")
|
||||||
|
mt := MessageType(parts[len(parts)-1])
|
||||||
|
if mt == nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
m := reflect.New(mt.Elem())
|
||||||
|
if err := Unmarshal(b, m.Interface().(Message)); err != nil {
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
w.Write([]byte("["))
|
||||||
|
u := turl.String()
|
||||||
|
if requiresQuotes(u) {
|
||||||
|
writeString(w, u)
|
||||||
|
} else {
|
||||||
|
w.Write([]byte(u))
|
||||||
|
}
|
||||||
|
if w.compact {
|
||||||
|
w.Write([]byte("]:<"))
|
||||||
|
} else {
|
||||||
|
w.Write([]byte("]: <\n"))
|
||||||
|
w.ind++
|
||||||
|
}
|
||||||
|
if err := tm.writeStruct(w, m.Elem()); err != nil {
|
||||||
|
return true, err
|
||||||
|
}
|
||||||
|
if w.compact {
|
||||||
|
w.Write([]byte("> "))
|
||||||
|
} else {
|
||||||
|
w.ind--
|
||||||
|
w.Write([]byte(">\n"))
|
||||||
|
}
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (tm *TextMarshaler) writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
|
if tm.ExpandAny && isAny(sv) {
|
||||||
|
if canExpand, err := tm.writeProto3Any(w, sv); canExpand {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
st := sv.Type()
|
st := sv.Type()
|
||||||
sprops := GetProperties(st)
|
sprops := GetProperties(st)
|
||||||
for i := 0; i < sv.NumField(); i++ {
|
for i := 0; i < sv.NumField(); i++ {
|
||||||
|
@ -234,7 +313,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if err := writeAny(w, v, props); err != nil {
|
if err := tm.writeAny(w, v, props); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
@ -245,7 +324,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
}
|
}
|
||||||
if fv.Kind() == reflect.Map {
|
if fv.Kind() == reflect.Map {
|
||||||
// Map fields are rendered as a repeated struct with key/value fields.
|
// Map fields are rendered as a repeated struct with key/value fields.
|
||||||
keys := fv.MapKeys() // TODO: should we sort these for deterministic output?
|
keys := fv.MapKeys()
|
||||||
sort.Sort(mapKeys(keys))
|
sort.Sort(mapKeys(keys))
|
||||||
for _, key := range keys {
|
for _, key := range keys {
|
||||||
val := fv.MapIndex(key)
|
val := fv.MapIndex(key)
|
||||||
|
@ -276,7 +355,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := writeAny(w, key, props.mkeyprop); err != nil {
|
if err := tm.writeAny(w, key, props.mkeyprop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
@ -293,7 +372,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := writeAny(w, val, props.mvalprop); err != nil {
|
if err := tm.writeAny(w, val, props.mvalprop); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
@ -322,6 +401,33 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if fv.Kind() == reflect.Interface {
|
||||||
|
// Check if it is a oneof.
|
||||||
|
if st.Field(i).Tag.Get("protobuf_oneof") != "" {
|
||||||
|
// fv is nil, or holds a pointer to generated struct.
|
||||||
|
// That generated struct has exactly one field,
|
||||||
|
// which has a protobuf struct tag.
|
||||||
|
if fv.IsNil() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
inner := fv.Elem().Elem() // interface -> *T -> T
|
||||||
|
tag := inner.Type().Field(0).Tag.Get("protobuf")
|
||||||
|
props = new(Properties) // Overwrite the outer props var, but not its pointee.
|
||||||
|
props.Parse(tag)
|
||||||
|
// Write the value in the oneof, not the oneof itself.
|
||||||
|
fv = inner.Field(0)
|
||||||
|
|
||||||
|
// Special case to cope with malformed messages gracefully:
|
||||||
|
// If the value in the oneof is a nil pointer, don't panic
|
||||||
|
// in writeAny.
|
||||||
|
if fv.Kind() == reflect.Ptr && fv.IsNil() {
|
||||||
|
// Use errors.New so writeAny won't render quotes.
|
||||||
|
msg := errors.New("/* nil */")
|
||||||
|
fv = reflect.ValueOf(&msg).Elem()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err := writeName(w, props); err != nil {
|
if err := writeName(w, props); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -338,7 +444,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enums have a String method, so writeAny will work fine.
|
// Enums have a String method, so writeAny will work fine.
|
||||||
if err := writeAny(w, fv, props); err != nil {
|
if err := tm.writeAny(w, fv, props); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -350,7 +456,7 @@ func writeStruct(w *textWriter, sv reflect.Value) error {
|
||||||
// Extensions (the XXX_extensions field).
|
// Extensions (the XXX_extensions field).
|
||||||
pv := sv.Addr()
|
pv := sv.Addr()
|
||||||
if pv.Type().Implements(extendableProtoType) {
|
if pv.Type().Implements(extendableProtoType) {
|
||||||
if err := writeExtensions(w, pv); err != nil {
|
if err := tm.writeExtensions(w, pv); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,7 +486,7 @@ func writeRaw(w *textWriter, b []byte) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeAny writes an arbitrary field.
|
// writeAny writes an arbitrary field.
|
||||||
func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
func (tm *TextMarshaler) writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||||
v = reflect.Indirect(v)
|
v = reflect.Indirect(v)
|
||||||
|
|
||||||
// Floats have special cases.
|
// Floats have special cases.
|
||||||
|
@ -429,15 +535,15 @@ func writeAny(w *textWriter, v reflect.Value, props *Properties) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
w.indent()
|
w.indent()
|
||||||
if tm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
if etm, ok := v.Interface().(encoding.TextMarshaler); ok {
|
||||||
text, err := tm.MarshalText()
|
text, err := etm.MarshalText()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if _, err = w.Write(text); err != nil {
|
if _, err = w.Write(text); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else if err := writeStruct(w, v); err != nil {
|
} else if err := tm.writeStruct(w, v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
w.unindent()
|
w.unindent()
|
||||||
|
@ -497,44 +603,6 @@ func writeString(w *textWriter, s string) error {
|
||||||
return w.WriteByte('"')
|
return w.WriteByte('"')
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeMessageSet(w *textWriter, ms *MessageSet) error {
|
|
||||||
for _, item := range ms.Item {
|
|
||||||
id := *item.TypeId
|
|
||||||
if msd, ok := messageSetMap[id]; ok {
|
|
||||||
// Known message set type.
|
|
||||||
if _, err := fmt.Fprintf(w, "[%s]: <\n", msd.name); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.indent()
|
|
||||||
|
|
||||||
pb := reflect.New(msd.t.Elem())
|
|
||||||
if err := Unmarshal(item.Message, pb.Interface().(Message)); err != nil {
|
|
||||||
if _, err := fmt.Fprintf(w, "/* bad message: %v */\n", err); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if err := writeStruct(w, pb.Elem()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Unknown type.
|
|
||||||
if _, err := fmt.Fprintf(w, "[%d]: <\n", id); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
w.indent()
|
|
||||||
if err := writeUnknownStruct(w, item.Message); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
w.unindent()
|
|
||||||
if _, err := w.Write(gtNewline); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
func writeUnknownStruct(w *textWriter, data []byte) (err error) {
|
||||||
if !w.compact {
|
if !w.compact {
|
||||||
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
if _, err := fmt.Fprintf(w, "/* %d unknown bytes */\n", len(data)); err != nil {
|
||||||
|
@ -619,7 +687,7 @@ func (s int32Slice) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
|
||||||
|
|
||||||
// writeExtensions writes all the extensions in pv.
|
// writeExtensions writes all the extensions in pv.
|
||||||
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
// pv is assumed to be a pointer to a protocol message struct that is extendable.
|
||||||
func writeExtensions(w *textWriter, pv reflect.Value) error {
|
func (tm *TextMarshaler) writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||||
emap := extensionMaps[pv.Type().Elem()]
|
emap := extensionMaps[pv.Type().Elem()]
|
||||||
ep := pv.Interface().(extendableProto)
|
ep := pv.Interface().(extendableProto)
|
||||||
|
|
||||||
|
@ -654,13 +722,13 @@ func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||||
|
|
||||||
// Repeated extensions will appear as a slice.
|
// Repeated extensions will appear as a slice.
|
||||||
if !desc.repeated() {
|
if !desc.repeated() {
|
||||||
if err := writeExtension(w, desc.Name, pb); err != nil {
|
if err := tm.writeExtension(w, desc.Name, pb); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
v := reflect.ValueOf(pb)
|
v := reflect.ValueOf(pb)
|
||||||
for i := 0; i < v.Len(); i++ {
|
for i := 0; i < v.Len(); i++ {
|
||||||
if err := writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
if err := tm.writeExtension(w, desc.Name, v.Index(i).Interface()); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -669,7 +737,7 @@ func writeExtensions(w *textWriter, pv reflect.Value) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func writeExtension(w *textWriter, name string, pb interface{}) error {
|
func (tm *TextMarshaler) writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||||
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
if _, err := fmt.Fprintf(w, "[%s]:", name); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -678,7 +746,7 @@ func writeExtension(w *textWriter, name string, pb interface{}) error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if err := writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
if err := tm.writeAny(w, reflect.ValueOf(pb), nil); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := w.WriteByte('\n'); err != nil {
|
if err := w.WriteByte('\n'); err != nil {
|
||||||
|
@ -703,7 +771,15 @@ func (w *textWriter) writeIndent() {
|
||||||
w.complete = false
|
w.complete = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func marshalText(w io.Writer, pb Message, compact bool) error {
|
// TextMarshaler is a configurable text format marshaler.
|
||||||
|
type TextMarshaler struct {
|
||||||
|
Compact bool // use compact text format (one line).
|
||||||
|
ExpandAny bool // expand google.protobuf.Any messages of known types
|
||||||
|
}
|
||||||
|
|
||||||
|
// Marshal writes a given protocol buffer in text format.
|
||||||
|
// The only errors returned are from w.
|
||||||
|
func (tm *TextMarshaler) Marshal(w io.Writer, pb Message) error {
|
||||||
val := reflect.ValueOf(pb)
|
val := reflect.ValueOf(pb)
|
||||||
if pb == nil || val.IsNil() {
|
if pb == nil || val.IsNil() {
|
||||||
w.Write([]byte("<nil>"))
|
w.Write([]byte("<nil>"))
|
||||||
|
@ -718,11 +794,11 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||||
aw := &textWriter{
|
aw := &textWriter{
|
||||||
w: ww,
|
w: ww,
|
||||||
complete: true,
|
complete: true,
|
||||||
compact: compact,
|
compact: tm.Compact,
|
||||||
}
|
}
|
||||||
|
|
||||||
if tm, ok := pb.(encoding.TextMarshaler); ok {
|
if etm, ok := pb.(encoding.TextMarshaler); ok {
|
||||||
text, err := tm.MarshalText()
|
text, err := etm.MarshalText()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -736,7 +812,7 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||||
}
|
}
|
||||||
// Dereference the received pointer so we don't have outer < and >.
|
// Dereference the received pointer so we don't have outer < and >.
|
||||||
v := reflect.Indirect(val)
|
v := reflect.Indirect(val)
|
||||||
if err := writeStruct(aw, v); err != nil {
|
if err := tm.writeStruct(aw, v); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if bw != nil {
|
if bw != nil {
|
||||||
|
@ -745,25 +821,29 @@ func marshalText(w io.Writer, pb Message, compact bool) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Text is the same as Marshal, but returns the string directly.
|
||||||
|
func (tm *TextMarshaler) Text(pb Message) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
tm.Marshal(&buf, pb)
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
defaultTextMarshaler = TextMarshaler{}
|
||||||
|
compactTextMarshaler = TextMarshaler{Compact: true}
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: consider removing some of the Marshal functions below.
|
||||||
|
|
||||||
// MarshalText writes a given protocol buffer in text format.
|
// MarshalText writes a given protocol buffer in text format.
|
||||||
// The only errors returned are from w.
|
// The only errors returned are from w.
|
||||||
func MarshalText(w io.Writer, pb Message) error {
|
func MarshalText(w io.Writer, pb Message) error { return defaultTextMarshaler.Marshal(w, pb) }
|
||||||
return marshalText(w, pb, false)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
// MarshalTextString is the same as MarshalText, but returns the string directly.
|
||||||
func MarshalTextString(pb Message) string {
|
func MarshalTextString(pb Message) string { return defaultTextMarshaler.Text(pb) }
|
||||||
var buf bytes.Buffer
|
|
||||||
marshalText(&buf, pb, false)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
// CompactText writes a given protocol buffer in compact text format (one line).
|
// CompactText writes a given protocol buffer in compact text format (one line).
|
||||||
func CompactText(w io.Writer, pb Message) error { return marshalText(w, pb, true) }
|
func CompactText(w io.Writer, pb Message) error { return compactTextMarshaler.Marshal(w, pb) }
|
||||||
|
|
||||||
// CompactTextString is the same as CompactText, but returns the string directly.
|
// CompactTextString is the same as CompactText, but returns the string directly.
|
||||||
func CompactTextString(pb Message) string {
|
func CompactTextString(pb Message) string { return compactTextMarshaler.Text(pb) }
|
||||||
var buf bytes.Buffer
|
|
||||||
marshalText(&buf, pb, true)
|
|
||||||
return buf.String()
|
|
||||||
}
|
|
||||||
|
|
325
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
325
vendor/github.com/golang/protobuf/proto/text_parser.go
generated
vendored
|
@ -119,6 +119,14 @@ func isWhitespace(c byte) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isQuote(c byte) bool {
|
||||||
|
switch c {
|
||||||
|
case '"', '\'':
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
func (p *textParser) skipWhitespace() {
|
func (p *textParser) skipWhitespace() {
|
||||||
i := 0
|
i := 0
|
||||||
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
for i < len(p.s) && (isWhitespace(p.s[i]) || p.s[i] == '#') {
|
||||||
|
@ -155,7 +163,7 @@ func (p *textParser) advance() {
|
||||||
p.cur.offset, p.cur.line = p.offset, p.line
|
p.cur.offset, p.cur.line = p.offset, p.line
|
||||||
p.cur.unquoted = ""
|
p.cur.unquoted = ""
|
||||||
switch p.s[0] {
|
switch p.s[0] {
|
||||||
case '<', '>', '{', '}', ':', '[', ']', ';', ',':
|
case '<', '>', '{', '}', ':', '[', ']', ';', ',', '/':
|
||||||
// Single symbol
|
// Single symbol
|
||||||
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
p.cur.value, p.s = p.s[0:1], p.s[1:len(p.s)]
|
||||||
case '"', '\'':
|
case '"', '\'':
|
||||||
|
@ -333,13 +341,13 @@ func (p *textParser) next() *token {
|
||||||
p.advance()
|
p.advance()
|
||||||
if p.done {
|
if p.done {
|
||||||
p.cur.value = ""
|
p.cur.value = ""
|
||||||
} else if len(p.cur.value) > 0 && p.cur.value[0] == '"' {
|
} else if len(p.cur.value) > 0 && isQuote(p.cur.value[0]) {
|
||||||
// Look for multiple quoted strings separated by whitespace,
|
// Look for multiple quoted strings separated by whitespace,
|
||||||
// and concatenate them.
|
// and concatenate them.
|
||||||
cat := p.cur
|
cat := p.cur
|
||||||
for {
|
for {
|
||||||
p.skipWhitespace()
|
p.skipWhitespace()
|
||||||
if p.done || p.s[0] != '"' {
|
if p.done || !isQuote(p.s[0]) {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
p.advance()
|
p.advance()
|
||||||
|
@ -385,8 +393,7 @@ func (p *textParser) missingRequiredFieldError(sv reflect.Value) *RequiredNotSet
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the index in the struct for the named field, as well as the parsed tag properties.
|
// Returns the index in the struct for the named field, as well as the parsed tag properties.
|
||||||
func structFieldByName(st reflect.Type, name string) (int, *Properties, bool) {
|
func structFieldByName(sprops *StructProperties, name string) (int, *Properties, bool) {
|
||||||
sprops := GetProperties(st)
|
|
||||||
i, ok := sprops.decoderOrigNames[name]
|
i, ok := sprops.decoderOrigNames[name]
|
||||||
if ok {
|
if ok {
|
||||||
return i, sprops.Prop[i], true
|
return i, sprops.Prop[i], true
|
||||||
|
@ -438,12 +445,16 @@ func (p *textParser) checkForColon(props *Properties, typ reflect.Type) *ParseEr
|
||||||
|
|
||||||
func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||||
st := sv.Type()
|
st := sv.Type()
|
||||||
reqCount := GetProperties(st).reqCount
|
sprops := GetProperties(st)
|
||||||
|
reqCount := sprops.reqCount
|
||||||
var reqFieldErr error
|
var reqFieldErr error
|
||||||
fieldSet := make(map[string]bool)
|
fieldSet := make(map[string]bool)
|
||||||
// A struct is a sequence of "name: value", terminated by one of
|
// A struct is a sequence of "name: value", terminated by one of
|
||||||
// '>' or '}', or the end of the input. A name may also be
|
// '>' or '}', or the end of the input. A name may also be
|
||||||
// "[extension]".
|
// "[extension]" or "[type/url]".
|
||||||
|
//
|
||||||
|
// The whole struct can also be an expanded Any message, like:
|
||||||
|
// [type/url] < ... struct contents ... >
|
||||||
for {
|
for {
|
||||||
tok := p.next()
|
tok := p.next()
|
||||||
if tok.err != nil {
|
if tok.err != nil {
|
||||||
|
@ -453,33 +464,66 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if tok.value == "[" {
|
if tok.value == "[" {
|
||||||
// Looks like an extension.
|
// Looks like an extension or an Any.
|
||||||
//
|
//
|
||||||
// TODO: Check whether we need to handle
|
// TODO: Check whether we need to handle
|
||||||
// namespace rooted names (e.g. ".something.Foo").
|
// namespace rooted names (e.g. ".something.Foo").
|
||||||
tok = p.next()
|
extName, err := p.consumeExtName()
|
||||||
if tok.err != nil {
|
if err != nil {
|
||||||
return tok.err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if s := strings.LastIndex(extName, "/"); s >= 0 {
|
||||||
|
// If it contains a slash, it's an Any type URL.
|
||||||
|
messageName := extName[s+1:]
|
||||||
|
mt := MessageType(messageName)
|
||||||
|
if mt == nil {
|
||||||
|
return p.errorf("unrecognized message %q in google.protobuf.Any", messageName)
|
||||||
|
}
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
// consume an optional colon
|
||||||
|
if tok.value == ":" {
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
v := reflect.New(mt.Elem())
|
||||||
|
if pe := p.readStruct(v.Elem(), terminator); pe != nil {
|
||||||
|
return pe
|
||||||
|
}
|
||||||
|
b, err := Marshal(v.Interface().(Message))
|
||||||
|
if err != nil {
|
||||||
|
return p.errorf("failed to marshal message of type %q: %v", messageName, err)
|
||||||
|
}
|
||||||
|
sv.FieldByName("TypeUrl").SetString(extName)
|
||||||
|
sv.FieldByName("Value").SetBytes(b)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
var desc *ExtensionDesc
|
var desc *ExtensionDesc
|
||||||
// This could be faster, but it's functional.
|
// This could be faster, but it's functional.
|
||||||
// TODO: Do something smarter than a linear scan.
|
// TODO: Do something smarter than a linear scan.
|
||||||
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
|
for _, d := range RegisteredExtensions(reflect.New(st).Interface().(Message)) {
|
||||||
if d.Name == tok.value {
|
if d.Name == extName {
|
||||||
desc = d
|
desc = d
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if desc == nil {
|
if desc == nil {
|
||||||
return p.errorf("unrecognized extension %q", tok.value)
|
return p.errorf("unrecognized extension %q", extName)
|
||||||
}
|
|
||||||
// Check the extension terminator.
|
|
||||||
tok = p.next()
|
|
||||||
if tok.err != nil {
|
|
||||||
return tok.err
|
|
||||||
}
|
|
||||||
if tok.value != "]" {
|
|
||||||
return p.errorf("unrecognized extension terminator %q", tok.value)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
props := &Properties{}
|
props := &Properties{}
|
||||||
|
@ -520,95 +564,107 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||||
sl = reflect.Append(sl, ext)
|
sl = reflect.Append(sl, ext)
|
||||||
SetExtension(ep, desc, sl.Interface())
|
SetExtension(ep, desc, sl.Interface())
|
||||||
}
|
}
|
||||||
} else {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
// This is a normal, non-extension field.
|
return err
|
||||||
name := tok.value
|
|
||||||
fi, props, ok := structFieldByName(st, name)
|
|
||||||
if !ok {
|
|
||||||
return p.errorf("unknown field name %q in %v", name, st)
|
|
||||||
}
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
dst := sv.Field(fi)
|
// This is a normal, non-extension field.
|
||||||
|
name := tok.value
|
||||||
|
var dst reflect.Value
|
||||||
|
fi, props, ok := structFieldByName(sprops, name)
|
||||||
|
if ok {
|
||||||
|
dst = sv.Field(fi)
|
||||||
|
} else if oop, ok := sprops.OneofTypes[name]; ok {
|
||||||
|
// It is a oneof.
|
||||||
|
props = oop.Prop
|
||||||
|
nv := reflect.New(oop.Type.Elem())
|
||||||
|
dst = nv.Elem().Field(0)
|
||||||
|
sv.Field(oop.Field).Set(nv)
|
||||||
|
}
|
||||||
|
if !dst.IsValid() {
|
||||||
|
return p.errorf("unknown field name %q in %v", name, st)
|
||||||
|
}
|
||||||
|
|
||||||
if dst.Kind() == reflect.Map {
|
if dst.Kind() == reflect.Map {
|
||||||
// Consume any colon.
|
// Consume any colon.
|
||||||
if err := p.checkForColon(props, dst.Type()); err != nil {
|
if err := p.checkForColon(props, dst.Type()); err != nil {
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Construct the map if it doesn't already exist.
|
|
||||||
if dst.IsNil() {
|
|
||||||
dst.Set(reflect.MakeMap(dst.Type()))
|
|
||||||
}
|
|
||||||
key := reflect.New(dst.Type().Key()).Elem()
|
|
||||||
val := reflect.New(dst.Type().Elem()).Elem()
|
|
||||||
|
|
||||||
// The map entry should be this sequence of tokens:
|
|
||||||
// < key : KEY value : VALUE >
|
|
||||||
// Technically the "key" and "value" could come in any order,
|
|
||||||
// but in practice they won't.
|
|
||||||
|
|
||||||
tok := p.next()
|
|
||||||
var terminator string
|
|
||||||
switch tok.value {
|
|
||||||
case "<":
|
|
||||||
terminator = ">"
|
|
||||||
case "{":
|
|
||||||
terminator = "}"
|
|
||||||
default:
|
|
||||||
return p.errorf("expected '{' or '<', found %q", tok.value)
|
|
||||||
}
|
|
||||||
if err := p.consumeToken("key"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.consumeToken(":"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.readAny(key, props.mkeyprop); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.consumeToken("value"); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.readAny(val, props.mvalprop); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if err := p.consumeToken(terminator); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
dst.SetMapIndex(key, val)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check that it's not already set if it's not a repeated field.
|
|
||||||
if !props.Repeated && fieldSet[name] {
|
|
||||||
return p.errorf("non-repeated field %q was repeated", name)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := p.checkForColon(props, st.Field(fi).Type); err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse into the field.
|
// Construct the map if it doesn't already exist.
|
||||||
fieldSet[name] = true
|
if dst.IsNil() {
|
||||||
if err := p.readAny(dst, props); err != nil {
|
dst.Set(reflect.MakeMap(dst.Type()))
|
||||||
if _, ok := err.(*RequiredNotSetError); !ok {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
reqFieldErr = err
|
|
||||||
} else if props.Required {
|
|
||||||
reqCount--
|
|
||||||
}
|
}
|
||||||
|
key := reflect.New(dst.Type().Key()).Elem()
|
||||||
|
val := reflect.New(dst.Type().Elem()).Elem()
|
||||||
|
|
||||||
|
// The map entry should be this sequence of tokens:
|
||||||
|
// < key : KEY value : VALUE >
|
||||||
|
// Technically the "key" and "value" could come in any order,
|
||||||
|
// but in practice they won't.
|
||||||
|
|
||||||
|
tok := p.next()
|
||||||
|
var terminator string
|
||||||
|
switch tok.value {
|
||||||
|
case "<":
|
||||||
|
terminator = ">"
|
||||||
|
case "{":
|
||||||
|
terminator = "}"
|
||||||
|
default:
|
||||||
|
return p.errorf("expected '{' or '<', found %q", tok.value)
|
||||||
|
}
|
||||||
|
if err := p.consumeToken("key"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken(":"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(key, props.mkeyprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken("value"); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.checkForColon(props.mvalprop, dst.Type().Elem()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.readAny(val, props.mvalprop); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if err := p.consumeToken(terminator); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
dst.SetMapIndex(key, val)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that it's not already set if it's not a repeated field.
|
||||||
|
if !props.Repeated && fieldSet[name] {
|
||||||
|
return p.errorf("non-repeated field %q was repeated", name)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := p.checkForColon(props, dst.Type()); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse into the field.
|
||||||
|
fieldSet[name] = true
|
||||||
|
if err := p.readAny(dst, props); err != nil {
|
||||||
|
if _, ok := err.(*RequiredNotSetError); !ok {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
reqFieldErr = err
|
||||||
|
} else if props.Required {
|
||||||
|
reqCount--
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := p.consumeOptionalSeparator(); err != nil {
|
if err := p.consumeOptionalSeparator(); err != nil {
|
||||||
|
@ -623,6 +679,35 @@ func (p *textParser) readStruct(sv reflect.Value, terminator string) error {
|
||||||
return reqFieldErr
|
return reqFieldErr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// consumeExtName consumes extension name or expanded Any type URL and the
|
||||||
|
// following ']'. It returns the name or URL consumed.
|
||||||
|
func (p *textParser) consumeExtName() (string, error) {
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return "", tok.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If extension name or type url is quoted, it's a single token.
|
||||||
|
if len(tok.value) > 2 && isQuote(tok.value[0]) && tok.value[len(tok.value)-1] == tok.value[0] {
|
||||||
|
name, err := unquoteC(tok.value[1:len(tok.value)-1], rune(tok.value[0]))
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return name, p.consumeToken("]")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Consume everything up to "]"
|
||||||
|
var parts []string
|
||||||
|
for tok.value != "]" {
|
||||||
|
parts = append(parts, tok.value)
|
||||||
|
tok = p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return "", p.errorf("unrecognized type_url or extension name: %s", tok.err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strings.Join(parts, ""), nil
|
||||||
|
}
|
||||||
|
|
||||||
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
// consumeOptionalSeparator consumes an optional semicolon or comma.
|
||||||
// It is used in readStruct to provide backward compatibility.
|
// It is used in readStruct to provide backward compatibility.
|
||||||
func (p *textParser) consumeOptionalSeparator() error {
|
func (p *textParser) consumeOptionalSeparator() error {
|
||||||
|
@ -660,18 +745,32 @@ func (p *textParser) readAny(v reflect.Value, props *Properties) error {
|
||||||
fv.Set(reflect.ValueOf(bytes))
|
fv.Set(reflect.ValueOf(bytes))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Repeated field. May already exist.
|
// Repeated field.
|
||||||
flen := fv.Len()
|
if tok.value == "[" {
|
||||||
if flen == fv.Cap() {
|
// Repeated field with list notation, like [1,2,3].
|
||||||
nav := reflect.MakeSlice(at, flen, 2*flen+1)
|
for {
|
||||||
reflect.Copy(nav, fv)
|
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
|
||||||
fv.Set(nav)
|
err := p.readAny(fv.Index(fv.Len()-1), props)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
tok := p.next()
|
||||||
|
if tok.err != nil {
|
||||||
|
return tok.err
|
||||||
|
}
|
||||||
|
if tok.value == "]" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if tok.value != "," {
|
||||||
|
return p.errorf("Expected ']' or ',' found %q", tok.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
fv.SetLen(flen + 1)
|
// One value of the repeated field.
|
||||||
|
|
||||||
// Read one.
|
|
||||||
p.back()
|
p.back()
|
||||||
return p.readAny(fv.Index(flen), props)
|
fv.Set(reflect.Append(fv, reflect.New(at.Elem()).Elem()))
|
||||||
|
return p.readAny(fv.Index(fv.Len()-1), props)
|
||||||
case reflect.Bool:
|
case reflect.Bool:
|
||||||
// Either "true", "false", 1 or 0.
|
// Either "true", "false", 1 or 0.
|
||||||
switch tok.value {
|
switch tok.value {
|
||||||
|
|
14
vendor/golang.org/x/net/context/context.go
generated
vendored
14
vendor/golang.org/x/net/context/context.go
generated
vendored
|
@ -189,7 +189,7 @@ func Background() Context {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||||
// it's unclear which Context to use or it's is not yet available (because the
|
// it's unclear which Context to use or it is not yet available (because the
|
||||||
// surrounding function has not yet been extended to accept a Context
|
// surrounding function has not yet been extended to accept a Context
|
||||||
// parameter). TODO is recognized by static analysis tools that determine
|
// parameter). TODO is recognized by static analysis tools that determine
|
||||||
// whether Contexts are propagated correctly in a program.
|
// whether Contexts are propagated correctly in a program.
|
||||||
|
@ -210,13 +210,13 @@ type CancelFunc func()
|
||||||
// call cancel as soon as the operations running in this Context complete.
|
// call cancel as soon as the operations running in this Context complete.
|
||||||
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
func WithCancel(parent Context) (ctx Context, cancel CancelFunc) {
|
||||||
c := newCancelCtx(parent)
|
c := newCancelCtx(parent)
|
||||||
propagateCancel(parent, &c)
|
propagateCancel(parent, c)
|
||||||
return &c, func() { c.cancel(true, Canceled) }
|
return c, func() { c.cancel(true, Canceled) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// newCancelCtx returns an initialized cancelCtx.
|
// newCancelCtx returns an initialized cancelCtx.
|
||||||
func newCancelCtx(parent Context) cancelCtx {
|
func newCancelCtx(parent Context) *cancelCtx {
|
||||||
return cancelCtx{
|
return &cancelCtx{
|
||||||
Context: parent,
|
Context: parent,
|
||||||
done: make(chan struct{}),
|
done: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
@ -259,7 +259,7 @@ func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||||
case *cancelCtx:
|
case *cancelCtx:
|
||||||
return c, true
|
return c, true
|
||||||
case *timerCtx:
|
case *timerCtx:
|
||||||
return &c.cancelCtx, true
|
return c.cancelCtx, true
|
||||||
case *valueCtx:
|
case *valueCtx:
|
||||||
parent = c.Context
|
parent = c.Context
|
||||||
default:
|
default:
|
||||||
|
@ -377,7 +377,7 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||||
// implement Done and Err. It implements cancel by stopping its timer then
|
// implement Done and Err. It implements cancel by stopping its timer then
|
||||||
// delegating to cancelCtx.cancel.
|
// delegating to cancelCtx.cancel.
|
||||||
type timerCtx struct {
|
type timerCtx struct {
|
||||||
cancelCtx
|
*cancelCtx
|
||||||
timer *time.Timer // Under cancelCtx.mu.
|
timer *time.Timer // Under cancelCtx.mu.
|
||||||
|
|
||||||
deadline time.Time
|
deadline time.Time
|
||||||
|
|
19
vendor/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
19
vendor/golang.org/x/net/context/ctxhttp/cancelreq.go
generated
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func canceler(client *http.Client, req *http.Request) func() {
|
||||||
|
// TODO(djd): Respect any existing value of req.Cancel.
|
||||||
|
ch := make(chan struct{})
|
||||||
|
req.Cancel = ch
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
close(ch)
|
||||||
|
}
|
||||||
|
}
|
23
vendor/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
23
vendor/golang.org/x/net/context/ctxhttp/cancelreq_go14.go
generated
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type requestCanceler interface {
|
||||||
|
CancelRequest(*http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
func canceler(client *http.Client, req *http.Request) func() {
|
||||||
|
rc, ok := client.Transport.(requestCanceler)
|
||||||
|
if !ok {
|
||||||
|
return func() {}
|
||||||
|
}
|
||||||
|
return func() {
|
||||||
|
rc.CancelRequest(req)
|
||||||
|
}
|
||||||
|
}
|
145
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
145
vendor/golang.org/x/net/context/ctxhttp/ctxhttp.go
generated
vendored
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
// Copyright 2015 The Go 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 ctxhttp provides helper functions for performing context-aware HTTP requests.
|
||||||
|
package ctxhttp
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func nop() {}
|
||||||
|
|
||||||
|
var (
|
||||||
|
testHookContextDoneBeforeHeaders = nop
|
||||||
|
testHookDoReturned = nop
|
||||||
|
testHookDidBodyClose = nop
|
||||||
|
)
|
||||||
|
|
||||||
|
// Do sends an HTTP request with the provided http.Client and returns an HTTP response.
|
||||||
|
// If the client is nil, http.DefaultClient is used.
|
||||||
|
// If the context is canceled or times out, ctx.Err() will be returned.
|
||||||
|
func Do(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
|
||||||
|
if client == nil {
|
||||||
|
client = http.DefaultClient
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request cancelation changed in Go 1.5, see cancelreq.go and cancelreq_go14.go.
|
||||||
|
cancel := canceler(client, req)
|
||||||
|
|
||||||
|
type responseAndError struct {
|
||||||
|
resp *http.Response
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
result := make(chan responseAndError, 1)
|
||||||
|
|
||||||
|
// Make local copies of test hooks closed over by goroutines below.
|
||||||
|
// Prevents data races in tests.
|
||||||
|
testHookDoReturned := testHookDoReturned
|
||||||
|
testHookDidBodyClose := testHookDidBodyClose
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
testHookDoReturned()
|
||||||
|
result <- responseAndError{resp, err}
|
||||||
|
}()
|
||||||
|
|
||||||
|
var resp *http.Response
|
||||||
|
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
testHookContextDoneBeforeHeaders()
|
||||||
|
cancel()
|
||||||
|
// Clean up after the goroutine calling client.Do:
|
||||||
|
go func() {
|
||||||
|
if r := <-result; r.resp != nil {
|
||||||
|
testHookDidBodyClose()
|
||||||
|
r.resp.Body.Close()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case r := <-result:
|
||||||
|
var err error
|
||||||
|
resp, err = r.resp, r.err
|
||||||
|
if err != nil {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
c := make(chan struct{})
|
||||||
|
go func() {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
cancel()
|
||||||
|
case <-c:
|
||||||
|
// The response's Body is closed.
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
resp.Body = ¬ifyingReader{resp.Body, c}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get issues a GET request via the Do function.
|
||||||
|
func Get(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Head issues a HEAD request via the Do function.
|
||||||
|
func Head(ctx context.Context, client *http.Client, url string) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("HEAD", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post issues a POST request via the Do function.
|
||||||
|
func Post(ctx context.Context, client *http.Client, url string, bodyType string, body io.Reader) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", url, body)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Type", bodyType)
|
||||||
|
return Do(ctx, client, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostForm issues a POST request via the Do function.
|
||||||
|
func PostForm(ctx context.Context, client *http.Client, url string, data url.Values) (*http.Response, error) {
|
||||||
|
return Post(ctx, client, url, "application/x-www-form-urlencoded", strings.NewReader(data.Encode()))
|
||||||
|
}
|
||||||
|
|
||||||
|
// notifyingReader is an io.ReadCloser that closes the notify channel after
|
||||||
|
// Close is called or a Read fails on the underlying ReadCloser.
|
||||||
|
type notifyingReader struct {
|
||||||
|
io.ReadCloser
|
||||||
|
notify chan<- struct{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Read(p []byte) (int, error) {
|
||||||
|
n, err := r.ReadCloser.Read(p)
|
||||||
|
if err != nil && r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *notifyingReader) Close() error {
|
||||||
|
err := r.ReadCloser.Close()
|
||||||
|
if r.notify != nil {
|
||||||
|
close(r.notify)
|
||||||
|
r.notify = nil
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
15
vendor/github.com/bradfitz/http2/Dockerfile → vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
15
vendor/github.com/bradfitz/http2/Dockerfile → vendor/golang.org/x/net/http2/Dockerfile
generated
vendored
|
@ -17,8 +17,15 @@ RUN apt-get install -y --no-install-recommends \
|
||||||
libcunit1-dev libssl-dev libxml2-dev libevent-dev \
|
libcunit1-dev libssl-dev libxml2-dev libevent-dev \
|
||||||
automake autoconf
|
automake autoconf
|
||||||
|
|
||||||
|
# The list of packages nghttp2 recommends for h2load:
|
||||||
|
RUN apt-get install -y --no-install-recommends make binutils \
|
||||||
|
autoconf automake autotools-dev \
|
||||||
|
libtool pkg-config zlib1g-dev libcunit1-dev libssl-dev libxml2-dev \
|
||||||
|
libev-dev libevent-dev libjansson-dev libjemalloc-dev \
|
||||||
|
cython python3.4-dev python-setuptools
|
||||||
|
|
||||||
# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
|
# Note: setting NGHTTP2_VER before the git clone, so an old git clone isn't cached:
|
||||||
ENV NGHTTP2_VER af24f8394e43f4
|
ENV NGHTTP2_VER 895da9a
|
||||||
RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
|
RUN cd /root && git clone https://github.com/tatsuhiro-t/nghttp2.git
|
||||||
|
|
||||||
WORKDIR /root/nghttp2
|
WORKDIR /root/nghttp2
|
||||||
|
@ -31,9 +38,9 @@ RUN make
|
||||||
RUN make install
|
RUN make install
|
||||||
|
|
||||||
WORKDIR /root
|
WORKDIR /root
|
||||||
RUN wget http://curl.haxx.se/download/curl-7.40.0.tar.gz
|
RUN wget http://curl.haxx.se/download/curl-7.45.0.tar.gz
|
||||||
RUN tar -zxvf curl-7.40.0.tar.gz
|
RUN tar -zxvf curl-7.45.0.tar.gz
|
||||||
WORKDIR /root/curl-7.40.0
|
WORKDIR /root/curl-7.45.0
|
||||||
RUN ./configure --with-ssl --with-nghttp2=/usr/local
|
RUN ./configure --with-ssl --with-nghttp2=/usr/local
|
||||||
RUN make
|
RUN make
|
||||||
RUN make install
|
RUN make install
|
0
vendor/github.com/bradfitz/http2/Makefile → vendor/golang.org/x/net/http2/Makefile
generated
vendored
0
vendor/github.com/bradfitz/http2/Makefile → vendor/golang.org/x/net/http2/Makefile
generated
vendored
7
vendor/github.com/bradfitz/http2/README → vendor/golang.org/x/net/http2/README
generated
vendored
7
vendor/github.com/bradfitz/http2/README → vendor/golang.org/x/net/http2/README
generated
vendored
|
@ -10,8 +10,11 @@ Status:
|
||||||
* The client work has just started but shares a lot of code
|
* The client work has just started but shares a lot of code
|
||||||
is coming along much quicker.
|
is coming along much quicker.
|
||||||
|
|
||||||
Docs are at https://godoc.org/github.com/bradfitz/http2
|
Docs are at https://godoc.org/golang.org/x/net/http2
|
||||||
|
|
||||||
Demo test server at https://http2.golang.org/
|
Demo test server at https://http2.golang.org/
|
||||||
|
|
||||||
Help & bug reports welcome.
|
Help & bug reports welcome!
|
||||||
|
|
||||||
|
Contributing: https://golang.org/doc/contribute.html
|
||||||
|
Bugs: https://golang.org/issue/new?title=x/net/http2:+
|
225
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
225
vendor/golang.org/x/net/http2/client_conn_pool.go
generated
vendored
Normal file
|
@ -0,0 +1,225 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Transport code's client connection pooling.
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ClientConnPool manages a pool of HTTP/2 client connections.
|
||||||
|
type ClientConnPool interface {
|
||||||
|
GetClientConn(req *http.Request, addr string) (*ClientConn, error)
|
||||||
|
MarkDead(*ClientConn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: use singleflight for dialing and addConnCalls?
|
||||||
|
type clientConnPool struct {
|
||||||
|
t *Transport
|
||||||
|
|
||||||
|
mu sync.Mutex // TODO: maybe switch to RWMutex
|
||||||
|
// TODO: add support for sharing conns based on cert names
|
||||||
|
// (e.g. share conn for googleapis.com and appspot.com)
|
||||||
|
conns map[string][]*ClientConn // key is host:port
|
||||||
|
dialing map[string]*dialCall // currently in-flight dials
|
||||||
|
keys map[*ClientConn][]string
|
||||||
|
addConnCalls map[string]*addConnCall // in-flight addConnIfNeede calls
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
|
||||||
|
return p.getClientConn(req, addr, dialOnMiss)
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
dialOnMiss = true
|
||||||
|
noDialOnMiss = false
|
||||||
|
)
|
||||||
|
|
||||||
|
func (p *clientConnPool) getClientConn(_ *http.Request, addr string, dialOnMiss bool) (*ClientConn, error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
for _, cc := range p.conns[addr] {
|
||||||
|
if cc.CanTakeNewRequest() {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return cc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !dialOnMiss {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return nil, ErrNoCachedConn
|
||||||
|
}
|
||||||
|
call := p.getStartDialLocked(addr)
|
||||||
|
p.mu.Unlock()
|
||||||
|
<-call.done
|
||||||
|
return call.res, call.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// dialCall is an in-flight Transport dial call to a host.
|
||||||
|
type dialCall struct {
|
||||||
|
p *clientConnPool
|
||||||
|
done chan struct{} // closed when done
|
||||||
|
res *ClientConn // valid after done is closed
|
||||||
|
err error // valid after done is closed
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires p.mu is held.
|
||||||
|
func (p *clientConnPool) getStartDialLocked(addr string) *dialCall {
|
||||||
|
if call, ok := p.dialing[addr]; ok {
|
||||||
|
// A dial is already in-flight. Don't start another.
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
call := &dialCall{p: p, done: make(chan struct{})}
|
||||||
|
if p.dialing == nil {
|
||||||
|
p.dialing = make(map[string]*dialCall)
|
||||||
|
}
|
||||||
|
p.dialing[addr] = call
|
||||||
|
go call.dial(addr)
|
||||||
|
return call
|
||||||
|
}
|
||||||
|
|
||||||
|
// run in its own goroutine.
|
||||||
|
func (c *dialCall) dial(addr string) {
|
||||||
|
c.res, c.err = c.p.t.dialClientConn(addr)
|
||||||
|
close(c.done)
|
||||||
|
|
||||||
|
c.p.mu.Lock()
|
||||||
|
delete(c.p.dialing, addr)
|
||||||
|
if c.err == nil {
|
||||||
|
c.p.addConnLocked(addr, c.res)
|
||||||
|
}
|
||||||
|
c.p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// addConnIfNeeded makes a NewClientConn out of c if a connection for key doesn't
|
||||||
|
// already exist. It coalesces concurrent calls with the same key.
|
||||||
|
// This is used by the http1 Transport code when it creates a new connection. Because
|
||||||
|
// the http1 Transport doesn't de-dup TCP dials to outbound hosts (because it doesn't know
|
||||||
|
// the protocol), it can get into a situation where it has multiple TLS connections.
|
||||||
|
// This code decides which ones live or die.
|
||||||
|
// The return value used is whether c was used.
|
||||||
|
// c is never closed.
|
||||||
|
func (p *clientConnPool) addConnIfNeeded(key string, t *Transport, c *tls.Conn) (used bool, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
for _, cc := range p.conns[key] {
|
||||||
|
if cc.CanTakeNewRequest() {
|
||||||
|
p.mu.Unlock()
|
||||||
|
return false, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
call, dup := p.addConnCalls[key]
|
||||||
|
if !dup {
|
||||||
|
if p.addConnCalls == nil {
|
||||||
|
p.addConnCalls = make(map[string]*addConnCall)
|
||||||
|
}
|
||||||
|
call = &addConnCall{
|
||||||
|
p: p,
|
||||||
|
done: make(chan struct{}),
|
||||||
|
}
|
||||||
|
p.addConnCalls[key] = call
|
||||||
|
go call.run(t, key, c)
|
||||||
|
}
|
||||||
|
p.mu.Unlock()
|
||||||
|
|
||||||
|
<-call.done
|
||||||
|
if call.err != nil {
|
||||||
|
return false, call.err
|
||||||
|
}
|
||||||
|
return !dup, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type addConnCall struct {
|
||||||
|
p *clientConnPool
|
||||||
|
done chan struct{} // closed when done
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *addConnCall) run(t *Transport, key string, tc *tls.Conn) {
|
||||||
|
cc, err := t.NewClientConn(tc)
|
||||||
|
|
||||||
|
p := c.p
|
||||||
|
p.mu.Lock()
|
||||||
|
if err != nil {
|
||||||
|
c.err = err
|
||||||
|
} else {
|
||||||
|
p.addConnLocked(key, cc)
|
||||||
|
}
|
||||||
|
delete(p.addConnCalls, key)
|
||||||
|
p.mu.Unlock()
|
||||||
|
close(c.done)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) addConn(key string, cc *ClientConn) {
|
||||||
|
p.mu.Lock()
|
||||||
|
p.addConnLocked(key, cc)
|
||||||
|
p.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
// p.mu must be held
|
||||||
|
func (p *clientConnPool) addConnLocked(key string, cc *ClientConn) {
|
||||||
|
for _, v := range p.conns[key] {
|
||||||
|
if v == cc {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p.conns == nil {
|
||||||
|
p.conns = make(map[string][]*ClientConn)
|
||||||
|
}
|
||||||
|
if p.keys == nil {
|
||||||
|
p.keys = make(map[*ClientConn][]string)
|
||||||
|
}
|
||||||
|
p.conns[key] = append(p.conns[key], cc)
|
||||||
|
p.keys[cc] = append(p.keys[cc], key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) MarkDead(cc *ClientConn) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
for _, key := range p.keys[cc] {
|
||||||
|
vv, ok := p.conns[key]
|
||||||
|
if !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
newList := filterOutClientConn(vv, cc)
|
||||||
|
if len(newList) > 0 {
|
||||||
|
p.conns[key] = newList
|
||||||
|
} else {
|
||||||
|
delete(p.conns, key)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
delete(p.keys, cc)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *clientConnPool) closeIdleConnections() {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
// TODO: don't close a cc if it was just added to the pool
|
||||||
|
// milliseconds ago and has never been used. There's currently
|
||||||
|
// a small race window with the HTTP/1 Transport's integration
|
||||||
|
// where it can add an idle conn just before using it, and
|
||||||
|
// somebody else can concurrently call CloseIdleConns and
|
||||||
|
// break some caller's RoundTrip.
|
||||||
|
for _, vv := range p.conns {
|
||||||
|
for _, cc := range vv {
|
||||||
|
cc.closeIfIdle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func filterOutClientConn(in []*ClientConn, exclude *ClientConn) []*ClientConn {
|
||||||
|
out := in[:0]
|
||||||
|
for _, v := range in {
|
||||||
|
if v != exclude {
|
||||||
|
out = append(out, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If we filtered it out, zero out the last item to prevent
|
||||||
|
// the GC from seeing it.
|
||||||
|
if len(in) != len(out) {
|
||||||
|
in[len(in)-1] = nil
|
||||||
|
}
|
||||||
|
return out
|
||||||
|
}
|
89
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
89
vendor/golang.org/x/net/http2/configure_transport.go
generated
vendored
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||||
|
connPool := new(clientConnPool)
|
||||||
|
t2 := &Transport{
|
||||||
|
ConnPool: noDialClientConnPool{connPool},
|
||||||
|
t1: t1,
|
||||||
|
}
|
||||||
|
connPool.t = t2
|
||||||
|
if err := registerHTTPSProtocol(t1, noDialH2RoundTripper{t2}); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if t1.TLSClientConfig == nil {
|
||||||
|
t1.TLSClientConfig = new(tls.Config)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "h2") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append([]string{"h2"}, t1.TLSClientConfig.NextProtos...)
|
||||||
|
}
|
||||||
|
if !strSliceContains(t1.TLSClientConfig.NextProtos, "http/1.1") {
|
||||||
|
t1.TLSClientConfig.NextProtos = append(t1.TLSClientConfig.NextProtos, "http/1.1")
|
||||||
|
}
|
||||||
|
upgradeFn := func(authority string, c *tls.Conn) http.RoundTripper {
|
||||||
|
addr := authorityAddr(authority)
|
||||||
|
if used, err := connPool.addConnIfNeeded(addr, t2, c); err != nil {
|
||||||
|
go c.Close()
|
||||||
|
return erringRoundTripper{err}
|
||||||
|
} else if !used {
|
||||||
|
// Turns out we don't need this c.
|
||||||
|
// For example, two goroutines made requests to the same host
|
||||||
|
// at the same time, both kicking off TCP dials. (since protocol
|
||||||
|
// was unknown)
|
||||||
|
go c.Close()
|
||||||
|
}
|
||||||
|
return t2
|
||||||
|
}
|
||||||
|
if m := t1.TLSNextProto; len(m) == 0 {
|
||||||
|
t1.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{
|
||||||
|
"h2": upgradeFn,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
m["h2"] = upgradeFn
|
||||||
|
}
|
||||||
|
return t2, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// registerHTTPSProtocol calls Transport.RegisterProtocol but
|
||||||
|
// convering panics into errors.
|
||||||
|
func registerHTTPSProtocol(t *http.Transport, rt http.RoundTripper) (err error) {
|
||||||
|
defer func() {
|
||||||
|
if e := recover(); e != nil {
|
||||||
|
err = fmt.Errorf("%v", e)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
t.RegisterProtocol("https", rt)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// noDialClientConnPool is an implementation of http2.ClientConnPool
|
||||||
|
// which never dials. We let the HTTP/1.1 client dial and use its TLS
|
||||||
|
// connection instead.
|
||||||
|
type noDialClientConnPool struct{ *clientConnPool }
|
||||||
|
|
||||||
|
func (p noDialClientConnPool) GetClientConn(req *http.Request, addr string) (*ClientConn, error) {
|
||||||
|
return p.getClientConn(req, addr, noDialOnMiss)
|
||||||
|
}
|
||||||
|
|
||||||
|
// noDialH2RoundTripper is a RoundTripper which only tries to complete the request
|
||||||
|
// if there's already has a cached connection to the host.
|
||||||
|
type noDialH2RoundTripper struct{ t *Transport }
|
||||||
|
|
||||||
|
func (rt noDialH2RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||||
|
res, err := rt.t.RoundTrip(req)
|
||||||
|
if err == ErrNoCachedConn {
|
||||||
|
return nil, http.ErrSkipAltProtocol
|
||||||
|
}
|
||||||
|
return res, err
|
||||||
|
}
|
54
vendor/github.com/bradfitz/http2/errors.go → vendor/golang.org/x/net/http2/errors.go
generated
vendored
54
vendor/github.com/bradfitz/http2/errors.go → vendor/golang.org/x/net/http2/errors.go
generated
vendored
|
@ -1,11 +1,13 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
package http2
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
|
// An ErrCode is an unsigned 32-bit error code as defined in the HTTP/2 spec.
|
||||||
type ErrCode uint32
|
type ErrCode uint32
|
||||||
|
@ -76,3 +78,45 @@ func (e StreamError) Error() string {
|
||||||
type goAwayFlowError struct{}
|
type goAwayFlowError struct{}
|
||||||
|
|
||||||
func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
|
func (goAwayFlowError) Error() string { return "connection exceeded flow control window size" }
|
||||||
|
|
||||||
|
// connErrorReason wraps a ConnectionError with an informative error about why it occurs.
|
||||||
|
|
||||||
|
// Errors of this type are only returned by the frame parser functions
|
||||||
|
// and converted into ConnectionError(ErrCodeProtocol).
|
||||||
|
type connError struct {
|
||||||
|
Code ErrCode
|
||||||
|
Reason string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e connError) Error() string {
|
||||||
|
return fmt.Sprintf("http2: connection error: %v: %v", e.Code, e.Reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
type pseudoHeaderError string
|
||||||
|
|
||||||
|
func (e pseudoHeaderError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid pseudo-header %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type duplicatePseudoHeaderError string
|
||||||
|
|
||||||
|
func (e duplicatePseudoHeaderError) Error() string {
|
||||||
|
return fmt.Sprintf("duplicate pseudo-header %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerFieldNameError string
|
||||||
|
|
||||||
|
func (e headerFieldNameError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid header field name %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
type headerFieldValueError string
|
||||||
|
|
||||||
|
func (e headerFieldValueError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid header field value %q", string(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errMixPseudoHeaderTypes = errors.New("mix of request and response pseudo headers")
|
||||||
|
errPseudoAfterRegular = errors.New("pseudo header field after regular")
|
||||||
|
)
|
60
vendor/golang.org/x/net/http2/fixed_buffer.go
generated
vendored
Normal file
60
vendor/golang.org/x/net/http2/fixed_buffer.go
generated
vendored
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// Copyright 2014 The Go 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
)
|
||||||
|
|
||||||
|
// fixedBuffer is an io.ReadWriter backed by a fixed size buffer.
|
||||||
|
// It never allocates, but moves old data as new data is written.
|
||||||
|
type fixedBuffer struct {
|
||||||
|
buf []byte
|
||||||
|
r, w int
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errReadEmpty = errors.New("read from empty fixedBuffer")
|
||||||
|
errWriteFull = errors.New("write on full fixedBuffer")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Read copies bytes from the buffer into p.
|
||||||
|
// It is an error to read when no data is available.
|
||||||
|
func (b *fixedBuffer) Read(p []byte) (n int, err error) {
|
||||||
|
if b.r == b.w {
|
||||||
|
return 0, errReadEmpty
|
||||||
|
}
|
||||||
|
n = copy(p, b.buf[b.r:b.w])
|
||||||
|
b.r += n
|
||||||
|
if b.r == b.w {
|
||||||
|
b.r = 0
|
||||||
|
b.w = 0
|
||||||
|
}
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Len returns the number of bytes of the unread portion of the buffer.
|
||||||
|
func (b *fixedBuffer) Len() int {
|
||||||
|
return b.w - b.r
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write copies bytes from p into the buffer.
|
||||||
|
// It is an error to write more data than the buffer can hold.
|
||||||
|
func (b *fixedBuffer) Write(p []byte) (n int, err error) {
|
||||||
|
// Slide existing data to beginning.
|
||||||
|
if b.r > 0 && len(p) > len(b.buf)-b.w {
|
||||||
|
copy(b.buf, b.buf[b.r:b.w])
|
||||||
|
b.w -= b.r
|
||||||
|
b.r = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write new data.
|
||||||
|
n = copy(b.buf[b.w:], p)
|
||||||
|
b.w += n
|
||||||
|
if n < len(p) {
|
||||||
|
err = errWriteFull
|
||||||
|
}
|
||||||
|
return n, err
|
||||||
|
}
|
7
vendor/github.com/bradfitz/http2/flow.go → vendor/golang.org/x/net/http2/flow.go
generated
vendored
7
vendor/github.com/bradfitz/http2/flow.go → vendor/golang.org/x/net/http2/flow.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
// Flow control
|
// Flow control
|
||||||
|
|
431
vendor/github.com/bradfitz/http2/frame.go → vendor/golang.org/x/net/http2/frame.go
generated
vendored
431
vendor/github.com/bradfitz/http2/frame.go → vendor/golang.org/x/net/http2/frame.go
generated
vendored
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
package http2
|
||||||
|
|
||||||
|
@ -11,7 +10,11 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"log"
|
||||||
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"golang.org/x/net/http2/hpack"
|
||||||
)
|
)
|
||||||
|
|
||||||
const frameHeaderLen = 9
|
const frameHeaderLen = 9
|
||||||
|
@ -172,6 +175,12 @@ func (h FrameHeader) Header() FrameHeader { return h }
|
||||||
func (h FrameHeader) String() string {
|
func (h FrameHeader) String() string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString("[FrameHeader ")
|
buf.WriteString("[FrameHeader ")
|
||||||
|
h.writeDebug(&buf)
|
||||||
|
buf.WriteByte(']')
|
||||||
|
return buf.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h FrameHeader) writeDebug(buf *bytes.Buffer) {
|
||||||
buf.WriteString(h.Type.String())
|
buf.WriteString(h.Type.String())
|
||||||
if h.Flags != 0 {
|
if h.Flags != 0 {
|
||||||
buf.WriteString(" flags=")
|
buf.WriteString(" flags=")
|
||||||
|
@ -188,15 +197,14 @@ func (h FrameHeader) String() string {
|
||||||
if name != "" {
|
if name != "" {
|
||||||
buf.WriteString(name)
|
buf.WriteString(name)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&buf, "0x%x", 1<<i)
|
fmt.Fprintf(buf, "0x%x", 1<<i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if h.StreamID != 0 {
|
if h.StreamID != 0 {
|
||||||
fmt.Fprintf(&buf, " stream=%d", h.StreamID)
|
fmt.Fprintf(buf, " stream=%d", h.StreamID)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&buf, " len=%d]", h.Length)
|
fmt.Fprintf(buf, " len=%d", h.Length)
|
||||||
return buf.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *FrameHeader) checkValid() {
|
func (h *FrameHeader) checkValid() {
|
||||||
|
@ -256,6 +264,11 @@ type Frame interface {
|
||||||
type Framer struct {
|
type Framer struct {
|
||||||
r io.Reader
|
r io.Reader
|
||||||
lastFrame Frame
|
lastFrame Frame
|
||||||
|
errDetail error
|
||||||
|
|
||||||
|
// lastHeaderStream is non-zero if the last frame was an
|
||||||
|
// unfinished HEADERS/CONTINUATION.
|
||||||
|
lastHeaderStream uint32
|
||||||
|
|
||||||
maxReadSize uint32
|
maxReadSize uint32
|
||||||
headerBuf [frameHeaderLen]byte
|
headerBuf [frameHeaderLen]byte
|
||||||
|
@ -272,18 +285,48 @@ type Framer struct {
|
||||||
wbuf []byte
|
wbuf []byte
|
||||||
|
|
||||||
// AllowIllegalWrites permits the Framer's Write methods to
|
// AllowIllegalWrites permits the Framer's Write methods to
|
||||||
// write frames that do not conform to the HTTP/2 spec. This
|
// write frames that do not conform to the HTTP/2 spec. This
|
||||||
// permits using the Framer to test other HTTP/2
|
// permits using the Framer to test other HTTP/2
|
||||||
// implementations' conformance to the spec.
|
// implementations' conformance to the spec.
|
||||||
// If false, the Write methods will prefer to return an error
|
// If false, the Write methods will prefer to return an error
|
||||||
// rather than comply.
|
// rather than comply.
|
||||||
AllowIllegalWrites bool
|
AllowIllegalWrites bool
|
||||||
|
|
||||||
|
// AllowIllegalReads permits the Framer's ReadFrame method
|
||||||
|
// to return non-compliant frames or frame orders.
|
||||||
|
// This is for testing and permits using the Framer to test
|
||||||
|
// other HTTP/2 implementations' conformance to the spec.
|
||||||
|
// It is not compatible with ReadMetaHeaders.
|
||||||
|
AllowIllegalReads bool
|
||||||
|
|
||||||
|
// ReadMetaHeaders if non-nil causes ReadFrame to merge
|
||||||
|
// HEADERS and CONTINUATION frames together and return
|
||||||
|
// MetaHeadersFrame instead.
|
||||||
|
ReadMetaHeaders *hpack.Decoder
|
||||||
|
|
||||||
|
// MaxHeaderListSize is the http2 MAX_HEADER_LIST_SIZE.
|
||||||
|
// It's used only if ReadMetaHeaders is set; 0 means a sane default
|
||||||
|
// (currently 16MB)
|
||||||
|
// If the limit is hit, MetaHeadersFrame.Truncated is set true.
|
||||||
|
MaxHeaderListSize uint32
|
||||||
|
|
||||||
// TODO: track which type of frame & with which flags was sent
|
// TODO: track which type of frame & with which flags was sent
|
||||||
// last. Then return an error (unless AllowIllegalWrites) if
|
// last. Then return an error (unless AllowIllegalWrites) if
|
||||||
// we're in the middle of a header block and a
|
// we're in the middle of a header block and a
|
||||||
// non-Continuation or Continuation on a different stream is
|
// non-Continuation or Continuation on a different stream is
|
||||||
// attempted to be written.
|
// attempted to be written.
|
||||||
|
|
||||||
|
logReads bool
|
||||||
|
|
||||||
|
debugFramer *Framer // only use for logging written writes
|
||||||
|
debugFramerBuf *bytes.Buffer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *Framer) maxHeaderListSize() uint32 {
|
||||||
|
if fr.MaxHeaderListSize == 0 {
|
||||||
|
return 16 << 20 // sane default, per docs
|
||||||
|
}
|
||||||
|
return fr.MaxHeaderListSize
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
|
func (f *Framer) startWrite(ftype FrameType, flags Flags, streamID uint32) {
|
||||||
|
@ -311,6 +354,10 @@ func (f *Framer) endWrite() error {
|
||||||
byte(length>>16),
|
byte(length>>16),
|
||||||
byte(length>>8),
|
byte(length>>8),
|
||||||
byte(length))
|
byte(length))
|
||||||
|
if logFrameWrites {
|
||||||
|
f.logWrite()
|
||||||
|
}
|
||||||
|
|
||||||
n, err := f.w.Write(f.wbuf)
|
n, err := f.w.Write(f.wbuf)
|
||||||
if err == nil && n != len(f.wbuf) {
|
if err == nil && n != len(f.wbuf) {
|
||||||
err = io.ErrShortWrite
|
err = io.ErrShortWrite
|
||||||
|
@ -318,6 +365,24 @@ func (f *Framer) endWrite() error {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *Framer) logWrite() {
|
||||||
|
if f.debugFramer == nil {
|
||||||
|
f.debugFramerBuf = new(bytes.Buffer)
|
||||||
|
f.debugFramer = NewFramer(nil, f.debugFramerBuf)
|
||||||
|
f.debugFramer.logReads = false // we log it ourselves, saying "wrote" below
|
||||||
|
// Let us read anything, even if we accidentally wrote it
|
||||||
|
// in the wrong order:
|
||||||
|
f.debugFramer.AllowIllegalReads = true
|
||||||
|
}
|
||||||
|
f.debugFramerBuf.Write(f.wbuf)
|
||||||
|
fr, err := f.debugFramer.ReadFrame()
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("http2: Framer %p: failed to decode just-written frame", f)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
log.Printf("http2: Framer %p: wrote %v", f, summarizeFrame(fr))
|
||||||
|
}
|
||||||
|
|
||||||
func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
|
func (f *Framer) writeByte(v byte) { f.wbuf = append(f.wbuf, v) }
|
||||||
func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
|
func (f *Framer) writeBytes(v []byte) { f.wbuf = append(f.wbuf, v...) }
|
||||||
func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
|
func (f *Framer) writeUint16(v uint16) { f.wbuf = append(f.wbuf, byte(v>>8), byte(v)) }
|
||||||
|
@ -333,8 +398,9 @@ const (
|
||||||
// NewFramer returns a Framer that writes frames to w and reads them from r.
|
// NewFramer returns a Framer that writes frames to w and reads them from r.
|
||||||
func NewFramer(w io.Writer, r io.Reader) *Framer {
|
func NewFramer(w io.Writer, r io.Reader) *Framer {
|
||||||
fr := &Framer{
|
fr := &Framer{
|
||||||
w: w,
|
w: w,
|
||||||
r: r,
|
r: r,
|
||||||
|
logReads: logFrameReads,
|
||||||
}
|
}
|
||||||
fr.getReadBuf = func(size uint32) []byte {
|
fr.getReadBuf = func(size uint32) []byte {
|
||||||
if cap(fr.readBuf) >= int(size) {
|
if cap(fr.readBuf) >= int(size) {
|
||||||
|
@ -358,15 +424,39 @@ func (fr *Framer) SetMaxReadFrameSize(v uint32) {
|
||||||
fr.maxReadSize = v
|
fr.maxReadSize = v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrorDetail returns a more detailed error of the last error
|
||||||
|
// returned by Framer.ReadFrame. For instance, if ReadFrame
|
||||||
|
// returns a StreamError with code PROTOCOL_ERROR, ErrorDetail
|
||||||
|
// will say exactly what was invalid. ErrorDetail is not guaranteed
|
||||||
|
// to return a non-nil value and like the rest of the http2 package,
|
||||||
|
// its return value is not protected by an API compatibility promise.
|
||||||
|
// ErrorDetail is reset after the next call to ReadFrame.
|
||||||
|
func (fr *Framer) ErrorDetail() error {
|
||||||
|
return fr.errDetail
|
||||||
|
}
|
||||||
|
|
||||||
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
|
// ErrFrameTooLarge is returned from Framer.ReadFrame when the peer
|
||||||
// sends a frame that is larger than declared with SetMaxReadFrameSize.
|
// sends a frame that is larger than declared with SetMaxReadFrameSize.
|
||||||
var ErrFrameTooLarge = errors.New("http2: frame too large")
|
var ErrFrameTooLarge = errors.New("http2: frame too large")
|
||||||
|
|
||||||
|
// terminalReadFrameError reports whether err is an unrecoverable
|
||||||
|
// error from ReadFrame and no other frames should be read.
|
||||||
|
func terminalReadFrameError(err error) bool {
|
||||||
|
if _, ok := err.(StreamError); ok {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return err != nil
|
||||||
|
}
|
||||||
|
|
||||||
// ReadFrame reads a single frame. The returned Frame is only valid
|
// ReadFrame reads a single frame. The returned Frame is only valid
|
||||||
// until the next call to ReadFrame.
|
// until the next call to ReadFrame.
|
||||||
// If the frame is larger than previously set with SetMaxReadFrameSize,
|
//
|
||||||
// the returned error is ErrFrameTooLarge.
|
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||||
|
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||||
|
// ConnectionError, StreamError, or anything else from from the underlying
|
||||||
|
// reader.
|
||||||
func (fr *Framer) ReadFrame() (Frame, error) {
|
func (fr *Framer) ReadFrame() (Frame, error) {
|
||||||
|
fr.errDetail = nil
|
||||||
if fr.lastFrame != nil {
|
if fr.lastFrame != nil {
|
||||||
fr.lastFrame.invalidate()
|
fr.lastFrame.invalidate()
|
||||||
}
|
}
|
||||||
|
@ -383,12 +473,71 @@ func (fr *Framer) ReadFrame() (Frame, error) {
|
||||||
}
|
}
|
||||||
f, err := typeFrameParser(fh.Type)(fh, payload)
|
f, err := typeFrameParser(fh.Type)(fh, payload)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
if ce, ok := err.(connError); ok {
|
||||||
|
return nil, fr.connError(ce.Code, ce.Reason)
|
||||||
|
}
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
fr.lastFrame = f
|
if err := fr.checkFrameOrder(f); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if fr.logReads {
|
||||||
|
log.Printf("http2: Framer %p: read %v", fr, summarizeFrame(f))
|
||||||
|
}
|
||||||
|
if fh.Type == FrameHeaders && fr.ReadMetaHeaders != nil {
|
||||||
|
return fr.readMetaFrame(f.(*HeadersFrame))
|
||||||
|
}
|
||||||
return f, nil
|
return f, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// connError returns ConnectionError(code) but first
|
||||||
|
// stashes away a public reason to the caller can optionally relay it
|
||||||
|
// to the peer before hanging up on them. This might help others debug
|
||||||
|
// their implementations.
|
||||||
|
func (fr *Framer) connError(code ErrCode, reason string) error {
|
||||||
|
fr.errDetail = errors.New(reason)
|
||||||
|
return ConnectionError(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// checkFrameOrder reports an error if f is an invalid frame to return
|
||||||
|
// next from ReadFrame. Mostly it checks whether HEADERS and
|
||||||
|
// CONTINUATION frames are contiguous.
|
||||||
|
func (fr *Framer) checkFrameOrder(f Frame) error {
|
||||||
|
last := fr.lastFrame
|
||||||
|
fr.lastFrame = f
|
||||||
|
if fr.AllowIllegalReads {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
fh := f.Header()
|
||||||
|
if fr.lastHeaderStream != 0 {
|
||||||
|
if fh.Type != FrameContinuation {
|
||||||
|
return fr.connError(ErrCodeProtocol,
|
||||||
|
fmt.Sprintf("got %s for stream %d; expected CONTINUATION following %s for stream %d",
|
||||||
|
fh.Type, fh.StreamID,
|
||||||
|
last.Header().Type, fr.lastHeaderStream))
|
||||||
|
}
|
||||||
|
if fh.StreamID != fr.lastHeaderStream {
|
||||||
|
return fr.connError(ErrCodeProtocol,
|
||||||
|
fmt.Sprintf("got CONTINUATION for stream %d; expected stream %d",
|
||||||
|
fh.StreamID, fr.lastHeaderStream))
|
||||||
|
}
|
||||||
|
} else if fh.Type == FrameContinuation {
|
||||||
|
return fr.connError(ErrCodeProtocol, fmt.Sprintf("unexpected CONTINUATION for stream %d", fh.StreamID))
|
||||||
|
}
|
||||||
|
|
||||||
|
switch fh.Type {
|
||||||
|
case FrameHeaders, FrameContinuation:
|
||||||
|
if fh.Flags.Has(FlagHeadersEndHeaders) {
|
||||||
|
fr.lastHeaderStream = 0
|
||||||
|
} else {
|
||||||
|
fr.lastHeaderStream = fh.StreamID
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// A DataFrame conveys arbitrary, variable-length sequences of octets
|
// A DataFrame conveys arbitrary, variable-length sequences of octets
|
||||||
// associated with a stream.
|
// associated with a stream.
|
||||||
// See http://http2.github.io/http2-spec/#rfc.section.6.1
|
// See http://http2.github.io/http2-spec/#rfc.section.6.1
|
||||||
|
@ -417,7 +566,7 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||||
// field is 0x0, the recipient MUST respond with a
|
// field is 0x0, the recipient MUST respond with a
|
||||||
// connection error (Section 5.4.1) of type
|
// connection error (Section 5.4.1) of type
|
||||||
// PROTOCOL_ERROR.
|
// PROTOCOL_ERROR.
|
||||||
return nil, ConnectionError(ErrCodeProtocol)
|
return nil, connError{ErrCodeProtocol, "DATA frame with stream ID 0"}
|
||||||
}
|
}
|
||||||
f := &DataFrame{
|
f := &DataFrame{
|
||||||
FrameHeader: fh,
|
FrameHeader: fh,
|
||||||
|
@ -435,7 +584,7 @@ func parseDataFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||||
// length of the frame payload, the recipient MUST
|
// length of the frame payload, the recipient MUST
|
||||||
// treat this as a connection error.
|
// treat this as a connection error.
|
||||||
// Filed: https://github.com/http2/http2-spec/issues/610
|
// Filed: https://github.com/http2/http2-spec/issues/610
|
||||||
return nil, ConnectionError(ErrCodeProtocol)
|
return nil, connError{ErrCodeProtocol, "pad size larger than data payload"}
|
||||||
}
|
}
|
||||||
f.data = payload[:len(payload)-int(padSize)]
|
f.data = payload[:len(payload)-int(padSize)]
|
||||||
return f, nil
|
return f, nil
|
||||||
|
@ -575,6 +724,8 @@ type PingFrame struct {
|
||||||
Data [8]byte
|
Data [8]byte
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (f *PingFrame) IsAck() bool { return f.Flags.Has(FlagPingAck) }
|
||||||
|
|
||||||
func parsePingFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
func parsePingFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||||
if len(payload) != 8 {
|
if len(payload) != 8 {
|
||||||
return nil, ConnectionError(ErrCodeFrameSize)
|
return nil, ConnectionError(ErrCodeFrameSize)
|
||||||
|
@ -663,7 +814,7 @@ func parseUnknownFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||||
// See http://http2.github.io/http2-spec/#rfc.section.6.9
|
// See http://http2.github.io/http2-spec/#rfc.section.6.9
|
||||||
type WindowUpdateFrame struct {
|
type WindowUpdateFrame struct {
|
||||||
FrameHeader
|
FrameHeader
|
||||||
Increment uint32
|
Increment uint32 // never read with high bit set
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseWindowUpdateFrame(fh FrameHeader, p []byte) (Frame, error) {
|
func parseWindowUpdateFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||||
|
@ -740,7 +891,7 @@ func parseHeadersFrame(fh FrameHeader, p []byte) (_ Frame, err error) {
|
||||||
// is received whose stream identifier field is 0x0, the recipient MUST
|
// is received whose stream identifier field is 0x0, the recipient MUST
|
||||||
// respond with a connection error (Section 5.4.1) of type
|
// respond with a connection error (Section 5.4.1) of type
|
||||||
// PROTOCOL_ERROR.
|
// PROTOCOL_ERROR.
|
||||||
return nil, ConnectionError(ErrCodeProtocol)
|
return nil, connError{ErrCodeProtocol, "HEADERS frame with stream ID 0"}
|
||||||
}
|
}
|
||||||
var padLength uint8
|
var padLength uint8
|
||||||
if fh.Flags.Has(FlagHeadersPadded) {
|
if fh.Flags.Has(FlagHeadersPadded) {
|
||||||
|
@ -870,10 +1021,10 @@ func (p PriorityParam) IsZero() bool {
|
||||||
|
|
||||||
func parsePriorityFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
func parsePriorityFrame(fh FrameHeader, payload []byte) (Frame, error) {
|
||||||
if fh.StreamID == 0 {
|
if fh.StreamID == 0 {
|
||||||
return nil, ConnectionError(ErrCodeProtocol)
|
return nil, connError{ErrCodeProtocol, "PRIORITY frame with stream ID 0"}
|
||||||
}
|
}
|
||||||
if len(payload) != 5 {
|
if len(payload) != 5 {
|
||||||
return nil, ConnectionError(ErrCodeFrameSize)
|
return nil, connError{ErrCodeFrameSize, fmt.Sprintf("PRIORITY frame payload size was %d; want 5", len(payload))}
|
||||||
}
|
}
|
||||||
v := binary.BigEndian.Uint32(payload[:4])
|
v := binary.BigEndian.Uint32(payload[:4])
|
||||||
streamID := v & 0x7fffffff // mask off high bit
|
streamID := v & 0x7fffffff // mask off high bit
|
||||||
|
@ -943,13 +1094,12 @@ type ContinuationFrame struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseContinuationFrame(fh FrameHeader, p []byte) (Frame, error) {
|
func parseContinuationFrame(fh FrameHeader, p []byte) (Frame, error) {
|
||||||
|
if fh.StreamID == 0 {
|
||||||
|
return nil, connError{ErrCodeProtocol, "CONTINUATION frame with stream ID 0"}
|
||||||
|
}
|
||||||
return &ContinuationFrame{fh, p}, nil
|
return &ContinuationFrame{fh, p}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (f *ContinuationFrame) StreamEnded() bool {
|
|
||||||
return f.FrameHeader.Flags.Has(FlagDataEndStream)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f *ContinuationFrame) HeaderBlockFragment() []byte {
|
func (f *ContinuationFrame) HeaderBlockFragment() []byte {
|
||||||
f.checkValid()
|
f.checkValid()
|
||||||
return f.headerFragBuf
|
return f.headerFragBuf
|
||||||
|
@ -1111,3 +1261,236 @@ type streamEnder interface {
|
||||||
type headersEnder interface {
|
type headersEnder interface {
|
||||||
HeadersEnded() bool
|
HeadersEnded() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type headersOrContinuation interface {
|
||||||
|
headersEnder
|
||||||
|
HeaderBlockFragment() []byte
|
||||||
|
}
|
||||||
|
|
||||||
|
// A MetaHeadersFrame is the representation of one HEADERS frame and
|
||||||
|
// zero or more contiguous CONTINUATION frames and the decoding of
|
||||||
|
// their HPACK-encoded contents.
|
||||||
|
//
|
||||||
|
// This type of frame does not appear on the wire and is only returned
|
||||||
|
// by the Framer when Framer.ReadMetaHeaders is set.
|
||||||
|
type MetaHeadersFrame struct {
|
||||||
|
*HeadersFrame
|
||||||
|
|
||||||
|
// Fields are the fields contained in the HEADERS and
|
||||||
|
// CONTINUATION frames. The underlying slice is owned by the
|
||||||
|
// Framer and must not be retained after the next call to
|
||||||
|
// ReadFrame.
|
||||||
|
//
|
||||||
|
// Fields are guaranteed to be in the correct http2 order and
|
||||||
|
// not have unknown pseudo header fields or invalid header
|
||||||
|
// field names or values. Required pseudo header fields may be
|
||||||
|
// missing, however. Use the MetaHeadersFrame.Pseudo accessor
|
||||||
|
// method access pseudo headers.
|
||||||
|
Fields []hpack.HeaderField
|
||||||
|
|
||||||
|
// Truncated is whether the max header list size limit was hit
|
||||||
|
// and Fields is incomplete. The hpack decoder state is still
|
||||||
|
// valid, however.
|
||||||
|
Truncated bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoValue returns the given pseudo header field's value.
|
||||||
|
// The provided pseudo field should not contain the leading colon.
|
||||||
|
func (mh *MetaHeadersFrame) PseudoValue(pseudo string) string {
|
||||||
|
for _, hf := range mh.Fields {
|
||||||
|
if !hf.IsPseudo() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
if hf.Name[1:] == pseudo {
|
||||||
|
return hf.Value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegularFields returns the regular (non-pseudo) header fields of mh.
|
||||||
|
// The caller does not own the returned slice.
|
||||||
|
func (mh *MetaHeadersFrame) RegularFields() []hpack.HeaderField {
|
||||||
|
for i, hf := range mh.Fields {
|
||||||
|
if !hf.IsPseudo() {
|
||||||
|
return mh.Fields[i:]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// PseudoFields returns the pseudo header fields of mh.
|
||||||
|
// The caller does not own the returned slice.
|
||||||
|
func (mh *MetaHeadersFrame) PseudoFields() []hpack.HeaderField {
|
||||||
|
for i, hf := range mh.Fields {
|
||||||
|
if !hf.IsPseudo() {
|
||||||
|
return mh.Fields[:i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return mh.Fields
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mh *MetaHeadersFrame) checkPseudos() error {
|
||||||
|
var isRequest, isResponse bool
|
||||||
|
pf := mh.PseudoFields()
|
||||||
|
for i, hf := range pf {
|
||||||
|
switch hf.Name {
|
||||||
|
case ":method", ":path", ":scheme", ":authority":
|
||||||
|
isRequest = true
|
||||||
|
case ":status":
|
||||||
|
isResponse = true
|
||||||
|
default:
|
||||||
|
return pseudoHeaderError(hf.Name)
|
||||||
|
}
|
||||||
|
// Check for duplicates.
|
||||||
|
// This would be a bad algorithm, but N is 4.
|
||||||
|
// And this doesn't allocate.
|
||||||
|
for _, hf2 := range pf[:i] {
|
||||||
|
if hf.Name == hf2.Name {
|
||||||
|
return duplicatePseudoHeaderError(hf.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if isRequest && isResponse {
|
||||||
|
return errMixPseudoHeaderTypes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *Framer) maxHeaderStringLen() int {
|
||||||
|
v := fr.maxHeaderListSize()
|
||||||
|
if uint32(int(v)) == v {
|
||||||
|
return int(v)
|
||||||
|
}
|
||||||
|
// They had a crazy big number for MaxHeaderBytes anyway,
|
||||||
|
// so give them unlimited header lengths:
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// readMetaFrame returns 0 or more CONTINUATION frames from fr and
|
||||||
|
// merge them into into the provided hf and returns a MetaHeadersFrame
|
||||||
|
// with the decoded hpack values.
|
||||||
|
func (fr *Framer) readMetaFrame(hf *HeadersFrame) (*MetaHeadersFrame, error) {
|
||||||
|
if fr.AllowIllegalReads {
|
||||||
|
return nil, errors.New("illegal use of AllowIllegalReads with ReadMetaHeaders")
|
||||||
|
}
|
||||||
|
mh := &MetaHeadersFrame{
|
||||||
|
HeadersFrame: hf,
|
||||||
|
}
|
||||||
|
var remainSize = fr.maxHeaderListSize()
|
||||||
|
var sawRegular bool
|
||||||
|
|
||||||
|
var invalid error // pseudo header field errors
|
||||||
|
hdec := fr.ReadMetaHeaders
|
||||||
|
hdec.SetEmitEnabled(true)
|
||||||
|
hdec.SetMaxStringLength(fr.maxHeaderStringLen())
|
||||||
|
hdec.SetEmitFunc(func(hf hpack.HeaderField) {
|
||||||
|
if !validHeaderFieldValue(hf.Value) {
|
||||||
|
invalid = headerFieldValueError(hf.Value)
|
||||||
|
}
|
||||||
|
isPseudo := strings.HasPrefix(hf.Name, ":")
|
||||||
|
if isPseudo {
|
||||||
|
if sawRegular {
|
||||||
|
invalid = errPseudoAfterRegular
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
sawRegular = true
|
||||||
|
if !validHeaderFieldName(hf.Name) {
|
||||||
|
invalid = headerFieldNameError(hf.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if invalid != nil {
|
||||||
|
hdec.SetEmitEnabled(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
size := hf.Size()
|
||||||
|
if size > remainSize {
|
||||||
|
hdec.SetEmitEnabled(false)
|
||||||
|
mh.Truncated = true
|
||||||
|
return
|
||||||
|
}
|
||||||
|
remainSize -= size
|
||||||
|
|
||||||
|
mh.Fields = append(mh.Fields, hf)
|
||||||
|
})
|
||||||
|
// Lose reference to MetaHeadersFrame:
|
||||||
|
defer hdec.SetEmitFunc(func(hf hpack.HeaderField) {})
|
||||||
|
|
||||||
|
var hc headersOrContinuation = hf
|
||||||
|
for {
|
||||||
|
frag := hc.HeaderBlockFragment()
|
||||||
|
if _, err := hdec.Write(frag); err != nil {
|
||||||
|
return nil, ConnectionError(ErrCodeCompression)
|
||||||
|
}
|
||||||
|
|
||||||
|
if hc.HeadersEnded() {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if f, err := fr.ReadFrame(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
} else {
|
||||||
|
hc = f.(*ContinuationFrame) // guaranteed by checkFrameOrder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mh.HeadersFrame.headerFragBuf = nil
|
||||||
|
mh.HeadersFrame.invalidate()
|
||||||
|
|
||||||
|
if err := hdec.Close(); err != nil {
|
||||||
|
return nil, ConnectionError(ErrCodeCompression)
|
||||||
|
}
|
||||||
|
if invalid != nil {
|
||||||
|
fr.errDetail = invalid
|
||||||
|
return nil, StreamError{mh.StreamID, ErrCodeProtocol}
|
||||||
|
}
|
||||||
|
if err := mh.checkPseudos(); err != nil {
|
||||||
|
fr.errDetail = err
|
||||||
|
return nil, StreamError{mh.StreamID, ErrCodeProtocol}
|
||||||
|
}
|
||||||
|
return mh, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func summarizeFrame(f Frame) string {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
f.Header().writeDebug(&buf)
|
||||||
|
switch f := f.(type) {
|
||||||
|
case *SettingsFrame:
|
||||||
|
n := 0
|
||||||
|
f.ForeachSetting(func(s Setting) error {
|
||||||
|
n++
|
||||||
|
if n == 1 {
|
||||||
|
buf.WriteString(", settings:")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, " %v=%v,", s.ID, s.Val)
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
if n > 0 {
|
||||||
|
buf.Truncate(buf.Len() - 1) // remove trailing comma
|
||||||
|
}
|
||||||
|
case *DataFrame:
|
||||||
|
data := f.Data()
|
||||||
|
const max = 256
|
||||||
|
if len(data) > max {
|
||||||
|
data = data[:max]
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, " data=%q", data)
|
||||||
|
if len(f.Data()) > max {
|
||||||
|
fmt.Fprintf(&buf, " (%d bytes omitted)", len(f.Data())-max)
|
||||||
|
}
|
||||||
|
case *WindowUpdateFrame:
|
||||||
|
if f.StreamID == 0 {
|
||||||
|
buf.WriteString(" (conn)")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(&buf, " incr=%v", f.Increment)
|
||||||
|
case *PingFrame:
|
||||||
|
fmt.Fprintf(&buf, " ping=%q", f.Data[:])
|
||||||
|
case *GoAwayFrame:
|
||||||
|
fmt.Fprintf(&buf, " LastStreamID=%v ErrCode=%v Debug=%q",
|
||||||
|
f.LastStreamID, f.ErrCode, f.debugData)
|
||||||
|
case *RSTStreamFrame:
|
||||||
|
fmt.Fprintf(&buf, " ErrCode=%v", f.ErrCode)
|
||||||
|
}
|
||||||
|
return buf.String()
|
||||||
|
}
|
11
vendor/golang.org/x/net/http2/go15.go
generated
vendored
Normal file
11
vendor/golang.org/x/net/http2/go15.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build go1.5
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func requestCancel(req *http.Request) <-chan struct{} { return req.Cancel }
|
|
@ -1,9 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
// Defensive debug-only utility to track that functions run on the
|
// Defensive debug-only utility to track that functions run on the
|
||||||
// goroutine that they're supposed to.
|
// goroutine that they're supposed to.
|
|
@ -1,9 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
package http2
|
||||||
|
|
||||||
|
@ -60,6 +57,7 @@ func init() {
|
||||||
"server",
|
"server",
|
||||||
"set-cookie",
|
"set-cookie",
|
||||||
"strict-transport-security",
|
"strict-transport-security",
|
||||||
|
"trailer",
|
||||||
"transfer-encoding",
|
"transfer-encoding",
|
||||||
"user-agent",
|
"user-agent",
|
||||||
"vary",
|
"vary",
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package hpack
|
package hpack
|
||||||
|
|
||||||
|
@ -145,7 +144,7 @@ func (e *Encoder) SetMaxDynamicTableSizeLimit(v uint32) {
|
||||||
|
|
||||||
// shouldIndex reports whether f should be indexed.
|
// shouldIndex reports whether f should be indexed.
|
||||||
func (e *Encoder) shouldIndex(f HeaderField) bool {
|
func (e *Encoder) shouldIndex(f HeaderField) bool {
|
||||||
return !f.Sensitive && f.size() <= e.dynTab.maxSize
|
return !f.Sensitive && f.Size() <= e.dynTab.maxSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// appendIndexed appends index i, as encoded in "Indexed Header Field"
|
// appendIndexed appends index i, as encoded in "Indexed Header Field"
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
// Package hpack implements HPACK, a compression format for
|
// Package hpack implements HPACK, a compression format for
|
||||||
// efficiently representing HTTP header fields in the context of HTTP/2.
|
// efficiently representing HTTP header fields in the context of HTTP/2.
|
||||||
|
@ -42,7 +41,24 @@ type HeaderField struct {
|
||||||
Sensitive bool
|
Sensitive bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (hf *HeaderField) size() uint32 {
|
// IsPseudo reports whether the header field is an http2 pseudo header.
|
||||||
|
// That is, it reports whether it starts with a colon.
|
||||||
|
// It is not otherwise guaranteed to be a valid psuedo header field,
|
||||||
|
// though.
|
||||||
|
func (hf HeaderField) IsPseudo() bool {
|
||||||
|
return len(hf.Name) != 0 && hf.Name[0] == ':'
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hf HeaderField) String() string {
|
||||||
|
var suffix string
|
||||||
|
if hf.Sensitive {
|
||||||
|
suffix = " (sensitive)"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("header field %q = %q%s", hf.Name, hf.Value, suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Size returns the size of an entry per RFC 7540 section 5.2.
|
||||||
|
func (hf HeaderField) Size() uint32 {
|
||||||
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
|
// http://http2.github.io/http2-spec/compression.html#rfc.section.4.1
|
||||||
// "The size of the dynamic table is the sum of the size of
|
// "The size of the dynamic table is the sum of the size of
|
||||||
// its entries. The size of an entry is the sum of its name's
|
// its entries. The size of an entry is the sum of its name's
|
||||||
|
@ -64,23 +80,65 @@ type Decoder struct {
|
||||||
dynTab dynamicTable
|
dynTab dynamicTable
|
||||||
emit func(f HeaderField)
|
emit func(f HeaderField)
|
||||||
|
|
||||||
|
emitEnabled bool // whether calls to emit are enabled
|
||||||
|
maxStrLen int // 0 means unlimited
|
||||||
|
|
||||||
// buf is the unparsed buffer. It's only written to
|
// buf is the unparsed buffer. It's only written to
|
||||||
// saveBuf if it was truncated in the middle of a header
|
// saveBuf if it was truncated in the middle of a header
|
||||||
// block. Because it's usually not owned, we can only
|
// block. Because it's usually not owned, we can only
|
||||||
// process it under Write.
|
// process it under Write.
|
||||||
buf []byte // usually not owned
|
buf []byte // not owned; only valid during Write
|
||||||
|
|
||||||
|
// saveBuf is previous data passed to Write which we weren't able
|
||||||
|
// to fully parse before. Unlike buf, we own this data.
|
||||||
saveBuf bytes.Buffer
|
saveBuf bytes.Buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDecoder(maxSize uint32, emitFunc func(f HeaderField)) *Decoder {
|
// NewDecoder returns a new decoder with the provided maximum dynamic
|
||||||
|
// table size. The emitFunc will be called for each valid field
|
||||||
|
// parsed, in the same goroutine as calls to Write, before Write returns.
|
||||||
|
func NewDecoder(maxDynamicTableSize uint32, emitFunc func(f HeaderField)) *Decoder {
|
||||||
d := &Decoder{
|
d := &Decoder{
|
||||||
emit: emitFunc,
|
emit: emitFunc,
|
||||||
|
emitEnabled: true,
|
||||||
}
|
}
|
||||||
d.dynTab.allowedMaxSize = maxSize
|
d.dynTab.allowedMaxSize = maxDynamicTableSize
|
||||||
d.dynTab.setMaxSize(maxSize)
|
d.dynTab.setMaxSize(maxDynamicTableSize)
|
||||||
return d
|
return d
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ErrStringLength is returned by Decoder.Write when the max string length
|
||||||
|
// (as configured by Decoder.SetMaxStringLength) would be violated.
|
||||||
|
var ErrStringLength = errors.New("hpack: string too long")
|
||||||
|
|
||||||
|
// SetMaxStringLength sets the maximum size of a HeaderField name or
|
||||||
|
// value string. If a string exceeds this length (even after any
|
||||||
|
// decompression), Write will return ErrStringLength.
|
||||||
|
// A value of 0 means unlimited and is the default from NewDecoder.
|
||||||
|
func (d *Decoder) SetMaxStringLength(n int) {
|
||||||
|
d.maxStrLen = n
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmitFunc changes the callback used when new header fields
|
||||||
|
// are decoded.
|
||||||
|
// It must be non-nil. It does not affect EmitEnabled.
|
||||||
|
func (d *Decoder) SetEmitFunc(emitFunc func(f HeaderField)) {
|
||||||
|
d.emit = emitFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetEmitEnabled controls whether the emitFunc provided to NewDecoder
|
||||||
|
// should be called. The default is true.
|
||||||
|
//
|
||||||
|
// This facility exists to let servers enforce MAX_HEADER_LIST_SIZE
|
||||||
|
// while still decoding and keeping in-sync with decoder state, but
|
||||||
|
// without doing unnecessary decompression or generating unnecessary
|
||||||
|
// garbage for header fields past the limit.
|
||||||
|
func (d *Decoder) SetEmitEnabled(v bool) { d.emitEnabled = v }
|
||||||
|
|
||||||
|
// EmitEnabled reports whether calls to the emitFunc provided to NewDecoder
|
||||||
|
// are currently enabled. The default is true.
|
||||||
|
func (d *Decoder) EmitEnabled() bool { return d.emitEnabled }
|
||||||
|
|
||||||
// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
|
// TODO: add method *Decoder.Reset(maxSize, emitFunc) to let callers re-use Decoders and their
|
||||||
// underlying buffers for garbage reasons.
|
// underlying buffers for garbage reasons.
|
||||||
|
|
||||||
|
@ -122,7 +180,7 @@ func (dt *dynamicTable) setMaxSize(v uint32) {
|
||||||
|
|
||||||
func (dt *dynamicTable) add(f HeaderField) {
|
func (dt *dynamicTable) add(f HeaderField) {
|
||||||
dt.ents = append(dt.ents, f)
|
dt.ents = append(dt.ents, f)
|
||||||
dt.size += f.size()
|
dt.size += f.Size()
|
||||||
dt.evict()
|
dt.evict()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +188,7 @@ func (dt *dynamicTable) add(f HeaderField) {
|
||||||
func (dt *dynamicTable) evict() {
|
func (dt *dynamicTable) evict() {
|
||||||
base := dt.ents // keep base pointer of slice
|
base := dt.ents // keep base pointer of slice
|
||||||
for dt.size > dt.maxSize {
|
for dt.size > dt.maxSize {
|
||||||
dt.size -= dt.ents[0].size()
|
dt.size -= dt.ents[0].Size()
|
||||||
dt.ents = dt.ents[1:]
|
dt.ents = dt.ents[1:]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -247,15 +305,23 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
|
||||||
|
|
||||||
for len(d.buf) > 0 {
|
for len(d.buf) > 0 {
|
||||||
err = d.parseHeaderFieldRepr()
|
err = d.parseHeaderFieldRepr()
|
||||||
if err != nil {
|
if err == errNeedMore {
|
||||||
if err == errNeedMore {
|
// Extra paranoia, making sure saveBuf won't
|
||||||
err = nil
|
// get too large. All the varint and string
|
||||||
d.saveBuf.Write(d.buf)
|
// reading code earlier should already catch
|
||||||
|
// overlong things and return ErrStringLength,
|
||||||
|
// but keep this as a last resort.
|
||||||
|
const varIntOverhead = 8 // conservative
|
||||||
|
if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
|
||||||
|
return 0, ErrStringLength
|
||||||
}
|
}
|
||||||
|
d.saveBuf.Write(d.buf)
|
||||||
|
return len(p), nil
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return len(p), err
|
return len(p), err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -323,9 +389,8 @@ func (d *Decoder) parseFieldIndexed() error {
|
||||||
if !ok {
|
if !ok {
|
||||||
return DecodingError{InvalidIndexError(idx)}
|
return DecodingError{InvalidIndexError(idx)}
|
||||||
}
|
}
|
||||||
d.emit(HeaderField{Name: hf.Name, Value: hf.Value})
|
|
||||||
d.buf = buf
|
d.buf = buf
|
||||||
return nil
|
return d.callEmit(HeaderField{Name: hf.Name, Value: hf.Value})
|
||||||
}
|
}
|
||||||
|
|
||||||
// (same invariants and behavior as parseHeaderFieldRepr)
|
// (same invariants and behavior as parseHeaderFieldRepr)
|
||||||
|
@ -337,6 +402,7 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
var hf HeaderField
|
var hf HeaderField
|
||||||
|
wantStr := d.emitEnabled || it.indexed()
|
||||||
if nameIdx > 0 {
|
if nameIdx > 0 {
|
||||||
ihf, ok := d.at(nameIdx)
|
ihf, ok := d.at(nameIdx)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
@ -344,12 +410,12 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||||
}
|
}
|
||||||
hf.Name = ihf.Name
|
hf.Name = ihf.Name
|
||||||
} else {
|
} else {
|
||||||
hf.Name, buf, err = readString(buf)
|
hf.Name, buf, err = d.readString(buf, wantStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
hf.Value, buf, err = readString(buf)
|
hf.Value, buf, err = d.readString(buf, wantStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -358,7 +424,18 @@ func (d *Decoder) parseFieldLiteral(n uint8, it indexType) error {
|
||||||
d.dynTab.add(hf)
|
d.dynTab.add(hf)
|
||||||
}
|
}
|
||||||
hf.Sensitive = it.sensitive()
|
hf.Sensitive = it.sensitive()
|
||||||
d.emit(hf)
|
return d.callEmit(hf)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (d *Decoder) callEmit(hf HeaderField) error {
|
||||||
|
if d.maxStrLen != 0 {
|
||||||
|
if len(hf.Name) > d.maxStrLen || len(hf.Value) > d.maxStrLen {
|
||||||
|
return ErrStringLength
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if d.emitEnabled {
|
||||||
|
d.emit(hf)
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +497,15 @@ func readVarInt(n byte, p []byte) (i uint64, remain []byte, err error) {
|
||||||
return 0, origP, errNeedMore
|
return 0, origP, errNeedMore
|
||||||
}
|
}
|
||||||
|
|
||||||
func readString(p []byte) (s string, remain []byte, err error) {
|
// readString decodes an hpack string from p.
|
||||||
|
//
|
||||||
|
// wantStr is whether s will be used. If false, decompression and
|
||||||
|
// []byte->string garbage are skipped if s will be ignored
|
||||||
|
// anyway. This does mean that huffman decoding errors for non-indexed
|
||||||
|
// strings past the MAX_HEADER_LIST_SIZE are ignored, but the server
|
||||||
|
// is returning an error anyway, and because they're not indexed, the error
|
||||||
|
// won't affect the decoding state.
|
||||||
|
func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, err error) {
|
||||||
if len(p) == 0 {
|
if len(p) == 0 {
|
||||||
return "", p, errNeedMore
|
return "", p, errNeedMore
|
||||||
}
|
}
|
||||||
|
@ -429,17 +514,29 @@ func readString(p []byte) (s string, remain []byte, err error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", p, err
|
return "", p, err
|
||||||
}
|
}
|
||||||
|
if d.maxStrLen != 0 && strLen > uint64(d.maxStrLen) {
|
||||||
|
return "", nil, ErrStringLength
|
||||||
|
}
|
||||||
if uint64(len(p)) < strLen {
|
if uint64(len(p)) < strLen {
|
||||||
return "", p, errNeedMore
|
return "", p, errNeedMore
|
||||||
}
|
}
|
||||||
if !isHuff {
|
if !isHuff {
|
||||||
return string(p[:strLen]), p[strLen:], nil
|
if wantStr {
|
||||||
|
s = string(p[:strLen])
|
||||||
|
}
|
||||||
|
return s, p[strLen:], nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: optimize this garbage:
|
if wantStr {
|
||||||
var buf bytes.Buffer
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
if _, err := HuffmanDecode(&buf, p[:strLen]); err != nil {
|
buf.Reset() // don't trust others
|
||||||
return "", nil, err
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||||
|
buf.Reset()
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
s = buf.String()
|
||||||
|
buf.Reset() // be nice to GC
|
||||||
}
|
}
|
||||||
return buf.String(), p[strLen:], nil
|
return s, p[strLen:], nil
|
||||||
}
|
}
|
|
@ -1,12 +1,12 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package hpack
|
package hpack
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"sync"
|
"sync"
|
||||||
)
|
)
|
||||||
|
@ -22,15 +22,46 @@ func HuffmanDecode(w io.Writer, v []byte) (int, error) {
|
||||||
buf := bufPool.Get().(*bytes.Buffer)
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
defer bufPool.Put(buf)
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, 0, v); err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
return w.Write(buf.Bytes())
|
||||||
|
}
|
||||||
|
|
||||||
|
// HuffmanDecodeToString decodes the string in v.
|
||||||
|
func HuffmanDecodeToString(v []byte) (string, error) {
|
||||||
|
buf := bufPool.Get().(*bytes.Buffer)
|
||||||
|
buf.Reset()
|
||||||
|
defer bufPool.Put(buf)
|
||||||
|
if err := huffmanDecode(buf, 0, v); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrInvalidHuffman is returned for errors found decoding
|
||||||
|
// Huffman-encoded strings.
|
||||||
|
var ErrInvalidHuffman = errors.New("hpack: invalid Huffman-encoded data")
|
||||||
|
|
||||||
|
// huffmanDecode decodes v to buf.
|
||||||
|
// If maxLen is greater than 0, attempts to write more to buf than
|
||||||
|
// maxLen bytes will return ErrStringLength.
|
||||||
|
func huffmanDecode(buf *bytes.Buffer, maxLen int, v []byte) error {
|
||||||
n := rootHuffmanNode
|
n := rootHuffmanNode
|
||||||
cur, nbits := uint(0), uint8(0)
|
cur, nbits := uint(0), uint8(0)
|
||||||
for _, b := range v {
|
for _, b := range v {
|
||||||
cur = cur<<8 | uint(b)
|
cur = cur<<8 | uint(b)
|
||||||
nbits += 8
|
nbits += 8
|
||||||
for nbits >= 8 {
|
for nbits >= 8 {
|
||||||
n = n.children[byte(cur>>(nbits-8))]
|
idx := byte(cur >> (nbits - 8))
|
||||||
|
n = n.children[idx]
|
||||||
|
if n == nil {
|
||||||
|
return ErrInvalidHuffman
|
||||||
|
}
|
||||||
if n.children == nil {
|
if n.children == nil {
|
||||||
|
if maxLen != 0 && buf.Len() == maxLen {
|
||||||
|
return ErrStringLength
|
||||||
|
}
|
||||||
buf.WriteByte(n.sym)
|
buf.WriteByte(n.sym)
|
||||||
nbits -= n.codeLen
|
nbits -= n.codeLen
|
||||||
n = rootHuffmanNode
|
n = rootHuffmanNode
|
||||||
|
@ -48,7 +79,7 @@ func HuffmanDecode(w io.Writer, v []byte) (int, error) {
|
||||||
nbits -= n.codeLen
|
nbits -= n.codeLen
|
||||||
n = rootHuffmanNode
|
n = rootHuffmanNode
|
||||||
}
|
}
|
||||||
return w.Write(buf.Bytes())
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type node struct {
|
type node struct {
|
||||||
|
@ -67,10 +98,10 @@ func newInternalNode() *node {
|
||||||
var rootHuffmanNode = newInternalNode()
|
var rootHuffmanNode = newInternalNode()
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
|
if len(huffmanCodes) != 256 {
|
||||||
|
panic("unexpected size")
|
||||||
|
}
|
||||||
for i, code := range huffmanCodes {
|
for i, code := range huffmanCodes {
|
||||||
if i > 255 {
|
|
||||||
panic("too many huffman codes")
|
|
||||||
}
|
|
||||||
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
addDecoderNode(byte(i), code, huffmanCodeLen[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
// Use of this source code is governed by a BSD-style
|
||||||
// Licensed under the same terms as Go itself:
|
// license that can be found in the LICENSE file.
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package hpack
|
package hpack
|
||||||
|
|
||||||
|
@ -10,7 +9,7 @@ func pair(name, value string) HeaderField {
|
||||||
}
|
}
|
||||||
|
|
||||||
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
|
// http://tools.ietf.org/html/draft-ietf-httpbis-header-compression-07#appendix-B
|
||||||
var staticTable = []HeaderField{
|
var staticTable = [...]HeaderField{
|
||||||
pair(":authority", ""), // index 1 (1-based)
|
pair(":authority", ""), // index 1 (1-based)
|
||||||
pair(":method", "GET"),
|
pair(":method", "GET"),
|
||||||
pair(":method", "POST"),
|
pair(":method", "POST"),
|
||||||
|
@ -74,7 +73,7 @@ var staticTable = []HeaderField{
|
||||||
pair("www-authenticate", ""),
|
pair("www-authenticate", ""),
|
||||||
}
|
}
|
||||||
|
|
||||||
var huffmanCodes = []uint32{
|
var huffmanCodes = [256]uint32{
|
||||||
0x1ff8,
|
0x1ff8,
|
||||||
0x7fffd8,
|
0x7fffd8,
|
||||||
0xfffffe2,
|
0xfffffe2,
|
||||||
|
@ -333,7 +332,7 @@ var huffmanCodes = []uint32{
|
||||||
0x3ffffee,
|
0x3ffffee,
|
||||||
}
|
}
|
||||||
|
|
||||||
var huffmanCodeLen = []uint8{
|
var huffmanCodeLen = [256]uint8{
|
||||||
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
|
13, 23, 28, 28, 28, 28, 28, 28, 28, 24, 30, 28, 28, 30, 28, 28,
|
||||||
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
28, 28, 28, 28, 28, 28, 30, 28, 28, 28, 28, 28, 28, 28, 28, 28,
|
||||||
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
|
6, 10, 10, 12, 13, 6, 8, 11, 10, 10, 8, 11, 8, 6, 6, 6,
|
463
vendor/golang.org/x/net/http2/http2.go
generated
vendored
Normal file
463
vendor/golang.org/x/net/http2/http2.go
generated
vendored
Normal file
|
@ -0,0 +1,463 @@
|
||||||
|
// Copyright 2014 The Go 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 http2 implements the HTTP/2 protocol.
|
||||||
|
//
|
||||||
|
// This package is low-level and intended to be used directly by very
|
||||||
|
// few people. Most users will use it indirectly through the automatic
|
||||||
|
// use by the net/http package (from Go 1.6 and later).
|
||||||
|
// For use in earlier Go versions see ConfigureServer. (Transport support
|
||||||
|
// requires Go 1.6 or later)
|
||||||
|
//
|
||||||
|
// See https://http2.github.io/ for more information on HTTP/2.
|
||||||
|
//
|
||||||
|
// See https://http2.golang.org/ for a test server running this code.
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"crypto/tls"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"sort"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
VerboseLogs bool
|
||||||
|
logFrameWrites bool
|
||||||
|
logFrameReads bool
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
e := os.Getenv("GODEBUG")
|
||||||
|
if strings.Contains(e, "http2debug=1") {
|
||||||
|
VerboseLogs = true
|
||||||
|
}
|
||||||
|
if strings.Contains(e, "http2debug=2") {
|
||||||
|
VerboseLogs = true
|
||||||
|
logFrameWrites = true
|
||||||
|
logFrameReads = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// ClientPreface is the string that must be sent by new
|
||||||
|
// connections from clients.
|
||||||
|
ClientPreface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
|
||||||
|
|
||||||
|
// SETTINGS_MAX_FRAME_SIZE default
|
||||||
|
// http://http2.github.io/http2-spec/#rfc.section.6.5.2
|
||||||
|
initialMaxFrameSize = 16384
|
||||||
|
|
||||||
|
// NextProtoTLS is the NPN/ALPN protocol negotiated during
|
||||||
|
// HTTP/2's TLS setup.
|
||||||
|
NextProtoTLS = "h2"
|
||||||
|
|
||||||
|
// http://http2.github.io/http2-spec/#SettingValues
|
||||||
|
initialHeaderTableSize = 4096
|
||||||
|
|
||||||
|
initialWindowSize = 65535 // 6.9.2 Initial Flow Control Window Size
|
||||||
|
|
||||||
|
defaultMaxReadFrameSize = 1 << 20
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
clientPreface = []byte(ClientPreface)
|
||||||
|
)
|
||||||
|
|
||||||
|
type streamState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
stateIdle streamState = iota
|
||||||
|
stateOpen
|
||||||
|
stateHalfClosedLocal
|
||||||
|
stateHalfClosedRemote
|
||||||
|
stateResvLocal
|
||||||
|
stateResvRemote
|
||||||
|
stateClosed
|
||||||
|
)
|
||||||
|
|
||||||
|
var stateName = [...]string{
|
||||||
|
stateIdle: "Idle",
|
||||||
|
stateOpen: "Open",
|
||||||
|
stateHalfClosedLocal: "HalfClosedLocal",
|
||||||
|
stateHalfClosedRemote: "HalfClosedRemote",
|
||||||
|
stateResvLocal: "ResvLocal",
|
||||||
|
stateResvRemote: "ResvRemote",
|
||||||
|
stateClosed: "Closed",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (st streamState) String() string {
|
||||||
|
return stateName[st]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setting is a setting parameter: which setting it is, and its value.
|
||||||
|
type Setting struct {
|
||||||
|
// ID is which setting is being set.
|
||||||
|
// See http://http2.github.io/http2-spec/#SettingValues
|
||||||
|
ID SettingID
|
||||||
|
|
||||||
|
// Val is the value.
|
||||||
|
Val uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Setting) String() string {
|
||||||
|
return fmt.Sprintf("[%v = %d]", s.ID, s.Val)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid reports whether the setting is valid.
|
||||||
|
func (s Setting) Valid() error {
|
||||||
|
// Limits and error codes from 6.5.2 Defined SETTINGS Parameters
|
||||||
|
switch s.ID {
|
||||||
|
case SettingEnablePush:
|
||||||
|
if s.Val != 1 && s.Val != 0 {
|
||||||
|
return ConnectionError(ErrCodeProtocol)
|
||||||
|
}
|
||||||
|
case SettingInitialWindowSize:
|
||||||
|
if s.Val > 1<<31-1 {
|
||||||
|
return ConnectionError(ErrCodeFlowControl)
|
||||||
|
}
|
||||||
|
case SettingMaxFrameSize:
|
||||||
|
if s.Val < 16384 || s.Val > 1<<24-1 {
|
||||||
|
return ConnectionError(ErrCodeProtocol)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// A SettingID is an HTTP/2 setting as defined in
|
||||||
|
// http://http2.github.io/http2-spec/#iana-settings
|
||||||
|
type SettingID uint16
|
||||||
|
|
||||||
|
const (
|
||||||
|
SettingHeaderTableSize SettingID = 0x1
|
||||||
|
SettingEnablePush SettingID = 0x2
|
||||||
|
SettingMaxConcurrentStreams SettingID = 0x3
|
||||||
|
SettingInitialWindowSize SettingID = 0x4
|
||||||
|
SettingMaxFrameSize SettingID = 0x5
|
||||||
|
SettingMaxHeaderListSize SettingID = 0x6
|
||||||
|
)
|
||||||
|
|
||||||
|
var settingName = map[SettingID]string{
|
||||||
|
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
|
||||||
|
SettingEnablePush: "ENABLE_PUSH",
|
||||||
|
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
|
||||||
|
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
|
||||||
|
SettingMaxFrameSize: "MAX_FRAME_SIZE",
|
||||||
|
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SettingID) String() string {
|
||||||
|
if v, ok := settingName[s]; ok {
|
||||||
|
return v
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("UNKNOWN_SETTING_%d", uint16(s))
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
errInvalidHeaderFieldName = errors.New("http2: invalid header field name")
|
||||||
|
errInvalidHeaderFieldValue = errors.New("http2: invalid header field value")
|
||||||
|
)
|
||||||
|
|
||||||
|
// validHeaderFieldName reports whether v is a valid header field name (key).
|
||||||
|
// RFC 7230 says:
|
||||||
|
// header-field = field-name ":" OWS field-value OWS
|
||||||
|
// field-name = token
|
||||||
|
// tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
|
||||||
|
// "^" / "_" / "
|
||||||
|
// Further, http2 says:
|
||||||
|
// "Just as in HTTP/1.x, header field names are strings of ASCII
|
||||||
|
// characters that are compared in a case-insensitive
|
||||||
|
// fashion. However, header field names MUST be converted to
|
||||||
|
// lowercase prior to their encoding in HTTP/2. "
|
||||||
|
func validHeaderFieldName(v string) bool {
|
||||||
|
if len(v) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
for _, r := range v {
|
||||||
|
if int(r) >= len(isTokenTable) || ('A' <= r && r <= 'Z') {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if !isTokenTable[byte(r)] {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// validHeaderFieldValue reports whether v is a valid header field value.
|
||||||
|
//
|
||||||
|
// RFC 7230 says:
|
||||||
|
// field-value = *( field-content / obs-fold )
|
||||||
|
// obj-fold = N/A to http2, and deprecated
|
||||||
|
// field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
|
||||||
|
// field-vchar = VCHAR / obs-text
|
||||||
|
// obs-text = %x80-FF
|
||||||
|
// VCHAR = "any visible [USASCII] character"
|
||||||
|
//
|
||||||
|
// http2 further says: "Similarly, HTTP/2 allows header field values
|
||||||
|
// that are not valid. While most of the values that can be encoded
|
||||||
|
// will not alter header field parsing, carriage return (CR, ASCII
|
||||||
|
// 0xd), line feed (LF, ASCII 0xa), and the zero character (NUL, ASCII
|
||||||
|
// 0x0) might be exploited by an attacker if they are translated
|
||||||
|
// verbatim. Any request or response that contains a character not
|
||||||
|
// permitted in a header field value MUST be treated as malformed
|
||||||
|
// (Section 8.1.2.6). Valid characters are defined by the
|
||||||
|
// field-content ABNF rule in Section 3.2 of [RFC7230]."
|
||||||
|
//
|
||||||
|
// This function does not (yet?) properly handle the rejection of
|
||||||
|
// strings that begin or end with SP or HTAB.
|
||||||
|
func validHeaderFieldValue(v string) bool {
|
||||||
|
for i := 0; i < len(v); i++ {
|
||||||
|
if b := v[i]; b < ' ' && b != '\t' || b == 0x7f {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
var httpCodeStringCommon = map[int]string{} // n -> strconv.Itoa(n)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
for i := 100; i <= 999; i++ {
|
||||||
|
if v := http.StatusText(i); v != "" {
|
||||||
|
httpCodeStringCommon[i] = strconv.Itoa(i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func httpCodeString(code int) string {
|
||||||
|
if s, ok := httpCodeStringCommon[code]; ok {
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
return strconv.Itoa(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
// from pkg io
|
||||||
|
type stringWriter interface {
|
||||||
|
WriteString(s string) (n int, err error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A gate lets two goroutines coordinate their activities.
|
||||||
|
type gate chan struct{}
|
||||||
|
|
||||||
|
func (g gate) Done() { g <- struct{}{} }
|
||||||
|
func (g gate) Wait() { <-g }
|
||||||
|
|
||||||
|
// A closeWaiter is like a sync.WaitGroup but only goes 1 to 0 (open to closed).
|
||||||
|
type closeWaiter chan struct{}
|
||||||
|
|
||||||
|
// Init makes a closeWaiter usable.
|
||||||
|
// It exists because so a closeWaiter value can be placed inside a
|
||||||
|
// larger struct and have the Mutex and Cond's memory in the same
|
||||||
|
// allocation.
|
||||||
|
func (cw *closeWaiter) Init() {
|
||||||
|
*cw = make(chan struct{})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close marks the closeWaiter as closed and unblocks any waiters.
|
||||||
|
func (cw closeWaiter) Close() {
|
||||||
|
close(cw)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait waits for the closeWaiter to become closed.
|
||||||
|
func (cw closeWaiter) Wait() {
|
||||||
|
<-cw
|
||||||
|
}
|
||||||
|
|
||||||
|
// bufferedWriter is a buffered writer that writes to w.
|
||||||
|
// Its buffered writer is lazily allocated as needed, to minimize
|
||||||
|
// idle memory usage with many connections.
|
||||||
|
type bufferedWriter struct {
|
||||||
|
w io.Writer // immutable
|
||||||
|
bw *bufio.Writer // non-nil when data is buffered
|
||||||
|
}
|
||||||
|
|
||||||
|
func newBufferedWriter(w io.Writer) *bufferedWriter {
|
||||||
|
return &bufferedWriter{w: w}
|
||||||
|
}
|
||||||
|
|
||||||
|
var bufWriterPool = sync.Pool{
|
||||||
|
New: func() interface{} {
|
||||||
|
// TODO: pick something better? this is a bit under
|
||||||
|
// (3 x typical 1500 byte MTU) at least.
|
||||||
|
return bufio.NewWriterSize(nil, 4<<10)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bufferedWriter) Write(p []byte) (n int, err error) {
|
||||||
|
if w.bw == nil {
|
||||||
|
bw := bufWriterPool.Get().(*bufio.Writer)
|
||||||
|
bw.Reset(w.w)
|
||||||
|
w.bw = bw
|
||||||
|
}
|
||||||
|
return w.bw.Write(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w *bufferedWriter) Flush() error {
|
||||||
|
bw := w.bw
|
||||||
|
if bw == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
err := bw.Flush()
|
||||||
|
bw.Reset(nil)
|
||||||
|
bufWriterPool.Put(bw)
|
||||||
|
w.bw = nil
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func mustUint31(v int32) uint32 {
|
||||||
|
if v < 0 || v > 2147483647 {
|
||||||
|
panic("out of range")
|
||||||
|
}
|
||||||
|
return uint32(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// bodyAllowedForStatus reports whether a given response status code
|
||||||
|
// permits a body. See RFC2616, section 4.4.
|
||||||
|
func bodyAllowedForStatus(status int) bool {
|
||||||
|
switch {
|
||||||
|
case status >= 100 && status <= 199:
|
||||||
|
return false
|
||||||
|
case status == 204:
|
||||||
|
return false
|
||||||
|
case status == 304:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
type httpError struct {
|
||||||
|
msg string
|
||||||
|
timeout bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *httpError) Error() string { return e.msg }
|
||||||
|
func (e *httpError) Timeout() bool { return e.timeout }
|
||||||
|
func (e *httpError) Temporary() bool { return true }
|
||||||
|
|
||||||
|
var errTimeout error = &httpError{msg: "http2: timeout awaiting response headers", timeout: true}
|
||||||
|
|
||||||
|
var isTokenTable = [127]bool{
|
||||||
|
'!': true,
|
||||||
|
'#': true,
|
||||||
|
'$': true,
|
||||||
|
'%': true,
|
||||||
|
'&': true,
|
||||||
|
'\'': true,
|
||||||
|
'*': true,
|
||||||
|
'+': true,
|
||||||
|
'-': true,
|
||||||
|
'.': true,
|
||||||
|
'0': true,
|
||||||
|
'1': true,
|
||||||
|
'2': true,
|
||||||
|
'3': true,
|
||||||
|
'4': true,
|
||||||
|
'5': true,
|
||||||
|
'6': true,
|
||||||
|
'7': true,
|
||||||
|
'8': true,
|
||||||
|
'9': true,
|
||||||
|
'A': true,
|
||||||
|
'B': true,
|
||||||
|
'C': true,
|
||||||
|
'D': true,
|
||||||
|
'E': true,
|
||||||
|
'F': true,
|
||||||
|
'G': true,
|
||||||
|
'H': true,
|
||||||
|
'I': true,
|
||||||
|
'J': true,
|
||||||
|
'K': true,
|
||||||
|
'L': true,
|
||||||
|
'M': true,
|
||||||
|
'N': true,
|
||||||
|
'O': true,
|
||||||
|
'P': true,
|
||||||
|
'Q': true,
|
||||||
|
'R': true,
|
||||||
|
'S': true,
|
||||||
|
'T': true,
|
||||||
|
'U': true,
|
||||||
|
'W': true,
|
||||||
|
'V': true,
|
||||||
|
'X': true,
|
||||||
|
'Y': true,
|
||||||
|
'Z': true,
|
||||||
|
'^': true,
|
||||||
|
'_': true,
|
||||||
|
'`': true,
|
||||||
|
'a': true,
|
||||||
|
'b': true,
|
||||||
|
'c': true,
|
||||||
|
'd': true,
|
||||||
|
'e': true,
|
||||||
|
'f': true,
|
||||||
|
'g': true,
|
||||||
|
'h': true,
|
||||||
|
'i': true,
|
||||||
|
'j': true,
|
||||||
|
'k': true,
|
||||||
|
'l': true,
|
||||||
|
'm': true,
|
||||||
|
'n': true,
|
||||||
|
'o': true,
|
||||||
|
'p': true,
|
||||||
|
'q': true,
|
||||||
|
'r': true,
|
||||||
|
's': true,
|
||||||
|
't': true,
|
||||||
|
'u': true,
|
||||||
|
'v': true,
|
||||||
|
'w': true,
|
||||||
|
'x': true,
|
||||||
|
'y': true,
|
||||||
|
'z': true,
|
||||||
|
'|': true,
|
||||||
|
'~': true,
|
||||||
|
}
|
||||||
|
|
||||||
|
type connectionStater interface {
|
||||||
|
ConnectionState() tls.ConnectionState
|
||||||
|
}
|
||||||
|
|
||||||
|
var sorterPool = sync.Pool{New: func() interface{} { return new(sorter) }}
|
||||||
|
|
||||||
|
type sorter struct {
|
||||||
|
v []string // owned by sorter
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sorter) Len() int { return len(s.v) }
|
||||||
|
func (s *sorter) Swap(i, j int) { s.v[i], s.v[j] = s.v[j], s.v[i] }
|
||||||
|
func (s *sorter) Less(i, j int) bool { return s.v[i] < s.v[j] }
|
||||||
|
|
||||||
|
// Keys returns the sorted keys of h.
|
||||||
|
//
|
||||||
|
// The returned slice is only valid until s used again or returned to
|
||||||
|
// its pool.
|
||||||
|
func (s *sorter) Keys(h http.Header) []string {
|
||||||
|
keys := s.v[:0]
|
||||||
|
for k := range h {
|
||||||
|
keys = append(keys, k)
|
||||||
|
}
|
||||||
|
s.v = keys
|
||||||
|
sort.Sort(s)
|
||||||
|
return keys
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *sorter) SortStrings(ss []string) {
|
||||||
|
// Our sorter works on s.v, which sorter owners, so
|
||||||
|
// stash it away while we sort the user's buffer.
|
||||||
|
save := s.v
|
||||||
|
s.v = ss
|
||||||
|
sort.Sort(s)
|
||||||
|
s.v = save
|
||||||
|
}
|
11
vendor/golang.org/x/net/http2/not_go15.go
generated
vendored
Normal file
11
vendor/golang.org/x/net/http2/not_go15.go
generated
vendored
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.5
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func requestCancel(req *http.Request) <-chan struct{} { return nil }
|
13
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
Normal file
13
vendor/golang.org/x/net/http2/not_go16.go
generated
vendored
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !go1.6
|
||||||
|
|
||||||
|
package http2
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
func configureTransport(t1 *http.Transport) (*Transport, error) {
|
||||||
|
return nil, errTransportVersion
|
||||||
|
}
|
147
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
Normal file
147
vendor/golang.org/x/net/http2/pipe.go
generated
vendored
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
// Copyright 2014 The Go 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 http2
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"io"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
|
||||||
|
// io.Pipe except there are no PipeReader/PipeWriter halves, and the
|
||||||
|
// underlying buffer is an interface. (io.Pipe is always unbuffered)
|
||||||
|
type pipe struct {
|
||||||
|
mu sync.Mutex
|
||||||
|
c sync.Cond // c.L lazily initialized to &p.mu
|
||||||
|
b pipeBuffer
|
||||||
|
err error // read error once empty. non-nil means closed.
|
||||||
|
breakErr error // immediate read error (caller doesn't see rest of b)
|
||||||
|
donec chan struct{} // closed on error
|
||||||
|
readFn func() // optional code to run in Read before error
|
||||||
|
}
|
||||||
|
|
||||||
|
type pipeBuffer interface {
|
||||||
|
Len() int
|
||||||
|
io.Writer
|
||||||
|
io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read waits until data is available and copies bytes
|
||||||
|
// from the buffer into p.
|
||||||
|
func (p *pipe) Read(d []byte) (n int, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
if p.breakErr != nil {
|
||||||
|
return 0, p.breakErr
|
||||||
|
}
|
||||||
|
if p.b.Len() > 0 {
|
||||||
|
return p.b.Read(d)
|
||||||
|
}
|
||||||
|
if p.err != nil {
|
||||||
|
if p.readFn != nil {
|
||||||
|
p.readFn() // e.g. copy trailers
|
||||||
|
p.readFn = nil // not sticky like p.err
|
||||||
|
}
|
||||||
|
return 0, p.err
|
||||||
|
}
|
||||||
|
p.c.Wait()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errClosedPipeWrite = errors.New("write on closed buffer")
|
||||||
|
|
||||||
|
// Write copies bytes from p into the buffer and wakes a reader.
|
||||||
|
// It is an error to write more data than the buffer can hold.
|
||||||
|
func (p *pipe) Write(d []byte) (n int, err error) {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
defer p.c.Signal()
|
||||||
|
if p.err != nil {
|
||||||
|
return 0, errClosedPipeWrite
|
||||||
|
}
|
||||||
|
return p.b.Write(d)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CloseWithError causes the next Read (waking up a current blocked
|
||||||
|
// Read if needed) to return the provided err after all data has been
|
||||||
|
// read.
|
||||||
|
//
|
||||||
|
// The error must be non-nil.
|
||||||
|
func (p *pipe) CloseWithError(err error) { p.closeWithError(&p.err, err, nil) }
|
||||||
|
|
||||||
|
// BreakWithError causes the next Read (waking up a current blocked
|
||||||
|
// Read if needed) to return the provided err immediately, without
|
||||||
|
// waiting for unread data.
|
||||||
|
func (p *pipe) BreakWithError(err error) { p.closeWithError(&p.breakErr, err, nil) }
|
||||||
|
|
||||||
|
// closeWithErrorAndCode is like CloseWithError but also sets some code to run
|
||||||
|
// in the caller's goroutine before returning the error.
|
||||||
|
func (p *pipe) closeWithErrorAndCode(err error, fn func()) { p.closeWithError(&p.err, err, fn) }
|
||||||
|
|
||||||
|
func (p *pipe) closeWithError(dst *error, err error, fn func()) {
|
||||||
|
if err == nil {
|
||||||
|
panic("err must be non-nil")
|
||||||
|
}
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.c.L == nil {
|
||||||
|
p.c.L = &p.mu
|
||||||
|
}
|
||||||
|
defer p.c.Signal()
|
||||||
|
if *dst != nil {
|
||||||
|
// Already been done.
|
||||||
|
return
|
||||||
|
}
|
||||||
|
p.readFn = fn
|
||||||
|
*dst = err
|
||||||
|
p.closeDoneLocked()
|
||||||
|
}
|
||||||
|
|
||||||
|
// requires p.mu be held.
|
||||||
|
func (p *pipe) closeDoneLocked() {
|
||||||
|
if p.donec == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// Close if unclosed. This isn't racy since we always
|
||||||
|
// hold p.mu while closing.
|
||||||
|
select {
|
||||||
|
case <-p.donec:
|
||||||
|
default:
|
||||||
|
close(p.donec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Err returns the error (if any) first set by BreakWithError or CloseWithError.
|
||||||
|
func (p *pipe) Err() error {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.breakErr != nil {
|
||||||
|
return p.breakErr
|
||||||
|
}
|
||||||
|
return p.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Done returns a channel which is closed if and when this pipe is closed
|
||||||
|
// with CloseWithError.
|
||||||
|
func (p *pipe) Done() <-chan struct{} {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
if p.donec == nil {
|
||||||
|
p.donec = make(chan struct{})
|
||||||
|
if p.err != nil || p.breakErr != nil {
|
||||||
|
// Already hit an error.
|
||||||
|
p.closeDoneLocked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return p.donec
|
||||||
|
}
|
1110
vendor/github.com/bradfitz/http2/server.go → vendor/golang.org/x/net/http2/server.go
generated
vendored
1110
vendor/github.com/bradfitz/http2/server.go → vendor/golang.org/x/net/http2/server.go
generated
vendored
File diff suppressed because it is too large
Load diff
1666
vendor/golang.org/x/net/http2/transport.go
generated
vendored
Normal file
1666
vendor/golang.org/x/net/http2/transport.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
100
vendor/github.com/bradfitz/http2/write.go → vendor/golang.org/x/net/http2/write.go
generated
vendored
100
vendor/github.com/bradfitz/http2/write.go → vendor/golang.org/x/net/http2/write.go
generated
vendored
|
@ -1,19 +1,17 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
package http2
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/bradfitz/http2/hpack"
|
"golang.org/x/net/http2/hpack"
|
||||||
)
|
)
|
||||||
|
|
||||||
// writeFramer is implemented by any type that is used to write frames.
|
// writeFramer is implemented by any type that is used to write frames.
|
||||||
|
@ -26,7 +24,11 @@ type writeFramer interface {
|
||||||
// frame writing scheduler (see writeScheduler in writesched.go).
|
// frame writing scheduler (see writeScheduler in writesched.go).
|
||||||
//
|
//
|
||||||
// This interface is implemented by *serverConn.
|
// This interface is implemented by *serverConn.
|
||||||
// TODO: use it from the client code too, once it exists.
|
//
|
||||||
|
// TODO: decide whether to a) use this in the client code (which didn't
|
||||||
|
// end up using this yet, because it has a simpler design, not
|
||||||
|
// currently implementing priorities), or b) delete this and
|
||||||
|
// make the server code a bit more concrete.
|
||||||
type writeContext interface {
|
type writeContext interface {
|
||||||
Framer() *Framer
|
Framer() *Framer
|
||||||
Flush() error
|
Flush() error
|
||||||
|
@ -44,6 +46,11 @@ func endsStream(w writeFramer) bool {
|
||||||
return v.endStream
|
return v.endStream
|
||||||
case *writeResHeaders:
|
case *writeResHeaders:
|
||||||
return v.endStream
|
return v.endStream
|
||||||
|
case nil:
|
||||||
|
// This can only happen if the caller reuses w after it's
|
||||||
|
// been intentionally nil'ed out to prevent use. Keep this
|
||||||
|
// here to catch future refactoring breaking it.
|
||||||
|
panic("endsStream called on nil writeFramer")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@ -89,6 +96,16 @@ func (w *writeData) writeFrame(ctx writeContext) error {
|
||||||
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
|
return ctx.Framer().WriteData(w.streamID, w.endStream, w.p)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// handlerPanicRST is the message sent from handler goroutines when
|
||||||
|
// the handler panics.
|
||||||
|
type handlerPanicRST struct {
|
||||||
|
StreamID uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
func (hp handlerPanicRST) writeFrame(ctx writeContext) error {
|
||||||
|
return ctx.Framer().WriteRSTStream(hp.StreamID, ErrCodeInternal)
|
||||||
|
}
|
||||||
|
|
||||||
func (se StreamError) writeFrame(ctx writeContext) error {
|
func (se StreamError) writeFrame(ctx writeContext) error {
|
||||||
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
|
return ctx.Framer().WriteRSTStream(se.StreamID, se.Code)
|
||||||
}
|
}
|
||||||
|
@ -106,40 +123,48 @@ func (writeSettingsAck) writeFrame(ctx writeContext) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
|
// writeResHeaders is a request to write a HEADERS and 0+ CONTINUATION frames
|
||||||
// for HTTP response headers from a server handler.
|
// for HTTP response headers or trailers from a server handler.
|
||||||
type writeResHeaders struct {
|
type writeResHeaders struct {
|
||||||
streamID uint32
|
streamID uint32
|
||||||
httpResCode int
|
httpResCode int // 0 means no ":status" line
|
||||||
h http.Header // may be nil
|
h http.Header // may be nil
|
||||||
|
trailers []string // if non-nil, which keys of h to write. nil means all.
|
||||||
endStream bool
|
endStream bool
|
||||||
|
|
||||||
|
date string
|
||||||
contentType string
|
contentType string
|
||||||
contentLength string
|
contentLength string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encKV(enc *hpack.Encoder, k, v string) {
|
||||||
|
if VerboseLogs {
|
||||||
|
log.Printf("http2: server encoding header %q = %q", k, v)
|
||||||
|
}
|
||||||
|
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
||||||
|
}
|
||||||
|
|
||||||
func (w *writeResHeaders) writeFrame(ctx writeContext) error {
|
func (w *writeResHeaders) writeFrame(ctx writeContext) error {
|
||||||
enc, buf := ctx.HeaderEncoder()
|
enc, buf := ctx.HeaderEncoder()
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: httpCodeString(w.httpResCode)})
|
|
||||||
for k, vv := range w.h {
|
if w.httpResCode != 0 {
|
||||||
k = lowerHeader(k)
|
encKV(enc, ":status", httpCodeString(w.httpResCode))
|
||||||
for _, v := range vv {
|
|
||||||
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
|
|
||||||
if k == "transfer-encoding" && v != "trailers" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
enc.WriteField(hpack.HeaderField{Name: k, Value: v})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
encodeHeaders(enc, w.h, w.trailers)
|
||||||
|
|
||||||
if w.contentType != "" {
|
if w.contentType != "" {
|
||||||
enc.WriteField(hpack.HeaderField{Name: "content-type", Value: w.contentType})
|
encKV(enc, "content-type", w.contentType)
|
||||||
}
|
}
|
||||||
if w.contentLength != "" {
|
if w.contentLength != "" {
|
||||||
enc.WriteField(hpack.HeaderField{Name: "content-length", Value: w.contentLength})
|
encKV(enc, "content-length", w.contentLength)
|
||||||
|
}
|
||||||
|
if w.date != "" {
|
||||||
|
encKV(enc, "date", w.date)
|
||||||
}
|
}
|
||||||
|
|
||||||
headerBlock := buf.Bytes()
|
headerBlock := buf.Bytes()
|
||||||
if len(headerBlock) == 0 {
|
if len(headerBlock) == 0 && w.trailers == nil {
|
||||||
panic("unexpected empty hpack")
|
panic("unexpected empty hpack")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -185,7 +210,7 @@ type write100ContinueHeadersFrame struct {
|
||||||
func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
|
func (w write100ContinueHeadersFrame) writeFrame(ctx writeContext) error {
|
||||||
enc, buf := ctx.HeaderEncoder()
|
enc, buf := ctx.HeaderEncoder()
|
||||||
buf.Reset()
|
buf.Reset()
|
||||||
enc.WriteField(hpack.HeaderField{Name: ":status", Value: "100"})
|
encKV(enc, ":status", "100")
|
||||||
return ctx.Framer().WriteHeaders(HeadersFrameParam{
|
return ctx.Framer().WriteHeaders(HeadersFrameParam{
|
||||||
StreamID: w.streamID,
|
StreamID: w.streamID,
|
||||||
BlockFragment: buf.Bytes(),
|
BlockFragment: buf.Bytes(),
|
||||||
|
@ -202,3 +227,36 @@ type writeWindowUpdate struct {
|
||||||
func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
|
func (wu writeWindowUpdate) writeFrame(ctx writeContext) error {
|
||||||
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
|
return ctx.Framer().WriteWindowUpdate(wu.streamID, wu.n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func encodeHeaders(enc *hpack.Encoder, h http.Header, keys []string) {
|
||||||
|
if keys == nil {
|
||||||
|
sorter := sorterPool.Get().(*sorter)
|
||||||
|
// Using defer here, since the returned keys from the
|
||||||
|
// sorter.Keys method is only valid until the sorter
|
||||||
|
// is returned:
|
||||||
|
defer sorterPool.Put(sorter)
|
||||||
|
keys = sorter.Keys(h)
|
||||||
|
}
|
||||||
|
for _, k := range keys {
|
||||||
|
vv := h[k]
|
||||||
|
k = lowerHeader(k)
|
||||||
|
if !validHeaderFieldName(k) {
|
||||||
|
// TODO: return an error? golang.org/issue/14048
|
||||||
|
// For now just omit it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
isTE := k == "transfer-encoding"
|
||||||
|
for _, v := range vv {
|
||||||
|
if !validHeaderFieldValue(v) {
|
||||||
|
// TODO: return an error? golang.org/issue/14048
|
||||||
|
// For now just omit it.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// TODO: more of "8.1.2.2 Connection-Specific Header Fields"
|
||||||
|
if isTE && v != "trailers" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
encKV(enc, k, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,6 @@
|
||||||
// Copyright 2014 The Go Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
// See https://code.google.com/p/go/source/browse/CONTRIBUTORS
|
|
||||||
// Licensed under the same terms as Go itself:
|
|
||||||
// https://code.google.com/p/go/source/browse/LICENSE
|
|
||||||
|
|
||||||
package http2
|
package http2
|
||||||
|
|
15
vendor/golang.org/x/net/trace/trace.go
generated
vendored
15
vendor/golang.org/x/net/trace/trace.go
generated
vendored
|
@ -95,11 +95,14 @@ var DebugUseAfterFinish = false
|
||||||
//
|
//
|
||||||
// The default AuthRequest function returns (true, true) iff the request comes from localhost/127.0.0.1/[::1].
|
// The default AuthRequest function returns (true, true) iff the request comes from localhost/127.0.0.1/[::1].
|
||||||
var AuthRequest = func(req *http.Request) (any, sensitive bool) {
|
var AuthRequest = func(req *http.Request) (any, sensitive bool) {
|
||||||
|
// RemoteAddr is commonly in the form "IP" or "IP:port".
|
||||||
|
// If it is in the form "IP:port", split off the port.
|
||||||
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
host, _, err := net.SplitHostPort(req.RemoteAddr)
|
||||||
switch {
|
if err != nil {
|
||||||
case err != nil: // Badly formed address; fail closed.
|
host = req.RemoteAddr
|
||||||
return false, false
|
}
|
||||||
case host == "localhost" || host == "127.0.0.1" || host == "::1":
|
switch host {
|
||||||
|
case "localhost", "127.0.0.1", "::1":
|
||||||
return true, true
|
return true, true
|
||||||
default:
|
default:
|
||||||
return false, false
|
return false, false
|
||||||
|
@ -113,6 +116,7 @@ func init() {
|
||||||
http.Error(w, "not allowed", http.StatusUnauthorized)
|
http.Error(w, "not allowed", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
Render(w, req, sensitive)
|
Render(w, req, sensitive)
|
||||||
})
|
})
|
||||||
http.HandleFunc("/debug/events", func(w http.ResponseWriter, req *http.Request) {
|
http.HandleFunc("/debug/events", func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
@ -121,6 +125,7 @@ func init() {
|
||||||
http.Error(w, "not allowed", http.StatusUnauthorized)
|
http.Error(w, "not allowed", http.StatusUnauthorized)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
RenderEvents(w, req, sensitive)
|
RenderEvents(w, req, sensitive)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -172,7 +177,7 @@ func Render(w io.Writer, req *http.Request, sensitive bool) {
|
||||||
|
|
||||||
completedMu.RLock()
|
completedMu.RLock()
|
||||||
data.Families = make([]string, 0, len(completedTraces))
|
data.Families = make([]string, 0, len(completedTraces))
|
||||||
for fam, _ := range completedTraces {
|
for fam := range completedTraces {
|
||||||
data.Families = append(data.Families, fam)
|
data.Families = append(data.Families, fam)
|
||||||
}
|
}
|
||||||
completedMu.RUnlock()
|
completedMu.RUnlock()
|
||||||
|
|
4
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
4
vendor/golang.org/x/oauth2/client_appengine.go
generated
vendored
|
@ -1,8 +1,8 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build appengine appenginevm
|
// +build appengine
|
||||||
|
|
||||||
// App Engine hooks.
|
// App Engine hooks.
|
||||||
|
|
||||||
|
|
5
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
5
vendor/golang.org/x/oauth2/google/appengine.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -14,6 +14,9 @@ import (
|
||||||
"golang.org/x/oauth2"
|
"golang.org/x/oauth2"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Set at init time by appenginevm_hook.go. If true, we are on App Engine Managed VMs.
|
||||||
|
var appengineVM bool
|
||||||
|
|
||||||
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
// Set at init time by appengine_hook.go. If nil, we're not on App Engine.
|
||||||
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
|
var appengineTokenFunc func(c context.Context, scopes ...string) (token string, expiry time.Time, err error)
|
||||||
|
|
||||||
|
|
4
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
4
vendor/golang.org/x/oauth2/google/appengine_hook.go
generated
vendored
|
@ -1,8 +1,8 @@
|
||||||
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// +build appengine appenginevm
|
// +build appengine
|
||||||
|
|
||||||
package google
|
package google
|
||||||
|
|
||||||
|
|
14
vendor/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
Normal file
14
vendor/golang.org/x/oauth2/google/appenginevm_hook.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appenginevm
|
||||||
|
|
||||||
|
package google
|
||||||
|
|
||||||
|
import "google.golang.org/appengine"
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
appengineVM = true
|
||||||
|
appengineTokenFunc = appengine.AccessToken
|
||||||
|
}
|
7
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
7
vendor/golang.org/x/oauth2/google/default.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -50,7 +50,8 @@ func DefaultClient(ctx context.Context, scope ...string) (*http.Client, error) {
|
||||||
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
|
// On Windows, this is %APPDATA%/gcloud/application_default_credentials.json.
|
||||||
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
// On other systems, $HOME/.config/gcloud/application_default_credentials.json.
|
||||||
// 3. On Google App Engine it uses the appengine.AccessToken function.
|
// 3. On Google App Engine it uses the appengine.AccessToken function.
|
||||||
// 4. On Google Compute Engine, it fetches credentials from the metadata server.
|
// 4. On Google Compute Engine and Google App Engine Managed VMs, it fetches
|
||||||
|
// credentials from the metadata server.
|
||||||
// (In this final case any provided scopes are ignored.)
|
// (In this final case any provided scopes are ignored.)
|
||||||
//
|
//
|
||||||
// For more details, see:
|
// For more details, see:
|
||||||
|
@ -84,7 +85,7 @@ func DefaultTokenSource(ctx context.Context, scope ...string) (oauth2.TokenSourc
|
||||||
}
|
}
|
||||||
|
|
||||||
// Third, if we're on Google App Engine use those credentials.
|
// Third, if we're on Google App Engine use those credentials.
|
||||||
if appengineTokenFunc != nil {
|
if appengineTokenFunc != nil && !appengineVM {
|
||||||
return AppEngineTokenSource(ctx, scope...), nil
|
return AppEngineTokenSource(ctx, scope...), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
2
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
2
vendor/golang.org/x/oauth2/google/google.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
71
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
Normal file
71
vendor/golang.org/x/oauth2/google/jwt.go
generated
vendored
Normal file
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright 2015 The Go 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 google
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/rsa"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/oauth2"
|
||||||
|
"golang.org/x/oauth2/internal"
|
||||||
|
"golang.org/x/oauth2/jws"
|
||||||
|
)
|
||||||
|
|
||||||
|
// JWTAccessTokenSourceFromJSON uses a Google Developers service account JSON
|
||||||
|
// key file to read the credentials that authorize and authenticate the
|
||||||
|
// requests, and returns a TokenSource that does not use any OAuth2 flow but
|
||||||
|
// instead creates a JWT and sends that as the access token.
|
||||||
|
// The audience is typically a URL that specifies the scope of the credentials.
|
||||||
|
//
|
||||||
|
// Note that this is not a standard OAuth flow, but rather an
|
||||||
|
// optimization supported by a few Google services.
|
||||||
|
// Unless you know otherwise, you should use JWTConfigFromJSON instead.
|
||||||
|
func JWTAccessTokenSourceFromJSON(jsonKey []byte, audience string) (oauth2.TokenSource, error) {
|
||||||
|
cfg, err := JWTConfigFromJSON(jsonKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("google: could not parse JSON key: %v", err)
|
||||||
|
}
|
||||||
|
pk, err := internal.ParseKey(cfg.PrivateKey)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("google: could not parse key: %v", err)
|
||||||
|
}
|
||||||
|
ts := &jwtAccessTokenSource{
|
||||||
|
email: cfg.Email,
|
||||||
|
audience: audience,
|
||||||
|
pk: pk,
|
||||||
|
}
|
||||||
|
tok, err := ts.Token()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return oauth2.ReuseTokenSource(tok, ts), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type jwtAccessTokenSource struct {
|
||||||
|
email, audience string
|
||||||
|
pk *rsa.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ts *jwtAccessTokenSource) Token() (*oauth2.Token, error) {
|
||||||
|
iat := time.Now()
|
||||||
|
exp := iat.Add(time.Hour)
|
||||||
|
cs := &jws.ClaimSet{
|
||||||
|
Iss: ts.email,
|
||||||
|
Sub: ts.email,
|
||||||
|
Aud: ts.audience,
|
||||||
|
Iat: iat.Unix(),
|
||||||
|
Exp: exp.Unix(),
|
||||||
|
}
|
||||||
|
hdr := &jws.Header{
|
||||||
|
Algorithm: "RS256",
|
||||||
|
Typ: "JWT",
|
||||||
|
}
|
||||||
|
msg, err := jws.Encode(hdr, cs, ts.pk)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("google: could not encode JWT: %v", err)
|
||||||
|
}
|
||||||
|
return &oauth2.Token{AccessToken: msg, TokenType: "Bearer", Expiry: exp}, nil
|
||||||
|
}
|
2
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
2
vendor/golang.org/x/oauth2/google/sdk.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2015 The oauth2 Authors. All rights reserved.
|
// Copyright 2015 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
2
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
2
vendor/golang.org/x/oauth2/internal/oauth2.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
36
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
36
vendor/golang.org/x/oauth2/internal/token.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -91,25 +91,35 @@ func (e *expirationTime) UnmarshalJSON(b []byte) error {
|
||||||
|
|
||||||
var brokenAuthHeaderProviders = []string{
|
var brokenAuthHeaderProviders = []string{
|
||||||
"https://accounts.google.com/",
|
"https://accounts.google.com/",
|
||||||
"https://www.googleapis.com/",
|
|
||||||
"https://github.com/",
|
|
||||||
"https://api.instagram.com/",
|
|
||||||
"https://www.douban.com/",
|
|
||||||
"https://api.dropbox.com/",
|
"https://api.dropbox.com/",
|
||||||
"https://api.soundcloud.com/",
|
"https://api.instagram.com/",
|
||||||
"https://www.linkedin.com/",
|
"https://api.netatmo.net/",
|
||||||
"https://api.twitch.tv/",
|
|
||||||
"https://oauth.vk.com/",
|
|
||||||
"https://api.odnoklassniki.ru/",
|
"https://api.odnoklassniki.ru/",
|
||||||
"https://connect.stripe.com/",
|
|
||||||
"https://api.pushbullet.com/",
|
"https://api.pushbullet.com/",
|
||||||
|
"https://api.soundcloud.com/",
|
||||||
|
"https://api.twitch.tv/",
|
||||||
|
"https://app.box.com/",
|
||||||
|
"https://connect.stripe.com/",
|
||||||
|
"https://login.microsoftonline.com/",
|
||||||
|
"https://login.salesforce.com/",
|
||||||
"https://oauth.sandbox.trainingpeaks.com/",
|
"https://oauth.sandbox.trainingpeaks.com/",
|
||||||
"https://oauth.trainingpeaks.com/",
|
"https://oauth.trainingpeaks.com/",
|
||||||
"https://www.strava.com/oauth/",
|
"https://oauth.vk.com/",
|
||||||
"https://app.box.com/",
|
"https://openapi.baidu.com/",
|
||||||
|
"https://slack.com/",
|
||||||
"https://test-sandbox.auth.corp.google.com",
|
"https://test-sandbox.auth.corp.google.com",
|
||||||
|
"https://test.salesforce.com/",
|
||||||
"https://user.gini.net/",
|
"https://user.gini.net/",
|
||||||
"https://api.netatmo.net/",
|
"https://www.douban.com/",
|
||||||
|
"https://www.googleapis.com/",
|
||||||
|
"https://www.linkedin.com/",
|
||||||
|
"https://www.strava.com/oauth/",
|
||||||
|
"https://www.wunderlist.com/oauth/",
|
||||||
|
"https://api.patreon.com/",
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||||
|
brokenAuthHeaderProviders = append(brokenAuthHeaderProviders, tokenURL)
|
||||||
}
|
}
|
||||||
|
|
||||||
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
|
// providerAuthHeaderWorks reports whether the OAuth2 server identified by the tokenURL
|
||||||
|
|
10
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
10
vendor/golang.org/x/oauth2/internal/transport.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -33,6 +33,11 @@ func RegisterContextClientFunc(fn ContextClientFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func ContextClient(ctx context.Context) (*http.Client, error) {
|
func ContextClient(ctx context.Context) (*http.Client, error) {
|
||||||
|
if ctx != nil {
|
||||||
|
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
||||||
|
return hc, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
for _, fn := range contextClientFuncs {
|
for _, fn := range contextClientFuncs {
|
||||||
c, err := fn(ctx)
|
c, err := fn(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -42,9 +47,6 @@ func ContextClient(ctx context.Context) (*http.Client, error) {
|
||||||
return c, nil
|
return c, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if hc, ok := ctx.Value(HTTPClient).(*http.Client); ok {
|
|
||||||
return hc, nil
|
|
||||||
}
|
|
||||||
return http.DefaultClient, nil
|
return http.DefaultClient, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
58
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
58
vendor/golang.org/x/oauth2/jws/jws.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -27,8 +27,8 @@ type ClaimSet struct {
|
||||||
Iss string `json:"iss"` // email address of the client_id of the application making the access token request
|
Iss string `json:"iss"` // email address of the client_id of the application making the access token request
|
||||||
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
|
Scope string `json:"scope,omitempty"` // space-delimited list of the permissions the application requests
|
||||||
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
|
Aud string `json:"aud"` // descriptor of the intended target of the assertion (Optional).
|
||||||
Exp int64 `json:"exp"` // the expiration time of the assertion
|
Exp int64 `json:"exp"` // the expiration time of the assertion (seconds since Unix epoch)
|
||||||
Iat int64 `json:"iat"` // the time the assertion was issued.
|
Iat int64 `json:"iat"` // the time the assertion was issued (seconds since Unix epoch)
|
||||||
Typ string `json:"typ,omitempty"` // token type (Optional).
|
Typ string `json:"typ,omitempty"` // token type (Optional).
|
||||||
|
|
||||||
// Email for which the application is requesting delegated access (Optional).
|
// Email for which the application is requesting delegated access (Optional).
|
||||||
|
@ -41,23 +41,22 @@ type ClaimSet struct {
|
||||||
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
|
// See http://tools.ietf.org/html/draft-jones-json-web-token-10#section-4.3
|
||||||
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
|
// This array is marshalled using custom code (see (c *ClaimSet) encode()).
|
||||||
PrivateClaims map[string]interface{} `json:"-"`
|
PrivateClaims map[string]interface{} `json:"-"`
|
||||||
|
|
||||||
exp time.Time
|
|
||||||
iat time.Time
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ClaimSet) encode() (string, error) {
|
func (c *ClaimSet) encode() (string, error) {
|
||||||
if c.exp.IsZero() || c.iat.IsZero() {
|
// Reverting time back for machines whose time is not perfectly in sync.
|
||||||
// Reverting time back for machines whose time is not perfectly in sync.
|
// If client machine's time is in the future according
|
||||||
// If client machine's time is in the future according
|
// to Google servers, an access token will not be issued.
|
||||||
// to Google servers, an access token will not be issued.
|
now := time.Now().Add(-10 * time.Second)
|
||||||
now := time.Now().Add(-10 * time.Second)
|
if c.Iat == 0 {
|
||||||
c.iat = now
|
c.Iat = now.Unix()
|
||||||
c.exp = now.Add(time.Hour)
|
}
|
||||||
|
if c.Exp == 0 {
|
||||||
|
c.Exp = now.Add(time.Hour).Unix()
|
||||||
|
}
|
||||||
|
if c.Exp < c.Iat {
|
||||||
|
return "", fmt.Errorf("jws: invalid Exp = %v; must be later than Iat = %v", c.Exp, c.Iat)
|
||||||
}
|
}
|
||||||
|
|
||||||
c.Exp = c.exp.Unix()
|
|
||||||
c.Iat = c.iat.Unix()
|
|
||||||
|
|
||||||
b, err := json.Marshal(c)
|
b, err := json.Marshal(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -120,8 +119,11 @@ func Decode(payload string) (*ClaimSet, error) {
|
||||||
return c, err
|
return c, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Encode encodes a signed JWS with provided header and claim set.
|
// Signer returns a signature for the given data.
|
||||||
func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, error) {
|
type Signer func(data []byte) (sig []byte, err error)
|
||||||
|
|
||||||
|
// EncodeWithSigner encodes a header and claim set with the provided signer.
|
||||||
|
func EncodeWithSigner(header *Header, c *ClaimSet, sg Signer) (string, error) {
|
||||||
head, err := header.encode()
|
head, err := header.encode()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
|
@ -131,14 +133,22 @@ func Encode(header *Header, c *ClaimSet, signature *rsa.PrivateKey) (string, err
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
ss := fmt.Sprintf("%s.%s", head, cs)
|
ss := fmt.Sprintf("%s.%s", head, cs)
|
||||||
h := sha256.New()
|
sig, err := sg([]byte(ss))
|
||||||
h.Write([]byte(ss))
|
|
||||||
b, err := rsa.SignPKCS1v15(rand.Reader, signature, crypto.SHA256, h.Sum(nil))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
sig := base64Encode(b)
|
return fmt.Sprintf("%s.%s", ss, base64Encode(sig)), nil
|
||||||
return fmt.Sprintf("%s.%s", ss, sig), nil
|
}
|
||||||
|
|
||||||
|
// Encode encodes a signed JWS with provided header and claim set.
|
||||||
|
// This invokes EncodeWithSigner using crypto/rsa.SignPKCS1v15 with the given RSA private key.
|
||||||
|
func Encode(header *Header, c *ClaimSet, key *rsa.PrivateKey) (string, error) {
|
||||||
|
sg := func(data []byte) (sig []byte, err error) {
|
||||||
|
h := sha256.New()
|
||||||
|
h.Write([]byte(data))
|
||||||
|
return rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, h.Sum(nil))
|
||||||
|
}
|
||||||
|
return EncodeWithSigner(header, c, sg)
|
||||||
}
|
}
|
||||||
|
|
||||||
// base64Encode returns and Base64url encoded version of the input string with any
|
// base64Encode returns and Base64url encoded version of the input string with any
|
||||||
|
@ -151,6 +161,8 @@ func base64Encode(b []byte) string {
|
||||||
func base64Decode(s string) ([]byte, error) {
|
func base64Decode(s string) ([]byte, error) {
|
||||||
// add back missing padding
|
// add back missing padding
|
||||||
switch len(s) % 4 {
|
switch len(s) % 4 {
|
||||||
|
case 1:
|
||||||
|
s += "==="
|
||||||
case 2:
|
case 2:
|
||||||
s += "=="
|
s += "=="
|
||||||
case 3:
|
case 3:
|
||||||
|
|
8
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
8
vendor/golang.org/x/oauth2/jwt/jwt.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -54,6 +54,9 @@ type Config struct {
|
||||||
|
|
||||||
// TokenURL is the endpoint required to complete the 2-legged JWT flow.
|
// TokenURL is the endpoint required to complete the 2-legged JWT flow.
|
||||||
TokenURL string
|
TokenURL string
|
||||||
|
|
||||||
|
// Expires optionally specifies how long the token is valid for.
|
||||||
|
Expires time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
// TokenSource returns a JWT TokenSource using the configuration
|
// TokenSource returns a JWT TokenSource using the configuration
|
||||||
|
@ -95,6 +98,9 @@ func (js jwtSource) Token() (*oauth2.Token, error) {
|
||||||
// to be compatible with legacy OAuth 2.0 providers.
|
// to be compatible with legacy OAuth 2.0 providers.
|
||||||
claimSet.Prn = subject
|
claimSet.Prn = subject
|
||||||
}
|
}
|
||||||
|
if t := js.conf.Expires; t > 0 {
|
||||||
|
claimSet.Exp = time.Now().Add(t).Unix()
|
||||||
|
}
|
||||||
payload, err := jws.Encode(defaultHeader, claimSet, pk)
|
payload, err := jws.Encode(defaultHeader, claimSet, pk)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
14
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
14
vendor/golang.org/x/oauth2/oauth2.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -23,6 +23,18 @@ import (
|
||||||
// your own context.Context (see https://golang.org/x/net/context).
|
// your own context.Context (see https://golang.org/x/net/context).
|
||||||
var NoContext = context.TODO()
|
var NoContext = context.TODO()
|
||||||
|
|
||||||
|
// RegisterBrokenAuthHeaderProvider registers an OAuth2 server
|
||||||
|
// identified by the tokenURL prefix as an OAuth2 implementation
|
||||||
|
// which doesn't support the HTTP Basic authentication
|
||||||
|
// scheme to authenticate with the authorization server.
|
||||||
|
// Once a server is registered, credentials (client_id and client_secret)
|
||||||
|
// will be passed as query parameters rather than being present
|
||||||
|
// in the Authorization header.
|
||||||
|
// See https://code.google.com/p/goauth2/issues/detail?id=31 for background.
|
||||||
|
func RegisterBrokenAuthHeaderProvider(tokenURL string) {
|
||||||
|
internal.RegisterBrokenAuthHeaderProvider(tokenURL)
|
||||||
|
}
|
||||||
|
|
||||||
// Config describes a typical 3-legged OAuth2 flow, with both the
|
// Config describes a typical 3-legged OAuth2 flow, with both the
|
||||||
// client application information and the server's endpoint URLs.
|
// client application information and the server's endpoint URLs.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
|
27
vendor/golang.org/x/oauth2/token.go
generated
vendored
27
vendor/golang.org/x/oauth2/token.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ package oauth2
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -92,14 +93,28 @@ func (t *Token) WithExtra(extra interface{}) *Token {
|
||||||
// Extra fields are key-value pairs returned by the server as a
|
// Extra fields are key-value pairs returned by the server as a
|
||||||
// part of the token retrieval response.
|
// part of the token retrieval response.
|
||||||
func (t *Token) Extra(key string) interface{} {
|
func (t *Token) Extra(key string) interface{} {
|
||||||
if vals, ok := t.raw.(url.Values); ok {
|
|
||||||
// TODO(jbd): Cast numeric values to int64 or float64.
|
|
||||||
return vals.Get(key)
|
|
||||||
}
|
|
||||||
if raw, ok := t.raw.(map[string]interface{}); ok {
|
if raw, ok := t.raw.(map[string]interface{}); ok {
|
||||||
return raw[key]
|
return raw[key]
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
vals, ok := t.raw.(url.Values)
|
||||||
|
if !ok {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
v := vals.Get(key)
|
||||||
|
switch s := strings.TrimSpace(v); strings.Count(s, ".") {
|
||||||
|
case 0: // Contains no "."; try to parse as int
|
||||||
|
if i, err := strconv.ParseInt(s, 10, 64); err == nil {
|
||||||
|
return i
|
||||||
|
}
|
||||||
|
case 1: // Contains a single "."; try to parse as float
|
||||||
|
if f, err := strconv.ParseFloat(s, 64); err == nil {
|
||||||
|
return f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
// expired reports whether the token is expired.
|
// expired reports whether the token is expired.
|
||||||
|
|
2
vendor/golang.org/x/oauth2/transport.go
generated
vendored
2
vendor/golang.org/x/oauth2/transport.go
generated
vendored
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2014 The oauth2 Authors. All rights reserved.
|
// Copyright 2014 The Go Authors. All rights reserved.
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
|
46
vendor/google.golang.org/api/gensupport/backoff.go
generated
vendored
Normal file
46
vendor/google.golang.org/api/gensupport/backoff.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2016 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type BackoffStrategy interface {
|
||||||
|
// Pause returns the duration of the next pause and true if the operation should be
|
||||||
|
// retried, or false if no further retries should be attempted.
|
||||||
|
Pause() (time.Duration, bool)
|
||||||
|
|
||||||
|
// Reset restores the strategy to its initial state.
|
||||||
|
Reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ExponentialBackoff performs exponential backoff as per https://en.wikipedia.org/wiki/Exponential_backoff.
|
||||||
|
// The initial pause time is given by Base.
|
||||||
|
// Once the total pause time exceeds Max, Pause will indicate no further retries.
|
||||||
|
type ExponentialBackoff struct {
|
||||||
|
Base time.Duration
|
||||||
|
Max time.Duration
|
||||||
|
total time.Duration
|
||||||
|
n uint
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eb *ExponentialBackoff) Pause() (time.Duration, bool) {
|
||||||
|
if eb.total > eb.Max {
|
||||||
|
return 0, false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The next pause is selected from randomly from [0, 2^n * Base).
|
||||||
|
d := time.Duration(rand.Int63n((1 << eb.n) * int64(eb.Base)))
|
||||||
|
eb.total += d
|
||||||
|
eb.n++
|
||||||
|
return d, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (eb *ExponentialBackoff) Reset() {
|
||||||
|
eb.n = 0
|
||||||
|
eb.total = 0
|
||||||
|
}
|
77
vendor/google.golang.org/api/gensupport/buffer.go
generated
vendored
Normal file
77
vendor/google.golang.org/api/gensupport/buffer.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
// Copyright 2016 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"io"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResumableBuffer buffers data from an io.Reader to support uploading media in retryable chunks.
|
||||||
|
type ResumableBuffer struct {
|
||||||
|
media io.Reader
|
||||||
|
|
||||||
|
chunk []byte // The current chunk which is pending upload. The capacity is the chunk size.
|
||||||
|
err error // Any error generated when populating chunk by reading media.
|
||||||
|
|
||||||
|
// The absolute position of chunk in the underlying media.
|
||||||
|
off int64
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewResumableBuffer(media io.Reader, chunkSize int) *ResumableBuffer {
|
||||||
|
return &ResumableBuffer{media: media, chunk: make([]byte, 0, chunkSize)}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chunk returns the current buffered chunk, the offset in the underlying media
|
||||||
|
// from which the chunk is drawn, and the size of the chunk.
|
||||||
|
// Successive calls to Chunk return the same chunk between calls to Next.
|
||||||
|
func (rb *ResumableBuffer) Chunk() (chunk io.Reader, off int64, size int, err error) {
|
||||||
|
// There may already be data in chunk if Next has not been called since the previous call to Chunk.
|
||||||
|
if rb.err == nil && len(rb.chunk) == 0 {
|
||||||
|
rb.err = rb.loadChunk()
|
||||||
|
}
|
||||||
|
return bytes.NewReader(rb.chunk), rb.off, len(rb.chunk), rb.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// loadChunk will read from media into chunk, up to the capacity of chunk.
|
||||||
|
func (rb *ResumableBuffer) loadChunk() error {
|
||||||
|
bufSize := cap(rb.chunk)
|
||||||
|
rb.chunk = rb.chunk[:bufSize]
|
||||||
|
|
||||||
|
read := 0
|
||||||
|
var err error
|
||||||
|
for err == nil && read < bufSize {
|
||||||
|
var n int
|
||||||
|
n, err = rb.media.Read(rb.chunk[read:])
|
||||||
|
read += n
|
||||||
|
}
|
||||||
|
rb.chunk = rb.chunk[:read]
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Next advances to the next chunk, which will be returned by the next call to Chunk.
|
||||||
|
// Calls to Next without a corresponding prior call to Chunk will have no effect.
|
||||||
|
func (rb *ResumableBuffer) Next() {
|
||||||
|
rb.off += int64(len(rb.chunk))
|
||||||
|
rb.chunk = rb.chunk[0:0]
|
||||||
|
}
|
||||||
|
|
||||||
|
type readerTyper struct {
|
||||||
|
io.Reader
|
||||||
|
googleapi.ContentTyper
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReaderAtToReader adapts a ReaderAt to be used as a Reader.
|
||||||
|
// If ra implements googleapi.ContentTyper, then the returned reader
|
||||||
|
// will also implement googleapi.ContentTyper, delegating to ra.
|
||||||
|
func ReaderAtToReader(ra io.ReaderAt, size int64) io.Reader {
|
||||||
|
r := io.NewSectionReader(ra, 0, size)
|
||||||
|
if typer, ok := ra.(googleapi.ContentTyper); ok {
|
||||||
|
return readerTyper{r, typer}
|
||||||
|
}
|
||||||
|
return r
|
||||||
|
}
|
10
vendor/google.golang.org/api/gensupport/doc.go
generated
vendored
Normal file
10
vendor/google.golang.org/api/gensupport/doc.go
generated
vendored
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
// Copyright 2016 The Go 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 gensupport is an internal implementation detail used by code
|
||||||
|
// generated by the google-api-go-generator tool.
|
||||||
|
//
|
||||||
|
// This package may be modified at any time without regard for backwards
|
||||||
|
// compatibility. It should not be used directly by API users.
|
||||||
|
package gensupport
|
172
vendor/google.golang.org/api/gensupport/json.go
generated
vendored
Normal file
172
vendor/google.golang.org/api/gensupport/json.go
generated
vendored
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
// Copyright 2015 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MarshalJSON returns a JSON encoding of schema containing only selected fields.
|
||||||
|
// A field is selected if:
|
||||||
|
// * it has a non-empty value, or
|
||||||
|
// * its field name is present in forceSendFields, and
|
||||||
|
// * it is not a nil pointer or nil interface.
|
||||||
|
// The JSON key for each selected field is taken from the field's json: struct tag.
|
||||||
|
func MarshalJSON(schema interface{}, forceSendFields []string) ([]byte, error) {
|
||||||
|
if len(forceSendFields) == 0 {
|
||||||
|
return json.Marshal(schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
mustInclude := make(map[string]struct{})
|
||||||
|
for _, f := range forceSendFields {
|
||||||
|
mustInclude[f] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
dataMap, err := schemaToMap(schema, mustInclude)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return json.Marshal(dataMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
func schemaToMap(schema interface{}, mustInclude map[string]struct{}) (map[string]interface{}, error) {
|
||||||
|
m := make(map[string]interface{})
|
||||||
|
s := reflect.ValueOf(schema)
|
||||||
|
st := s.Type()
|
||||||
|
|
||||||
|
for i := 0; i < s.NumField(); i++ {
|
||||||
|
jsonTag := st.Field(i).Tag.Get("json")
|
||||||
|
if jsonTag == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
tag, err := parseJSONTag(jsonTag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if tag.ignore {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
v := s.Field(i)
|
||||||
|
f := st.Field(i)
|
||||||
|
if !includeField(v, f, mustInclude) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil maps are treated as empty maps.
|
||||||
|
if f.Type.Kind() == reflect.Map && v.IsNil() {
|
||||||
|
m[tag.apiName] = map[string]string{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// nil slices are treated as empty slices.
|
||||||
|
if f.Type.Kind() == reflect.Slice && v.IsNil() {
|
||||||
|
m[tag.apiName] = []bool{}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if tag.stringFormat {
|
||||||
|
m[tag.apiName] = formatAsString(v, f.Type.Kind())
|
||||||
|
} else {
|
||||||
|
m[tag.apiName] = v.Interface()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return m, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// formatAsString returns a string representation of v, dereferencing it first if possible.
|
||||||
|
func formatAsString(v reflect.Value, kind reflect.Kind) string {
|
||||||
|
if kind == reflect.Ptr && !v.IsNil() {
|
||||||
|
v = v.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
return fmt.Sprintf("%v", v.Interface())
|
||||||
|
}
|
||||||
|
|
||||||
|
// jsonTag represents a restricted version of the struct tag format used by encoding/json.
|
||||||
|
// It is used to describe the JSON encoding of fields in a Schema struct.
|
||||||
|
type jsonTag struct {
|
||||||
|
apiName string
|
||||||
|
stringFormat bool
|
||||||
|
ignore bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseJSONTag parses a restricted version of the struct tag format used by encoding/json.
|
||||||
|
// The format of the tag must match that generated by the Schema.writeSchemaStruct method
|
||||||
|
// in the api generator.
|
||||||
|
func parseJSONTag(val string) (jsonTag, error) {
|
||||||
|
if val == "-" {
|
||||||
|
return jsonTag{ignore: true}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var tag jsonTag
|
||||||
|
|
||||||
|
i := strings.Index(val, ",")
|
||||||
|
if i == -1 || val[:i] == "" {
|
||||||
|
return tag, fmt.Errorf("malformed json tag: %s", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
tag = jsonTag{
|
||||||
|
apiName: val[:i],
|
||||||
|
}
|
||||||
|
|
||||||
|
switch val[i+1:] {
|
||||||
|
case "omitempty":
|
||||||
|
case "omitempty,string":
|
||||||
|
tag.stringFormat = true
|
||||||
|
default:
|
||||||
|
return tag, fmt.Errorf("malformed json tag: %s", val)
|
||||||
|
}
|
||||||
|
|
||||||
|
return tag, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reports whether the struct field "f" with value "v" should be included in JSON output.
|
||||||
|
func includeField(v reflect.Value, f reflect.StructField, mustInclude map[string]struct{}) bool {
|
||||||
|
// The regular JSON encoding of a nil pointer is "null", which means "delete this field".
|
||||||
|
// Therefore, we could enable field deletion by honoring pointer fields' presence in the mustInclude set.
|
||||||
|
// However, many fields are not pointers, so there would be no way to delete these fields.
|
||||||
|
// Rather than partially supporting field deletion, we ignore mustInclude for nil pointer fields.
|
||||||
|
// Deletion will be handled by a separate mechanism.
|
||||||
|
if f.Type.Kind() == reflect.Ptr && v.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// The "any" type is represented as an interface{}. If this interface
|
||||||
|
// is nil, there is no reasonable representation to send. We ignore
|
||||||
|
// these fields, for the same reasons as given above for pointers.
|
||||||
|
if f.Type.Kind() == reflect.Interface && v.IsNil() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
_, ok := mustInclude[f.Name]
|
||||||
|
return ok || !isEmptyValue(v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// isEmptyValue reports whether v is the empty value for its type. This
|
||||||
|
// implementation is based on that of the encoding/json package, but its
|
||||||
|
// correctness does not depend on it being identical. What's important is that
|
||||||
|
// this function return false in situations where v should not be sent as part
|
||||||
|
// of a PATCH operation.
|
||||||
|
func isEmptyValue(v reflect.Value) bool {
|
||||||
|
switch v.Kind() {
|
||||||
|
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||||
|
return v.Len() == 0
|
||||||
|
case reflect.Bool:
|
||||||
|
return !v.Bool()
|
||||||
|
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||||
|
return v.Int() == 0
|
||||||
|
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||||
|
return v.Uint() == 0
|
||||||
|
case reflect.Float32, reflect.Float64:
|
||||||
|
return v.Float() == 0
|
||||||
|
case reflect.Interface, reflect.Ptr:
|
||||||
|
return v.IsNil()
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
200
vendor/google.golang.org/api/gensupport/media.go
generated
vendored
Normal file
200
vendor/google.golang.org/api/gensupport/media.go
generated
vendored
Normal file
|
@ -0,0 +1,200 @@
|
||||||
|
// Copyright 2016 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"io/ioutil"
|
||||||
|
"mime/multipart"
|
||||||
|
"net/http"
|
||||||
|
"net/textproto"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
const sniffBuffSize = 512
|
||||||
|
|
||||||
|
func newContentSniffer(r io.Reader) *contentSniffer {
|
||||||
|
return &contentSniffer{r: r}
|
||||||
|
}
|
||||||
|
|
||||||
|
// contentSniffer wraps a Reader, and reports the content type determined by sniffing up to 512 bytes from the Reader.
|
||||||
|
type contentSniffer struct {
|
||||||
|
r io.Reader
|
||||||
|
start []byte // buffer for the sniffed bytes.
|
||||||
|
err error // set to any error encountered while reading bytes to be sniffed.
|
||||||
|
|
||||||
|
ctype string // set on first sniff.
|
||||||
|
sniffed bool // set to true on first sniff.
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cs *contentSniffer) Read(p []byte) (n int, err error) {
|
||||||
|
// Ensure that the content type is sniffed before any data is consumed from Reader.
|
||||||
|
_, _ = cs.ContentType()
|
||||||
|
|
||||||
|
if len(cs.start) > 0 {
|
||||||
|
n := copy(p, cs.start)
|
||||||
|
cs.start = cs.start[n:]
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// We may have read some bytes into start while sniffing, even if the read ended in an error.
|
||||||
|
// We should first return those bytes, then the error.
|
||||||
|
if cs.err != nil {
|
||||||
|
return 0, cs.err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we have handled all bytes that were buffered while sniffing. Now just delegate to the underlying reader.
|
||||||
|
return cs.r.Read(p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType returns the sniffed content type, and whether the content type was succesfully sniffed.
|
||||||
|
func (cs *contentSniffer) ContentType() (string, bool) {
|
||||||
|
if cs.sniffed {
|
||||||
|
return cs.ctype, cs.ctype != ""
|
||||||
|
}
|
||||||
|
cs.sniffed = true
|
||||||
|
// If ReadAll hits EOF, it returns err==nil.
|
||||||
|
cs.start, cs.err = ioutil.ReadAll(io.LimitReader(cs.r, sniffBuffSize))
|
||||||
|
|
||||||
|
// Don't try to detect the content type based on possibly incomplete data.
|
||||||
|
if cs.err != nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
|
||||||
|
cs.ctype = http.DetectContentType(cs.start)
|
||||||
|
return cs.ctype, true
|
||||||
|
}
|
||||||
|
|
||||||
|
// DetermineContentType determines the content type of the supplied reader.
|
||||||
|
// If the content type is already known, it can be specified via ctype.
|
||||||
|
// Otherwise, the content of media will be sniffed to determine the content type.
|
||||||
|
// If media implements googleapi.ContentTyper (deprecated), this will be used
|
||||||
|
// instead of sniffing the content.
|
||||||
|
// After calling DetectContentType the caller must not perform further reads on
|
||||||
|
// media, but rather read from the Reader that is returned.
|
||||||
|
func DetermineContentType(media io.Reader, ctype string) (io.Reader, string) {
|
||||||
|
// Note: callers could avoid calling DetectContentType if ctype != "",
|
||||||
|
// but doing the check inside this function reduces the amount of
|
||||||
|
// generated code.
|
||||||
|
if ctype != "" {
|
||||||
|
return media, ctype
|
||||||
|
}
|
||||||
|
|
||||||
|
// For backwards compatability, allow clients to set content
|
||||||
|
// type by providing a ContentTyper for media.
|
||||||
|
if typer, ok := media.(googleapi.ContentTyper); ok {
|
||||||
|
return media, typer.ContentType()
|
||||||
|
}
|
||||||
|
|
||||||
|
sniffer := newContentSniffer(media)
|
||||||
|
if ctype, ok := sniffer.ContentType(); ok {
|
||||||
|
return sniffer, ctype
|
||||||
|
}
|
||||||
|
// If content type could not be sniffed, reads from sniffer will eventually fail with an error.
|
||||||
|
return sniffer, ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type typeReader struct {
|
||||||
|
io.Reader
|
||||||
|
typ string
|
||||||
|
}
|
||||||
|
|
||||||
|
// multipartReader combines the contents of multiple readers to creat a multipart/related HTTP body.
|
||||||
|
// Close must be called if reads from the multipartReader are abandoned before reaching EOF.
|
||||||
|
type multipartReader struct {
|
||||||
|
pr *io.PipeReader
|
||||||
|
pipeOpen bool
|
||||||
|
ctype string
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMultipartReader(parts []typeReader) *multipartReader {
|
||||||
|
mp := &multipartReader{pipeOpen: true}
|
||||||
|
var pw *io.PipeWriter
|
||||||
|
mp.pr, pw = io.Pipe()
|
||||||
|
mpw := multipart.NewWriter(pw)
|
||||||
|
mp.ctype = "multipart/related; boundary=" + mpw.Boundary()
|
||||||
|
go func() {
|
||||||
|
for _, part := range parts {
|
||||||
|
w, err := mpw.CreatePart(typeHeader(part.typ))
|
||||||
|
if err != nil {
|
||||||
|
mpw.Close()
|
||||||
|
pw.CloseWithError(fmt.Errorf("googleapi: CreatePart failed: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
_, err = io.Copy(w, part.Reader)
|
||||||
|
if err != nil {
|
||||||
|
mpw.Close()
|
||||||
|
pw.CloseWithError(fmt.Errorf("googleapi: Copy failed: %v", err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mpw.Close()
|
||||||
|
pw.Close()
|
||||||
|
}()
|
||||||
|
return mp
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *multipartReader) Read(data []byte) (n int, err error) {
|
||||||
|
return mp.pr.Read(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (mp *multipartReader) Close() error {
|
||||||
|
if !mp.pipeOpen {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
mp.pipeOpen = false
|
||||||
|
return mp.pr.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// CombineBodyMedia combines a json body with media content to create a multipart/related HTTP body.
|
||||||
|
// It returns a ReadCloser containing the combined body, and the overall "multipart/related" content type, with random boundary.
|
||||||
|
//
|
||||||
|
// The caller must call Close on the returned ReadCloser if reads are abandoned before reaching EOF.
|
||||||
|
func CombineBodyMedia(body io.Reader, bodyContentType string, media io.Reader, mediaContentType string) (io.ReadCloser, string) {
|
||||||
|
mp := newMultipartReader([]typeReader{
|
||||||
|
{body, bodyContentType},
|
||||||
|
{media, mediaContentType},
|
||||||
|
})
|
||||||
|
return mp, mp.ctype
|
||||||
|
}
|
||||||
|
|
||||||
|
func typeHeader(contentType string) textproto.MIMEHeader {
|
||||||
|
h := make(textproto.MIMEHeader)
|
||||||
|
if contentType != "" {
|
||||||
|
h.Set("Content-Type", contentType)
|
||||||
|
}
|
||||||
|
return h
|
||||||
|
}
|
||||||
|
|
||||||
|
// PrepareUpload determines whether the data in the supplied reader should be
|
||||||
|
// uploaded in a single request, or in sequential chunks.
|
||||||
|
// chunkSize is the size of the chunk that media should be split into.
|
||||||
|
// If chunkSize is non-zero and the contents of media do not fit in a single
|
||||||
|
// chunk (or there is an error reading media), then media will be returned as a
|
||||||
|
// ResumableBuffer. Otherwise, media will be returned as a Reader.
|
||||||
|
//
|
||||||
|
// After PrepareUpload has been called, media should no longer be used: the
|
||||||
|
// media content should be accessed via one of the return values.
|
||||||
|
func PrepareUpload(media io.Reader, chunkSize int) (io.Reader,
|
||||||
|
*ResumableBuffer) {
|
||||||
|
if chunkSize == 0 { // do not chunk
|
||||||
|
return media, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
rb := NewResumableBuffer(media, chunkSize)
|
||||||
|
rdr, _, _, err := rb.Chunk()
|
||||||
|
|
||||||
|
if err == io.EOF { // we can upload this in a single request
|
||||||
|
return rdr, nil
|
||||||
|
}
|
||||||
|
// err might be a non-EOF error. If it is, the next call to rb.Chunk will
|
||||||
|
// return the same error. Returning a ResumableBuffer ensures that this error
|
||||||
|
// will be handled at some point.
|
||||||
|
|
||||||
|
return nil, rb
|
||||||
|
}
|
50
vendor/google.golang.org/api/gensupport/params.go
generated
vendored
Normal file
50
vendor/google.golang.org/api/gensupport/params.go
generated
vendored
Normal file
|
@ -0,0 +1,50 @@
|
||||||
|
// Copyright 2015 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/url"
|
||||||
|
|
||||||
|
"google.golang.org/api/googleapi"
|
||||||
|
)
|
||||||
|
|
||||||
|
// URLParams is a simplified replacement for url.Values
|
||||||
|
// that safely builds up URL parameters for encoding.
|
||||||
|
type URLParams map[string][]string
|
||||||
|
|
||||||
|
// Get returns the first value for the given key, or "".
|
||||||
|
func (u URLParams) Get(key string) string {
|
||||||
|
vs := u[key]
|
||||||
|
if len(vs) == 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return vs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set sets the key to value.
|
||||||
|
// It replaces any existing values.
|
||||||
|
func (u URLParams) Set(key, value string) {
|
||||||
|
u[key] = []string{value}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetMulti sets the key to an array of values.
|
||||||
|
// It replaces any existing values.
|
||||||
|
// Note that values must not be modified after calling SetMulti
|
||||||
|
// so the caller is responsible for making a copy if necessary.
|
||||||
|
func (u URLParams) SetMulti(key string, values []string) {
|
||||||
|
u[key] = values
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encode encodes the values into ``URL encoded'' form
|
||||||
|
// ("bar=baz&foo=quux") sorted by key.
|
||||||
|
func (u URLParams) Encode() string {
|
||||||
|
return url.Values(u).Encode()
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetOptions(u URLParams, opts ...googleapi.CallOption) {
|
||||||
|
for _, o := range opts {
|
||||||
|
u.Set(o.Get())
|
||||||
|
}
|
||||||
|
}
|
198
vendor/google.golang.org/api/gensupport/resumable.go
generated
vendored
Normal file
198
vendor/google.golang.org/api/gensupport/resumable.go
generated
vendored
Normal file
|
@ -0,0 +1,198 @@
|
||||||
|
// Copyright 2016 The Go 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 gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
"golang.org/x/net/context/ctxhttp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// statusResumeIncomplete is the code returned by the Google uploader
|
||||||
|
// when the transfer is not yet complete.
|
||||||
|
statusResumeIncomplete = 308
|
||||||
|
|
||||||
|
// statusTooManyRequests is returned by the storage API if the
|
||||||
|
// per-project limits have been temporarily exceeded. The request
|
||||||
|
// should be retried.
|
||||||
|
// https://cloud.google.com/storage/docs/json_api/v1/status-codes#standardcodes
|
||||||
|
statusTooManyRequests = 429
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResumableUpload is used by the generated APIs to provide resumable uploads.
|
||||||
|
// It is not used by developers directly.
|
||||||
|
type ResumableUpload struct {
|
||||||
|
Client *http.Client
|
||||||
|
// URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
|
||||||
|
URI string
|
||||||
|
UserAgent string // User-Agent for header of the request
|
||||||
|
// Media is the object being uploaded.
|
||||||
|
Media *ResumableBuffer
|
||||||
|
// MediaType defines the media type, e.g. "image/jpeg".
|
||||||
|
MediaType string
|
||||||
|
|
||||||
|
mu sync.Mutex // guards progress
|
||||||
|
progress int64 // number of bytes uploaded so far
|
||||||
|
|
||||||
|
// Callback is an optional function that will be periodically called with the cumulative number of bytes uploaded.
|
||||||
|
Callback func(int64)
|
||||||
|
|
||||||
|
// If not specified, a default exponential backoff strategy will be used.
|
||||||
|
Backoff BackoffStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
// Progress returns the number of bytes uploaded at this point.
|
||||||
|
func (rx *ResumableUpload) Progress() int64 {
|
||||||
|
rx.mu.Lock()
|
||||||
|
defer rx.mu.Unlock()
|
||||||
|
return rx.progress
|
||||||
|
}
|
||||||
|
|
||||||
|
// doUploadRequest performs a single HTTP request to upload data.
|
||||||
|
// off specifies the offset in rx.Media from which data is drawn.
|
||||||
|
// size is the number of bytes in data.
|
||||||
|
// final specifies whether data is the final chunk to be uploaded.
|
||||||
|
func (rx *ResumableUpload) doUploadRequest(ctx context.Context, data io.Reader, off, size int64, final bool) (*http.Response, error) {
|
||||||
|
req, err := http.NewRequest("POST", rx.URI, data)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
req.ContentLength = size
|
||||||
|
var contentRange string
|
||||||
|
if final {
|
||||||
|
if size == 0 {
|
||||||
|
contentRange = fmt.Sprintf("bytes */%v", off)
|
||||||
|
} else {
|
||||||
|
contentRange = fmt.Sprintf("bytes %v-%v/%v", off, off+size-1, off+size)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
contentRange = fmt.Sprintf("bytes %v-%v/*", off, off+size-1)
|
||||||
|
}
|
||||||
|
req.Header.Set("Content-Range", contentRange)
|
||||||
|
req.Header.Set("Content-Type", rx.MediaType)
|
||||||
|
req.Header.Set("User-Agent", rx.UserAgent)
|
||||||
|
return ctxhttp.Do(ctx, rx.Client, req)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// reportProgress calls a user-supplied callback to report upload progress.
|
||||||
|
// If old==updated, the callback is not called.
|
||||||
|
func (rx *ResumableUpload) reportProgress(old, updated int64) {
|
||||||
|
if updated-old == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
rx.mu.Lock()
|
||||||
|
rx.progress = updated
|
||||||
|
rx.mu.Unlock()
|
||||||
|
if rx.Callback != nil {
|
||||||
|
rx.Callback(updated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// transferChunk performs a single HTTP request to upload a single chunk from rx.Media.
|
||||||
|
func (rx *ResumableUpload) transferChunk(ctx context.Context) (*http.Response, error) {
|
||||||
|
chunk, off, size, err := rx.Media.Chunk()
|
||||||
|
|
||||||
|
done := err == io.EOF
|
||||||
|
if !done && err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := rx.doUploadRequest(ctx, chunk, off, int64(size), done)
|
||||||
|
if err != nil {
|
||||||
|
return res, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode == statusResumeIncomplete || res.StatusCode == http.StatusOK {
|
||||||
|
rx.reportProgress(off, off+int64(size))
|
||||||
|
}
|
||||||
|
|
||||||
|
if res.StatusCode == statusResumeIncomplete {
|
||||||
|
rx.Media.Next()
|
||||||
|
}
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func contextDone(ctx context.Context) bool {
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Upload starts the process of a resumable upload with a cancellable context.
|
||||||
|
// It retries using the provided back off strategy until cancelled or the
|
||||||
|
// strategy indicates to stop retrying.
|
||||||
|
// It is called from the auto-generated API code and is not visible to the user.
|
||||||
|
// rx is private to the auto-generated API code.
|
||||||
|
// Exactly one of resp or err will be nil. If resp is non-nil, the caller must call resp.Body.Close.
|
||||||
|
func (rx *ResumableUpload) Upload(ctx context.Context) (resp *http.Response, err error) {
|
||||||
|
var pause time.Duration
|
||||||
|
backoff := rx.Backoff
|
||||||
|
if backoff == nil {
|
||||||
|
backoff = DefaultBackoffStrategy()
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
// Ensure that we return in the case of cancelled context, even if pause is 0.
|
||||||
|
if contextDone(ctx) {
|
||||||
|
return nil, ctx.Err()
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-time.After(pause):
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = rx.transferChunk(ctx)
|
||||||
|
|
||||||
|
var status int
|
||||||
|
if resp != nil {
|
||||||
|
status = resp.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we should retry the request.
|
||||||
|
if shouldRetry(status, err) {
|
||||||
|
var retry bool
|
||||||
|
pause, retry = backoff.Pause()
|
||||||
|
if retry {
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the chunk was uploaded successfully, but there's still
|
||||||
|
// more to go, upload the next chunk without any delay.
|
||||||
|
if status == statusResumeIncomplete {
|
||||||
|
pause = 0
|
||||||
|
backoff.Reset()
|
||||||
|
resp.Body.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// It's possible for err and resp to both be non-nil here, but we expose a simpler
|
||||||
|
// contract to our callers: exactly one of resp and err will be non-nil. This means
|
||||||
|
// that any response body must be closed here before returning a non-nil error.
|
||||||
|
if err != nil {
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
}
|
77
vendor/google.golang.org/api/gensupport/retry.go
generated
vendored
Normal file
77
vendor/google.golang.org/api/gensupport/retry.go
generated
vendored
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
package gensupport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"io"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Retry invokes the given function, retrying it multiple times if the connection failed or
|
||||||
|
// the HTTP status response indicates the request should be attempted again. ctx may be nil.
|
||||||
|
func Retry(ctx context.Context, f func() (*http.Response, error), backoff BackoffStrategy) (*http.Response, error) {
|
||||||
|
for {
|
||||||
|
resp, err := f()
|
||||||
|
|
||||||
|
var status int
|
||||||
|
if resp != nil {
|
||||||
|
status = resp.StatusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if we shouldn't retry.
|
||||||
|
pause, retry := backoff.Pause()
|
||||||
|
if !shouldRetry(status, err) || !retry {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure the response body is closed, if any.
|
||||||
|
if resp != nil && resp.Body != nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pause, but still listen to ctx.Done if context is not nil.
|
||||||
|
var done <-chan struct{}
|
||||||
|
if ctx != nil {
|
||||||
|
done = ctx.Done()
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case <-done:
|
||||||
|
return nil, ctx.Err()
|
||||||
|
case <-time.After(pause):
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultBackoffStrategy returns a default strategy to use for retrying failed upload requests.
|
||||||
|
func DefaultBackoffStrategy() BackoffStrategy {
|
||||||
|
return &ExponentialBackoff{
|
||||||
|
Base: 250 * time.Millisecond,
|
||||||
|
Max: 16 * time.Second,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// shouldRetry returns true if the HTTP response / error indicates that the
|
||||||
|
// request should be attempted again.
|
||||||
|
func shouldRetry(status int, err error) bool {
|
||||||
|
// Retry for 5xx response codes.
|
||||||
|
if 500 <= status && status < 600 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry on statusTooManyRequests{
|
||||||
|
if status == statusTooManyRequests {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retry on unexpected EOFs and temporary network errors.
|
||||||
|
if err == io.ErrUnexpectedEOF {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
if err, ok := err.(net.Error); ok {
|
||||||
|
return err.Temporary()
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
383
vendor/google.golang.org/api/googleapi/googleapi.go
generated
vendored
383
vendor/google.golang.org/api/googleapi/googleapi.go
generated
vendored
|
@ -9,21 +9,13 @@ package googleapi
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"mime/multipart"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/textproto"
|
|
||||||
"net/url"
|
"net/url"
|
||||||
"regexp"
|
|
||||||
"strconv"
|
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
|
||||||
"google.golang.org/api/googleapi/internal/uritemplates"
|
"google.golang.org/api/googleapi/internal/uritemplates"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -42,17 +34,28 @@ type SizeReaderAt interface {
|
||||||
Size() int64
|
Size() int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ServerResponse is embedded in each Do response and
|
||||||
|
// provides the HTTP status code and header sent by the server.
|
||||||
|
type ServerResponse struct {
|
||||||
|
// HTTPStatusCode is the server's response status code.
|
||||||
|
// When using a resource method's Do call, this will always be in the 2xx range.
|
||||||
|
HTTPStatusCode int
|
||||||
|
// Header contains the response header fields from the server.
|
||||||
|
Header http.Header
|
||||||
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
Version = "0.5"
|
Version = "0.5"
|
||||||
|
|
||||||
// statusResumeIncomplete is the code returned by the Google uploader when the transfer is not yet complete.
|
|
||||||
statusResumeIncomplete = 308
|
|
||||||
|
|
||||||
// UserAgent is the header string used to identify this package.
|
// UserAgent is the header string used to identify this package.
|
||||||
UserAgent = "google-api-go-client/" + Version
|
UserAgent = "google-api-go-client/" + Version
|
||||||
|
|
||||||
// uploadPause determines the delay between failed upload attempts
|
// The default chunk size to use for resumable uplods if not specified by the user.
|
||||||
uploadPause = 1 * time.Second
|
DefaultUploadChunkSize = 8 * 1024 * 1024
|
||||||
|
|
||||||
|
// The minimum chunk size that can be used for resumable uploads. All
|
||||||
|
// user-specified chunk sizes must be multiple of this value.
|
||||||
|
MinUploadChunkSize = 256 * 1024
|
||||||
)
|
)
|
||||||
|
|
||||||
// Error contains an error response from the server.
|
// Error contains an error response from the server.
|
||||||
|
@ -65,6 +68,8 @@ type Error struct {
|
||||||
// Body is the raw response returned by the server.
|
// Body is the raw response returned by the server.
|
||||||
// It is often but not always JSON, depending on how the request fails.
|
// It is often but not always JSON, depending on how the request fails.
|
||||||
Body string
|
Body string
|
||||||
|
// Header contains the response header fields from the server.
|
||||||
|
Header http.Header
|
||||||
|
|
||||||
Errors []ErrorItem
|
Errors []ErrorItem
|
||||||
}
|
}
|
||||||
|
@ -122,6 +127,34 @@ func CheckResponse(res *http.Response) error {
|
||||||
return jerr.Error
|
return jerr.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return &Error{
|
||||||
|
Code: res.StatusCode,
|
||||||
|
Body: string(slurp),
|
||||||
|
Header: res.Header,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// IsNotModified reports whether err is the result of the
|
||||||
|
// server replying with http.StatusNotModified.
|
||||||
|
// Such error values are sometimes returned by "Do" methods
|
||||||
|
// on calls when If-None-Match is used.
|
||||||
|
func IsNotModified(err error) bool {
|
||||||
|
if err == nil {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
ae, ok := err.(*Error)
|
||||||
|
return ok && ae.Code == http.StatusNotModified
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckMediaResponse returns an error (of type *Error) if the response
|
||||||
|
// status code is not 2xx. Unlike CheckResponse it does not assume the
|
||||||
|
// body is a JSON error document.
|
||||||
|
func CheckMediaResponse(res *http.Response) error {
|
||||||
|
if res.StatusCode >= 200 && res.StatusCode <= 299 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
slurp, _ := ioutil.ReadAll(io.LimitReader(res.Body, 1<<20))
|
||||||
|
res.Body.Close()
|
||||||
return &Error{
|
return &Error{
|
||||||
Code: res.StatusCode,
|
Code: res.StatusCode,
|
||||||
Body: string(slurp),
|
Body: string(slurp),
|
||||||
|
@ -148,52 +181,6 @@ func (wrap MarshalStyle) JSONReader(v interface{}) (io.Reader, error) {
|
||||||
return buf, nil
|
return buf, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMediaType(media io.Reader) (io.Reader, string) {
|
|
||||||
if typer, ok := media.(ContentTyper); ok {
|
|
||||||
return media, typer.ContentType()
|
|
||||||
}
|
|
||||||
|
|
||||||
pr, pw := io.Pipe()
|
|
||||||
typ := "application/octet-stream"
|
|
||||||
buf, err := ioutil.ReadAll(io.LimitReader(media, 512))
|
|
||||||
if err != nil {
|
|
||||||
pw.CloseWithError(fmt.Errorf("error reading media: %v", err))
|
|
||||||
return pr, typ
|
|
||||||
}
|
|
||||||
typ = http.DetectContentType(buf)
|
|
||||||
mr := io.MultiReader(bytes.NewReader(buf), media)
|
|
||||||
go func() {
|
|
||||||
_, err = io.Copy(pw, mr)
|
|
||||||
if err != nil {
|
|
||||||
pw.CloseWithError(fmt.Errorf("error reading media: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
pw.Close()
|
|
||||||
}()
|
|
||||||
return pr, typ
|
|
||||||
}
|
|
||||||
|
|
||||||
// DetectMediaType detects and returns the content type of the provided media.
|
|
||||||
// If the type can not be determined, "application/octet-stream" is returned.
|
|
||||||
func DetectMediaType(media io.ReaderAt) string {
|
|
||||||
if typer, ok := media.(ContentTyper); ok {
|
|
||||||
return typer.ContentType()
|
|
||||||
}
|
|
||||||
|
|
||||||
typ := "application/octet-stream"
|
|
||||||
buf := make([]byte, 1024)
|
|
||||||
n, err := media.ReadAt(buf, 0)
|
|
||||||
buf = buf[:n]
|
|
||||||
if err == nil || err == io.EOF {
|
|
||||||
typ = http.DetectContentType(buf)
|
|
||||||
}
|
|
||||||
return typ
|
|
||||||
}
|
|
||||||
|
|
||||||
type Lengther interface {
|
|
||||||
Len() int
|
|
||||||
}
|
|
||||||
|
|
||||||
// endingWithErrorReader from r until it returns an error. If the
|
// endingWithErrorReader from r until it returns an error. If the
|
||||||
// final error from r is io.EOF and e is non-nil, e is used instead.
|
// final error from r is io.EOF and e is non-nil, e is used instead.
|
||||||
type endingWithErrorReader struct {
|
type endingWithErrorReader struct {
|
||||||
|
@ -209,12 +196,6 @@ func (er endingWithErrorReader) Read(p []byte) (n int, err error) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func typeHeader(contentType string) textproto.MIMEHeader {
|
|
||||||
h := make(textproto.MIMEHeader)
|
|
||||||
h.Set("Content-Type", contentType)
|
|
||||||
return h
|
|
||||||
}
|
|
||||||
|
|
||||||
// countingWriter counts the number of bytes it receives to write, but
|
// countingWriter counts the number of bytes it receives to write, but
|
||||||
// discards them.
|
// discards them.
|
||||||
type countingWriter struct {
|
type countingWriter struct {
|
||||||
|
@ -226,203 +207,65 @@ func (w countingWriter) Write(p []byte) (int, error) {
|
||||||
return len(p), nil
|
return len(p), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ConditionallyIncludeMedia does nothing if media is nil.
|
|
||||||
//
|
|
||||||
// bodyp is an in/out parameter. It should initially point to the
|
|
||||||
// reader of the application/json (or whatever) payload to send in the
|
|
||||||
// API request. It's updated to point to the multipart body reader.
|
|
||||||
//
|
|
||||||
// ctypep is an in/out parameter. It should initially point to the
|
|
||||||
// content type of the bodyp, usually "application/json". It's updated
|
|
||||||
// to the "multipart/related" content type, with random boundary.
|
|
||||||
//
|
|
||||||
// The return value is the content-length of the entire multpart body.
|
|
||||||
func ConditionallyIncludeMedia(media io.Reader, bodyp *io.Reader, ctypep *string) (cancel func(), ok bool) {
|
|
||||||
if media == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
// Get the media type, which might return a different reader instance.
|
|
||||||
var mediaType string
|
|
||||||
media, mediaType = getMediaType(media)
|
|
||||||
|
|
||||||
body, bodyType := *bodyp, *ctypep
|
|
||||||
|
|
||||||
pr, pw := io.Pipe()
|
|
||||||
mpw := multipart.NewWriter(pw)
|
|
||||||
*bodyp = pr
|
|
||||||
*ctypep = "multipart/related; boundary=" + mpw.Boundary()
|
|
||||||
go func() {
|
|
||||||
w, err := mpw.CreatePart(typeHeader(bodyType))
|
|
||||||
if err != nil {
|
|
||||||
mpw.Close()
|
|
||||||
pw.CloseWithError(fmt.Errorf("googleapi: body CreatePart failed: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = io.Copy(w, body)
|
|
||||||
if err != nil {
|
|
||||||
mpw.Close()
|
|
||||||
pw.CloseWithError(fmt.Errorf("googleapi: body Copy failed: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
w, err = mpw.CreatePart(typeHeader(mediaType))
|
|
||||||
if err != nil {
|
|
||||||
mpw.Close()
|
|
||||||
pw.CloseWithError(fmt.Errorf("googleapi: media CreatePart failed: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
_, err = io.Copy(w, media)
|
|
||||||
if err != nil {
|
|
||||||
mpw.Close()
|
|
||||||
pw.CloseWithError(fmt.Errorf("googleapi: media Copy failed: %v", err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
mpw.Close()
|
|
||||||
pw.Close()
|
|
||||||
}()
|
|
||||||
cancel = func() { pw.CloseWithError(errAborted) }
|
|
||||||
return cancel, true
|
|
||||||
}
|
|
||||||
|
|
||||||
var errAborted = errors.New("googleapi: upload aborted")
|
|
||||||
|
|
||||||
// ProgressUpdater is a function that is called upon every progress update of a resumable upload.
|
// ProgressUpdater is a function that is called upon every progress update of a resumable upload.
|
||||||
// This is the only part of a resumable upload (from googleapi) that is usable by the developer.
|
// This is the only part of a resumable upload (from googleapi) that is usable by the developer.
|
||||||
// The remaining usable pieces of resumable uploads is exposed in each auto-generated API.
|
// The remaining usable pieces of resumable uploads is exposed in each auto-generated API.
|
||||||
type ProgressUpdater func(current, total int64)
|
type ProgressUpdater func(current, total int64)
|
||||||
|
|
||||||
// ResumableUpload is used by the generated APIs to provide resumable uploads.
|
type MediaOption interface {
|
||||||
|
setOptions(o *MediaOptions)
|
||||||
|
}
|
||||||
|
|
||||||
|
type contentTypeOption string
|
||||||
|
|
||||||
|
func (ct contentTypeOption) setOptions(o *MediaOptions) {
|
||||||
|
o.ContentType = string(ct)
|
||||||
|
if o.ContentType == "" {
|
||||||
|
o.ForceEmptyContentType = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContentType returns a MediaOption which sets the Content-Type header for media uploads.
|
||||||
|
// If ctype is empty, the Content-Type header will be omitted.
|
||||||
|
func ContentType(ctype string) MediaOption {
|
||||||
|
return contentTypeOption(ctype)
|
||||||
|
}
|
||||||
|
|
||||||
|
type chunkSizeOption int
|
||||||
|
|
||||||
|
func (cs chunkSizeOption) setOptions(o *MediaOptions) {
|
||||||
|
size := int(cs)
|
||||||
|
if size%MinUploadChunkSize != 0 {
|
||||||
|
size += MinUploadChunkSize - (size % MinUploadChunkSize)
|
||||||
|
}
|
||||||
|
o.ChunkSize = size
|
||||||
|
}
|
||||||
|
|
||||||
|
// ChunkSize returns a MediaOption which sets the chunk size for media uploads.
|
||||||
|
// size will be rounded up to the nearest multiple of 256K.
|
||||||
|
// Media which contains fewer than size bytes will be uploaded in a single request.
|
||||||
|
// Media which contains size bytes or more will be uploaded in separate chunks.
|
||||||
|
// If size is zero, media will be uploaded in a single request.
|
||||||
|
func ChunkSize(size int) MediaOption {
|
||||||
|
return chunkSizeOption(size)
|
||||||
|
}
|
||||||
|
|
||||||
|
// MediaOptions stores options for customizing media upload. It is not used by developers directly.
|
||||||
|
type MediaOptions struct {
|
||||||
|
ContentType string
|
||||||
|
ForceEmptyContentType bool
|
||||||
|
|
||||||
|
ChunkSize int
|
||||||
|
}
|
||||||
|
|
||||||
|
// ProcessMediaOptions stores options from opts in a MediaOptions.
|
||||||
// It is not used by developers directly.
|
// It is not used by developers directly.
|
||||||
type ResumableUpload struct {
|
func ProcessMediaOptions(opts []MediaOption) *MediaOptions {
|
||||||
Client *http.Client
|
mo := &MediaOptions{ChunkSize: DefaultUploadChunkSize}
|
||||||
// URI is the resumable resource destination provided by the server after specifying "&uploadType=resumable".
|
for _, o := range opts {
|
||||||
URI string
|
o.setOptions(mo)
|
||||||
UserAgent string // User-Agent for header of the request
|
|
||||||
// Media is the object being uploaded.
|
|
||||||
Media io.ReaderAt
|
|
||||||
// MediaType defines the media type, e.g. "image/jpeg".
|
|
||||||
MediaType string
|
|
||||||
// ContentLength is the full size of the object being uploaded.
|
|
||||||
ContentLength int64
|
|
||||||
|
|
||||||
mu sync.Mutex // guards progress
|
|
||||||
progress int64 // number of bytes uploaded so far
|
|
||||||
started bool // whether the upload has been started
|
|
||||||
|
|
||||||
// Callback is an optional function that will be called upon every progress update.
|
|
||||||
Callback ProgressUpdater
|
|
||||||
}
|
|
||||||
|
|
||||||
var (
|
|
||||||
// rangeRE matches the transfer status response from the server. $1 is the last byte index uploaded.
|
|
||||||
rangeRE = regexp.MustCompile(`^bytes=0\-(\d+)$`)
|
|
||||||
// chunkSize is the size of the chunks created during a resumable upload and should be a power of two.
|
|
||||||
// 1<<18 is the minimum size supported by the Google uploader, and there is no maximum.
|
|
||||||
chunkSize int64 = 1 << 18
|
|
||||||
)
|
|
||||||
|
|
||||||
// Progress returns the number of bytes uploaded at this point.
|
|
||||||
func (rx *ResumableUpload) Progress() int64 {
|
|
||||||
rx.mu.Lock()
|
|
||||||
defer rx.mu.Unlock()
|
|
||||||
return rx.progress
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rx *ResumableUpload) transferStatus() (int64, *http.Response, error) {
|
|
||||||
req, _ := http.NewRequest("POST", rx.URI, nil)
|
|
||||||
req.ContentLength = 0
|
|
||||||
req.Header.Set("User-Agent", rx.UserAgent)
|
|
||||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes */%v", rx.ContentLength))
|
|
||||||
res, err := rx.Client.Do(req)
|
|
||||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
|
||||||
return 0, res, err
|
|
||||||
}
|
}
|
||||||
var start int64
|
return mo
|
||||||
if m := rangeRE.FindStringSubmatch(res.Header.Get("Range")); len(m) == 2 {
|
|
||||||
start, err = strconv.ParseInt(m[1], 10, 64)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, fmt.Errorf("unable to parse range size %v", m[1])
|
|
||||||
}
|
|
||||||
start += 1 // Start at the next byte
|
|
||||||
}
|
|
||||||
return start, res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type chunk struct {
|
|
||||||
body io.Reader
|
|
||||||
size int64
|
|
||||||
err error
|
|
||||||
}
|
|
||||||
|
|
||||||
func (rx *ResumableUpload) transferChunks(ctx context.Context) (*http.Response, error) {
|
|
||||||
var start int64
|
|
||||||
var err error
|
|
||||||
res := &http.Response{}
|
|
||||||
if rx.started {
|
|
||||||
start, res, err = rx.transferStatus()
|
|
||||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rx.started = true
|
|
||||||
|
|
||||||
for {
|
|
||||||
select { // Check for cancellation
|
|
||||||
case <-ctx.Done():
|
|
||||||
res.StatusCode = http.StatusRequestTimeout
|
|
||||||
return res, ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
reqSize := rx.ContentLength - start
|
|
||||||
if reqSize > chunkSize {
|
|
||||||
reqSize = chunkSize
|
|
||||||
}
|
|
||||||
r := io.NewSectionReader(rx.Media, start, reqSize)
|
|
||||||
req, _ := http.NewRequest("POST", rx.URI, r)
|
|
||||||
req.ContentLength = reqSize
|
|
||||||
req.Header.Set("Content-Range", fmt.Sprintf("bytes %v-%v/%v", start, start+reqSize-1, rx.ContentLength))
|
|
||||||
req.Header.Set("Content-Type", rx.MediaType)
|
|
||||||
req.Header.Set("User-Agent", rx.UserAgent)
|
|
||||||
res, err = rx.Client.Do(req)
|
|
||||||
start += reqSize
|
|
||||||
if err == nil && (res.StatusCode == statusResumeIncomplete || res.StatusCode == http.StatusOK) {
|
|
||||||
rx.mu.Lock()
|
|
||||||
rx.progress = start // keep track of number of bytes sent so far
|
|
||||||
rx.mu.Unlock()
|
|
||||||
if rx.Callback != nil {
|
|
||||||
rx.Callback(start, rx.ContentLength)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if err != nil || res.StatusCode != statusResumeIncomplete {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
|
|
||||||
var sleep = time.Sleep // override in unit tests
|
|
||||||
|
|
||||||
// Upload starts the process of a resumable upload with a cancellable context.
|
|
||||||
// It retries indefinitely (with a pause of uploadPause between attempts) until cancelled.
|
|
||||||
// It is called from the auto-generated API code and is not visible to the user.
|
|
||||||
// rx is private to the auto-generated API code.
|
|
||||||
func (rx *ResumableUpload) Upload(ctx context.Context) (*http.Response, error) {
|
|
||||||
var res *http.Response
|
|
||||||
var err error
|
|
||||||
for {
|
|
||||||
res, err = rx.transferChunks(ctx)
|
|
||||||
if err != nil || res.StatusCode == http.StatusCreated || res.StatusCode == http.StatusOK {
|
|
||||||
return res, err
|
|
||||||
}
|
|
||||||
select { // Check for cancellation
|
|
||||||
case <-ctx.Done():
|
|
||||||
res.StatusCode = http.StatusRequestTimeout
|
|
||||||
return res, ctx.Err()
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
sleep(uploadPause)
|
|
||||||
}
|
|
||||||
return res, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ResolveRelative(basestr, relstr string) string {
|
func ResolveRelative(basestr, relstr string) string {
|
||||||
|
@ -549,3 +392,33 @@ func CombineFields(s []Field) string {
|
||||||
}
|
}
|
||||||
return strings.Join(r, ",")
|
return strings.Join(r, ",")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A CallOption is an optional argument to an API call.
|
||||||
|
// It should be treated as an opaque value by users of Google APIs.
|
||||||
|
//
|
||||||
|
// A CallOption is something that configures an API call in a way that is
|
||||||
|
// not specific to that API; for instance, controlling the quota user for
|
||||||
|
// an API call is common across many APIs, and is thus a CallOption.
|
||||||
|
type CallOption interface {
|
||||||
|
Get() (key, value string)
|
||||||
|
}
|
||||||
|
|
||||||
|
// QuotaUser returns a CallOption that will set the quota user for a call.
|
||||||
|
// The quota user can be used by server-side applications to control accounting.
|
||||||
|
// It can be an arbitrary string up to 40 characters, and will override UserIP
|
||||||
|
// if both are provided.
|
||||||
|
func QuotaUser(u string) CallOption { return quotaUser(u) }
|
||||||
|
|
||||||
|
type quotaUser string
|
||||||
|
|
||||||
|
func (q quotaUser) Get() (string, string) { return "quotaUser", string(q) }
|
||||||
|
|
||||||
|
// UserIP returns a CallOption that will set the "userIp" parameter of a call.
|
||||||
|
// This should be the IP address of the originating request.
|
||||||
|
func UserIP(ip string) CallOption { return userIP(ip) }
|
||||||
|
|
||||||
|
type userIP string
|
||||||
|
|
||||||
|
func (i userIP) Get() (string, string) { return "userIp", string(i) }
|
||||||
|
|
||||||
|
// TODO: Fields too
|
||||||
|
|
247
vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates.go
generated
vendored
247
vendor/google.golang.org/api/googleapi/internal/uritemplates/uritemplates.go
generated
vendored
|
@ -2,26 +2,15 @@
|
||||||
// Use of this source code is governed by a BSD-style
|
// Use of this source code is governed by a BSD-style
|
||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
// Package uritemplates is a level 4 implementation of RFC 6570 (URI
|
// Package uritemplates is a level 3 implementation of RFC 6570 (URI
|
||||||
// Template, http://tools.ietf.org/html/rfc6570).
|
// Template, http://tools.ietf.org/html/rfc6570).
|
||||||
//
|
// uritemplates does not support composite values (in Go: slices or maps)
|
||||||
// To use uritemplates, parse a template string and expand it with a value
|
// and so does not qualify as a level 4 implementation.
|
||||||
// map:
|
|
||||||
//
|
|
||||||
// template, _ := uritemplates.Parse("https://api.github.com/repos{/user,repo}")
|
|
||||||
// values := make(map[string]interface{})
|
|
||||||
// values["user"] = "jtacoma"
|
|
||||||
// values["repo"] = "uritemplates"
|
|
||||||
// expanded, _ := template.ExpandString(values)
|
|
||||||
// fmt.Printf(expanded)
|
|
||||||
//
|
|
||||||
package uritemplates
|
package uritemplates
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
@ -45,52 +34,47 @@ func pctEncode(src []byte) []byte {
|
||||||
return dst
|
return dst
|
||||||
}
|
}
|
||||||
|
|
||||||
func escape(s string, allowReserved bool) (escaped string) {
|
func escape(s string, allowReserved bool) string {
|
||||||
if allowReserved {
|
if allowReserved {
|
||||||
escaped = string(reserved.ReplaceAllFunc([]byte(s), pctEncode))
|
return string(reserved.ReplaceAllFunc([]byte(s), pctEncode))
|
||||||
} else {
|
|
||||||
escaped = string(unreserved.ReplaceAllFunc([]byte(s), pctEncode))
|
|
||||||
}
|
}
|
||||||
return escaped
|
return string(unreserved.ReplaceAllFunc([]byte(s), pctEncode))
|
||||||
}
|
}
|
||||||
|
|
||||||
// A UriTemplate is a parsed representation of a URI template.
|
// A uriTemplate is a parsed representation of a URI template.
|
||||||
type UriTemplate struct {
|
type uriTemplate struct {
|
||||||
raw string
|
raw string
|
||||||
parts []templatePart
|
parts []templatePart
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse parses a URI template string into a UriTemplate object.
|
// parse parses a URI template string into a uriTemplate object.
|
||||||
func Parse(rawtemplate string) (template *UriTemplate, err error) {
|
func parse(rawTemplate string) (*uriTemplate, error) {
|
||||||
template = new(UriTemplate)
|
split := strings.Split(rawTemplate, "{")
|
||||||
template.raw = rawtemplate
|
parts := make([]templatePart, len(split)*2-1)
|
||||||
split := strings.Split(rawtemplate, "{")
|
|
||||||
template.parts = make([]templatePart, len(split)*2-1)
|
|
||||||
for i, s := range split {
|
for i, s := range split {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
if strings.Contains(s, "}") {
|
if strings.Contains(s, "}") {
|
||||||
err = errors.New("unexpected }")
|
return nil, errors.New("unexpected }")
|
||||||
break
|
|
||||||
}
|
}
|
||||||
template.parts[i].raw = s
|
parts[i].raw = s
|
||||||
} else {
|
continue
|
||||||
subsplit := strings.Split(s, "}")
|
|
||||||
if len(subsplit) != 2 {
|
|
||||||
err = errors.New("malformed template")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
expression := subsplit[0]
|
|
||||||
template.parts[i*2-1], err = parseExpression(expression)
|
|
||||||
if err != nil {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
template.parts[i*2].raw = subsplit[1]
|
|
||||||
}
|
}
|
||||||
|
subsplit := strings.Split(s, "}")
|
||||||
|
if len(subsplit) != 2 {
|
||||||
|
return nil, errors.New("malformed template")
|
||||||
|
}
|
||||||
|
expression := subsplit[0]
|
||||||
|
var err error
|
||||||
|
parts[i*2-1], err = parseExpression(expression)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
parts[i*2].raw = subsplit[1]
|
||||||
}
|
}
|
||||||
if err != nil {
|
return &uriTemplate{
|
||||||
template = nil
|
raw: rawTemplate,
|
||||||
}
|
parts: parts,
|
||||||
return template, err
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type templatePart struct {
|
type templatePart struct {
|
||||||
|
@ -160,6 +144,8 @@ func parseExpression(expression string) (result templatePart, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseTerm(term string) (result templateTerm, err error) {
|
func parseTerm(term string) (result templateTerm, err error) {
|
||||||
|
// TODO(djd): Remove "*" suffix parsing once we check that no APIs have
|
||||||
|
// mistakenly used that attribute.
|
||||||
if strings.HasSuffix(term, "*") {
|
if strings.HasSuffix(term, "*") {
|
||||||
result.explode = true
|
result.explode = true
|
||||||
term = term[:len(term)-1]
|
term = term[:len(term)-1]
|
||||||
|
@ -185,175 +171,50 @@ func parseTerm(term string) (result templateTerm, err error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Expand expands a URI template with a set of values to produce a string.
|
// Expand expands a URI template with a set of values to produce a string.
|
||||||
func (self *UriTemplate) Expand(value interface{}) (string, error) {
|
func (t *uriTemplate) Expand(values map[string]string) string {
|
||||||
values, ismap := value.(map[string]interface{})
|
|
||||||
if !ismap {
|
|
||||||
if m, ismap := struct2map(value); !ismap {
|
|
||||||
return "", errors.New("expected map[string]interface{}, struct, or pointer to struct.")
|
|
||||||
} else {
|
|
||||||
return self.Expand(m)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
for _, p := range self.parts {
|
for _, p := range t.parts {
|
||||||
err := p.expand(&buf, values)
|
p.expand(&buf, values)
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return buf.String(), nil
|
return buf.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templatePart) expand(buf *bytes.Buffer, values map[string]interface{}) error {
|
func (tp *templatePart) expand(buf *bytes.Buffer, values map[string]string) {
|
||||||
if len(self.raw) > 0 {
|
if len(tp.raw) > 0 {
|
||||||
buf.WriteString(self.raw)
|
buf.WriteString(tp.raw)
|
||||||
return nil
|
return
|
||||||
}
|
}
|
||||||
var zeroLen = buf.Len()
|
var first = true
|
||||||
buf.WriteString(self.first)
|
for _, term := range tp.terms {
|
||||||
var firstLen = buf.Len()
|
|
||||||
for _, term := range self.terms {
|
|
||||||
value, exists := values[term.name]
|
value, exists := values[term.name]
|
||||||
if !exists {
|
if !exists {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if buf.Len() != firstLen {
|
if first {
|
||||||
buf.WriteString(self.sep)
|
buf.WriteString(tp.first)
|
||||||
}
|
first = false
|
||||||
switch v := value.(type) {
|
} else {
|
||||||
case string:
|
buf.WriteString(tp.sep)
|
||||||
self.expandString(buf, term, v)
|
|
||||||
case []interface{}:
|
|
||||||
self.expandArray(buf, term, v)
|
|
||||||
case map[string]interface{}:
|
|
||||||
if term.truncate > 0 {
|
|
||||||
return errors.New("cannot truncate a map expansion")
|
|
||||||
}
|
|
||||||
self.expandMap(buf, term, v)
|
|
||||||
default:
|
|
||||||
if m, ismap := struct2map(value); ismap {
|
|
||||||
if term.truncate > 0 {
|
|
||||||
return errors.New("cannot truncate a map expansion")
|
|
||||||
}
|
|
||||||
self.expandMap(buf, term, m)
|
|
||||||
} else {
|
|
||||||
str := fmt.Sprintf("%v", value)
|
|
||||||
self.expandString(buf, term, str)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
tp.expandString(buf, term, value)
|
||||||
}
|
}
|
||||||
if buf.Len() == firstLen {
|
|
||||||
original := buf.Bytes()[:zeroLen]
|
|
||||||
buf.Reset()
|
|
||||||
buf.Write(original)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templatePart) expandName(buf *bytes.Buffer, name string, empty bool) {
|
func (tp *templatePart) expandName(buf *bytes.Buffer, name string, empty bool) {
|
||||||
if self.named {
|
if tp.named {
|
||||||
buf.WriteString(name)
|
buf.WriteString(name)
|
||||||
if empty {
|
if empty {
|
||||||
buf.WriteString(self.ifemp)
|
buf.WriteString(tp.ifemp)
|
||||||
} else {
|
} else {
|
||||||
buf.WriteString("=")
|
buf.WriteString("=")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *templatePart) expandString(buf *bytes.Buffer, t templateTerm, s string) {
|
func (tp *templatePart) expandString(buf *bytes.Buffer, t templateTerm, s string) {
|
||||||
if len(s) > t.truncate && t.truncate > 0 {
|
if len(s) > t.truncate && t.truncate > 0 {
|
||||||
s = s[:t.truncate]
|
s = s[:t.truncate]
|
||||||
}
|
}
|
||||||
self.expandName(buf, t.name, len(s) == 0)
|
tp.expandName(buf, t.name, len(s) == 0)
|
||||||
buf.WriteString(escape(s, self.allowReserved))
|
buf.WriteString(escape(s, tp.allowReserved))
|
||||||
}
|
|
||||||
|
|
||||||
func (self *templatePart) expandArray(buf *bytes.Buffer, t templateTerm, a []interface{}) {
|
|
||||||
if len(a) == 0 {
|
|
||||||
return
|
|
||||||
} else if !t.explode {
|
|
||||||
self.expandName(buf, t.name, false)
|
|
||||||
}
|
|
||||||
for i, value := range a {
|
|
||||||
if t.explode && i > 0 {
|
|
||||||
buf.WriteString(self.sep)
|
|
||||||
} else if i > 0 {
|
|
||||||
buf.WriteString(",")
|
|
||||||
}
|
|
||||||
var s string
|
|
||||||
switch v := value.(type) {
|
|
||||||
case string:
|
|
||||||
s = v
|
|
||||||
default:
|
|
||||||
s = fmt.Sprintf("%v", v)
|
|
||||||
}
|
|
||||||
if len(s) > t.truncate && t.truncate > 0 {
|
|
||||||
s = s[:t.truncate]
|
|
||||||
}
|
|
||||||
if self.named && t.explode {
|
|
||||||
self.expandName(buf, t.name, len(s) == 0)
|
|
||||||
}
|
|
||||||
buf.WriteString(escape(s, self.allowReserved))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (self *templatePart) expandMap(buf *bytes.Buffer, t templateTerm, m map[string]interface{}) {
|
|
||||||
if len(m) == 0 {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if !t.explode {
|
|
||||||
self.expandName(buf, t.name, len(m) == 0)
|
|
||||||
}
|
|
||||||
var firstLen = buf.Len()
|
|
||||||
for k, value := range m {
|
|
||||||
if firstLen != buf.Len() {
|
|
||||||
if t.explode {
|
|
||||||
buf.WriteString(self.sep)
|
|
||||||
} else {
|
|
||||||
buf.WriteString(",")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var s string
|
|
||||||
switch v := value.(type) {
|
|
||||||
case string:
|
|
||||||
s = v
|
|
||||||
default:
|
|
||||||
s = fmt.Sprintf("%v", v)
|
|
||||||
}
|
|
||||||
if t.explode {
|
|
||||||
buf.WriteString(escape(k, self.allowReserved))
|
|
||||||
buf.WriteRune('=')
|
|
||||||
buf.WriteString(escape(s, self.allowReserved))
|
|
||||||
} else {
|
|
||||||
buf.WriteString(escape(k, self.allowReserved))
|
|
||||||
buf.WriteRune(',')
|
|
||||||
buf.WriteString(escape(s, self.allowReserved))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func struct2map(v interface{}) (map[string]interface{}, bool) {
|
|
||||||
value := reflect.ValueOf(v)
|
|
||||||
switch value.Type().Kind() {
|
|
||||||
case reflect.Ptr:
|
|
||||||
return struct2map(value.Elem().Interface())
|
|
||||||
case reflect.Struct:
|
|
||||||
m := make(map[string]interface{})
|
|
||||||
for i := 0; i < value.NumField(); i++ {
|
|
||||||
tag := value.Type().Field(i).Tag
|
|
||||||
var name string
|
|
||||||
if strings.Contains(string(tag), ":") {
|
|
||||||
name = tag.Get("uri")
|
|
||||||
} else {
|
|
||||||
name = strings.TrimSpace(string(tag))
|
|
||||||
}
|
|
||||||
if len(name) == 0 {
|
|
||||||
name = value.Type().Field(i).Name
|
|
||||||
}
|
|
||||||
m[name] = value.Field(i).Interface()
|
|
||||||
}
|
|
||||||
return m, true
|
|
||||||
}
|
|
||||||
return nil, false
|
|
||||||
}
|
}
|
||||||
|
|
14
vendor/google.golang.org/api/googleapi/internal/uritemplates/utils.go
generated
vendored
14
vendor/google.golang.org/api/googleapi/internal/uritemplates/utils.go
generated
vendored
|
@ -1,13 +1,13 @@
|
||||||
|
// Copyright 2016 The Go 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 uritemplates
|
package uritemplates
|
||||||
|
|
||||||
func Expand(path string, expansions map[string]string) (string, error) {
|
func Expand(path string, values map[string]string) (string, error) {
|
||||||
template, err := Parse(path)
|
template, err := parse(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
values := make(map[string]interface{})
|
return template.Expand(values), nil
|
||||||
for k, v := range expansions {
|
|
||||||
values[k] = v
|
|
||||||
}
|
|
||||||
return template.Expand(values)
|
|
||||||
}
|
}
|
||||||
|
|
32
vendor/google.golang.org/api/googleapi/types.go
generated
vendored
32
vendor/google.golang.org/api/googleapi/types.go
generated
vendored
|
@ -148,3 +148,35 @@ func (s Float64s) MarshalJSON() ([]byte, error) {
|
||||||
return strconv.AppendFloat(dst, s[i], 'g', -1, 64)
|
return strconv.AppendFloat(dst, s[i], 'g', -1, 64)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Helper routines for simplifying the creation of optional fields of basic type.
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Bool is a helper routine that allocates a new bool value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Bool(v bool) *bool { return &v }
|
||||||
|
|
||||||
|
// Int32 is a helper routine that allocates a new int32 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Int32(v int32) *int32 { return &v }
|
||||||
|
|
||||||
|
// Int64 is a helper routine that allocates a new int64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Int64(v int64) *int64 { return &v }
|
||||||
|
|
||||||
|
// Float64 is a helper routine that allocates a new float64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Float64(v float64) *float64 { return &v }
|
||||||
|
|
||||||
|
// Uint32 is a helper routine that allocates a new uint32 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Uint32(v uint32) *uint32 { return &v }
|
||||||
|
|
||||||
|
// Uint64 is a helper routine that allocates a new uint64 value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func Uint64(v uint64) *uint64 { return &v }
|
||||||
|
|
||||||
|
// String is a helper routine that allocates a new string value
|
||||||
|
// to store v and returns a pointer to it.
|
||||||
|
func String(v string) *string { return &v }
|
||||||
|
|
116
vendor/google.golang.org/api/storage/v1/storage-api.json
generated
vendored
116
vendor/google.golang.org/api/storage/v1/storage-api.json
generated
vendored
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"kind": "discovery#restDescription",
|
"kind": "discovery#restDescription",
|
||||||
"etag": "\"ye6orv2F-1npMW3u9suM3a7C5Bo/ALzt_o9hBNBIakQJmeXCNhSU8II\"",
|
"etag": "\"bRFOOrZKfO9LweMbPqu0kcu6De8/KVPQfwGxQTBtH0g1kuij0C9i4uc\"",
|
||||||
"discoveryVersion": "v1",
|
"discoveryVersion": "v1",
|
||||||
"id": "storage:v1",
|
"id": "storage:v1",
|
||||||
"name": "storage",
|
"name": "storage",
|
||||||
"version": "v1",
|
"version": "v1",
|
||||||
"revision": "20150630",
|
"revision": "20160304",
|
||||||
"title": "Cloud Storage API",
|
"title": "Cloud Storage JSON API",
|
||||||
"description": "Lets you store and retrieve potentially-large, immutable data objects.",
|
"description": "Stores and retrieves potentially large, immutable data objects.",
|
||||||
"ownerDomain": "google.com",
|
"ownerDomain": "google.com",
|
||||||
"ownerName": "Google",
|
"ownerName": "Google",
|
||||||
"icons": {
|
"icons": {
|
||||||
|
@ -75,6 +75,9 @@
|
||||||
"https://www.googleapis.com/auth/cloud-platform": {
|
"https://www.googleapis.com/auth/cloud-platform": {
|
||||||
"description": "View and manage your data across Google Cloud Platform services"
|
"description": "View and manage your data across Google Cloud Platform services"
|
||||||
},
|
},
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only": {
|
||||||
|
"description": "View your data across Google Cloud Platform services"
|
||||||
|
},
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control": {
|
"https://www.googleapis.com/auth/devstorage.full_control": {
|
||||||
"description": "Manage your data and permissions in Google Cloud Storage"
|
"description": "Manage your data and permissions in Google Cloud Storage"
|
||||||
},
|
},
|
||||||
|
@ -271,7 +274,12 @@
|
||||||
},
|
},
|
||||||
"timeCreated": {
|
"timeCreated": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Creation time of the bucket in RFC 3339 format.",
|
"description": "The creation time of the bucket in RFC 3339 format.",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
|
"updated": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The modification time of the bucket in RFC 3339 format.",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
},
|
},
|
||||||
"versioning": {
|
"versioning": {
|
||||||
|
@ -566,18 +574,26 @@
|
||||||
},
|
},
|
||||||
"contentType": {
|
"contentType": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Content-Type of the object data.",
|
"description": "Content-Type of the object data."
|
||||||
"annotations": {
|
|
||||||
"required": [
|
|
||||||
"storage.objects.insert",
|
|
||||||
"storage.objects.update"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"crc32c": {
|
"crc32c": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "CRC32c checksum, as described in RFC 4960, Appendix B; encoded using base64 in big-endian byte order. For more information about using the CRC32c checksum, see Hashes and ETags: Best Practices."
|
"description": "CRC32c checksum, as described in RFC 4960, Appendix B; encoded using base64 in big-endian byte order. For more information about using the CRC32c checksum, see Hashes and ETags: Best Practices."
|
||||||
},
|
},
|
||||||
|
"customerEncryption": {
|
||||||
|
"type": "object",
|
||||||
|
"description": "Metadata of customer-supplied encryption key, if the object is encrypted by such a key.",
|
||||||
|
"properties": {
|
||||||
|
"encryptionAlgorithm": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The encryption algorithm."
|
||||||
|
},
|
||||||
|
"keySha256": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "SHA256 hash value of the encryption key."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"etag": {
|
"etag": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "HTTP 1.1 Entity tag for the object."
|
"description": "HTTP 1.1 Entity tag for the object."
|
||||||
|
@ -648,6 +664,11 @@
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Storage class of the object."
|
"description": "Storage class of the object."
|
||||||
},
|
},
|
||||||
|
"timeCreated": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "The creation time of the object in RFC 3339 format.",
|
||||||
|
"format": "date-time"
|
||||||
|
},
|
||||||
"timeDeleted": {
|
"timeDeleted": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The deletion time of the object in RFC 3339 format. Will be returned if and only if this version of the object has been deleted.",
|
"description": "The deletion time of the object in RFC 3339 format. Will be returned if and only if this version of the object has been deleted.",
|
||||||
|
@ -655,7 +676,7 @@
|
||||||
},
|
},
|
||||||
"updated": {
|
"updated": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The creation or modification time of the object in RFC 3339 format. For buckets with versioning enabled, changing an object's metadata does not change this property.",
|
"description": "The modification time of the object metadata in RFC 3339 format.",
|
||||||
"format": "date-time"
|
"format": "date-time"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -842,6 +863,7 @@
|
||||||
"entity"
|
"entity"
|
||||||
],
|
],
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -872,6 +894,7 @@
|
||||||
"$ref": "BucketAccessControl"
|
"$ref": "BucketAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -898,6 +921,7 @@
|
||||||
"$ref": "BucketAccessControl"
|
"$ref": "BucketAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -921,6 +945,7 @@
|
||||||
"$ref": "BucketAccessControls"
|
"$ref": "BucketAccessControls"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -954,6 +979,7 @@
|
||||||
"$ref": "BucketAccessControl"
|
"$ref": "BucketAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -987,6 +1013,7 @@
|
||||||
"$ref": "BucketAccessControl"
|
"$ref": "BucketAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1074,6 +1101,7 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
|
@ -1211,6 +1239,7 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
|
@ -1417,6 +1446,7 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
|
@ -1450,6 +1480,7 @@
|
||||||
"entity"
|
"entity"
|
||||||
],
|
],
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1480,6 +1511,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1506,6 +1538,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1541,6 +1574,7 @@
|
||||||
"$ref": "ObjectAccessControls"
|
"$ref": "ObjectAccessControls"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1574,6 +1608,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1607,6 +1642,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1640,7 +1676,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1651,6 +1687,7 @@
|
||||||
"entity"
|
"entity"
|
||||||
],
|
],
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1680,7 +1717,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1694,6 +1731,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1717,7 +1755,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1733,6 +1771,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1756,7 +1795,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1769,6 +1808,7 @@
|
||||||
"$ref": "ObjectAccessControls"
|
"$ref": "ObjectAccessControls"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1798,7 +1838,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1815,6 +1855,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
@ -1844,7 +1885,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -1861,6 +1902,7 @@
|
||||||
"$ref": "ObjectAccessControl"
|
"$ref": "ObjectAccessControl"
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control"
|
"https://www.googleapis.com/auth/devstorage.full_control"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1882,7 +1924,7 @@
|
||||||
},
|
},
|
||||||
"destinationObject": {
|
"destinationObject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the new object.",
|
"description": "Name of the new object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -1935,7 +1977,8 @@
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
],
|
],
|
||||||
"supportsMediaDownload": true
|
"supportsMediaDownload": true,
|
||||||
|
"useMediaDownloadService": true
|
||||||
},
|
},
|
||||||
"copy": {
|
"copy": {
|
||||||
"id": "storage.objects.copy",
|
"id": "storage.objects.copy",
|
||||||
|
@ -1945,7 +1988,7 @@
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"destinationBucket": {
|
"destinationBucket": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the bucket in which to store the new object. Overrides the provided object metadata's bucket value, if any.",
|
"description": "Name of the bucket in which to store the new object. Overrides the provided object metadata's bucket value, if any.For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -2051,7 +2094,7 @@
|
||||||
},
|
},
|
||||||
"sourceObject": {
|
"sourceObject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the source object.",
|
"description": "Name of the source object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -2073,7 +2116,8 @@
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
],
|
],
|
||||||
"supportsMediaDownload": true
|
"supportsMediaDownload": true,
|
||||||
|
"useMediaDownloadService": true
|
||||||
},
|
},
|
||||||
"delete": {
|
"delete": {
|
||||||
"id": "storage.objects.delete",
|
"id": "storage.objects.delete",
|
||||||
|
@ -2119,7 +2163,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -2178,7 +2222,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -2205,11 +2249,13 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
],
|
],
|
||||||
"supportsMediaDownload": true
|
"supportsMediaDownload": true,
|
||||||
|
"useMediaDownloadService": true
|
||||||
},
|
},
|
||||||
"insert": {
|
"insert": {
|
||||||
"id": "storage.objects.insert",
|
"id": "storage.objects.insert",
|
||||||
|
@ -2254,7 +2300,7 @@
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object. Required when the object metadata is not otherwise provided. Overrides the object metadata's name value, if any.",
|
"description": "Name of the object. Required when the object metadata is not otherwise provided. Overrides the object metadata's name value, if any. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"location": "query"
|
"location": "query"
|
||||||
},
|
},
|
||||||
"predefinedAcl": {
|
"predefinedAcl": {
|
||||||
|
@ -2307,6 +2353,7 @@
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
],
|
],
|
||||||
"supportsMediaDownload": true,
|
"supportsMediaDownload": true,
|
||||||
|
"useMediaDownloadService": true,
|
||||||
"supportsMediaUpload": true,
|
"supportsMediaUpload": true,
|
||||||
"mediaUpload": {
|
"mediaUpload": {
|
||||||
"accept": [
|
"accept": [
|
||||||
|
@ -2385,6 +2432,7 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
|
@ -2435,7 +2483,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -2504,7 +2552,7 @@
|
||||||
},
|
},
|
||||||
"destinationObject": {
|
"destinationObject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the new object. Required when the object metadata is not otherwise provided. Overrides the object metadata's name value, if any.",
|
"description": "Name of the new object. Required when the object metadata is not otherwise provided. Overrides the object metadata's name value, if any. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -2615,7 +2663,7 @@
|
||||||
},
|
},
|
||||||
"sourceObject": {
|
"sourceObject": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the source object.",
|
"description": "Name of the source object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
}
|
}
|
||||||
|
@ -2682,7 +2730,7 @@
|
||||||
},
|
},
|
||||||
"object": {
|
"object": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Name of the object.",
|
"description": "Name of the object. For information about how to URL encode object names to be path safe, see Encoding URI Path Parts.",
|
||||||
"required": true,
|
"required": true,
|
||||||
"location": "path"
|
"location": "path"
|
||||||
},
|
},
|
||||||
|
@ -2736,7 +2784,8 @@
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
],
|
],
|
||||||
"supportsMediaDownload": true
|
"supportsMediaDownload": true,
|
||||||
|
"useMediaDownloadService": true
|
||||||
},
|
},
|
||||||
"watchAll": {
|
"watchAll": {
|
||||||
"id": "storage.objects.watchAll",
|
"id": "storage.objects.watchAll",
|
||||||
|
@ -2803,6 +2852,7 @@
|
||||||
},
|
},
|
||||||
"scopes": [
|
"scopes": [
|
||||||
"https://www.googleapis.com/auth/cloud-platform",
|
"https://www.googleapis.com/auth/cloud-platform",
|
||||||
|
"https://www.googleapis.com/auth/cloud-platform.read-only",
|
||||||
"https://www.googleapis.com/auth/devstorage.full_control",
|
"https://www.googleapis.com/auth/devstorage.full_control",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_only",
|
"https://www.googleapis.com/auth/devstorage.read_only",
|
||||||
"https://www.googleapis.com/auth/devstorage.read_write"
|
"https://www.googleapis.com/auth/devstorage.read_write"
|
||||||
|
|
3609
vendor/google.golang.org/api/storage/v1/storage-gen.go
generated
vendored
3609
vendor/google.golang.org/api/storage/v1/storage-gen.go
generated
vendored
File diff suppressed because it is too large
Load diff
18
vendor/google.golang.org/appengine/.travis.yml
generated
vendored
Normal file
18
vendor/google.golang.org/appengine/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
language: go
|
||||||
|
sudo: false
|
||||||
|
|
||||||
|
go:
|
||||||
|
- 1.4
|
||||||
|
|
||||||
|
install:
|
||||||
|
- go get -v -t -d google.golang.org/appengine/...
|
||||||
|
- mkdir sdk
|
||||||
|
- curl -o sdk.zip "https://storage.googleapis.com/appengine-sdks/featured/go_appengine_sdk_linux_amd64-1.9.24.zip"
|
||||||
|
- unzip sdk.zip -d sdk
|
||||||
|
- export APPENGINE_DEV_APPSERVER=$(pwd)/sdk/go_appengine/dev_appserver.py
|
||||||
|
|
||||||
|
script:
|
||||||
|
- go version
|
||||||
|
- go test -v google.golang.org/appengine/...
|
||||||
|
- go test -v -race google.golang.org/appengine/...
|
||||||
|
- sdk/go_appengine/goapp test -v google.golang.org/appengine/...
|
202
vendor/google.golang.org/appengine/LICENSE
generated
vendored
Normal file
202
vendor/google.golang.org/appengine/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,202 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright [yyyy] [name of copyright owner]
|
||||||
|
|
||||||
|
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.
|
73
vendor/google.golang.org/appengine/README.md
generated
vendored
Normal file
73
vendor/google.golang.org/appengine/README.md
generated
vendored
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
# Go App Engine packages
|
||||||
|
|
||||||
|
[![Build Status](https://travis-ci.org/golang/appengine.svg)](https://travis-ci.org/golang/appengine)
|
||||||
|
|
||||||
|
This repository supports the Go runtime on App Engine,
|
||||||
|
including both classic App Engine and Managed VMs.
|
||||||
|
It provides APIs for interacting with App Engine services.
|
||||||
|
Its canonical import path is `google.golang.org/appengine`.
|
||||||
|
|
||||||
|
See https://cloud.google.com/appengine/docs/go/
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
File issue reports and feature requests on the [Google App Engine issue
|
||||||
|
tracker](https://code.google.com/p/googleappengine/issues/entry?template=Go%20defect).
|
||||||
|
|
||||||
|
## Directory structure
|
||||||
|
The top level directory of this repository is the `appengine` package. It
|
||||||
|
contains the
|
||||||
|
basic APIs (e.g. `appengine.NewContext`) that apply across APIs. Specific API
|
||||||
|
packages are in subdirectories (e.g. `datastore`).
|
||||||
|
|
||||||
|
There is an `internal` subdirectory that contains service protocol buffers,
|
||||||
|
plus packages required for connectivity to make API calls. App Engine apps
|
||||||
|
should not directly import any package under `internal`.
|
||||||
|
|
||||||
|
## Updating a Go App Engine app
|
||||||
|
|
||||||
|
This section describes how to update a traditional Go App Engine app to use
|
||||||
|
these packages.
|
||||||
|
|
||||||
|
### 1. Update YAML files (Managed VMs only)
|
||||||
|
|
||||||
|
The `app.yaml` file (and YAML files for modules) should have these new lines added:
|
||||||
|
```
|
||||||
|
vm: true
|
||||||
|
```
|
||||||
|
See https://cloud.google.com/appengine/docs/go/modules/#Go_Instance_scaling_and_class for details.
|
||||||
|
|
||||||
|
### 2. Update import paths
|
||||||
|
|
||||||
|
The import paths for App Engine packages are now fully qualified, based at `google.golang.org/appengine`.
|
||||||
|
You will need to update your code to use import paths starting with that; for instance,
|
||||||
|
code importing `appengine/datastore` will now need to import `google.golang.org/appengine/datastore`.
|
||||||
|
You can do that manually, or by running this command to recursively update all Go source files in the current directory:
|
||||||
|
(may require GNU sed)
|
||||||
|
```
|
||||||
|
sed -i '/"appengine/{s,"appengine,"google.golang.org/appengine,;s,appengine_,appengine/,}' \
|
||||||
|
$(find . -name '*.go')
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Update code using deprecated, removed or modified APIs
|
||||||
|
|
||||||
|
Most App Engine services are available with exactly the same API.
|
||||||
|
A few APIs were cleaned up, and some are not available yet.
|
||||||
|
This list summarises the differences:
|
||||||
|
|
||||||
|
* `appengine.Context` has been replaced with the `Context` type from `golang.org/x/net/context`.
|
||||||
|
* Logging methods that were on `appengine.Context` are now functions in `google.golang.org/appengine/log`.
|
||||||
|
* `appengine.Timeout` has been removed. Use `context.WithTimeout` instead.
|
||||||
|
* `appengine.Datacenter` now takes a `context.Context` argument.
|
||||||
|
* `datastore.PropertyLoadSaver` has been simplified to use slices in place of channels.
|
||||||
|
* `delay.Call` now returns an error.
|
||||||
|
* `search.FieldLoadSaver` now handles document metadata.
|
||||||
|
* `urlfetch.Transport` no longer has a Deadline field; set a deadline on the
|
||||||
|
`context.Context` instead.
|
||||||
|
* `aetest` no longer declares its own Context type, and uses the standard one instead.
|
||||||
|
* `taskqueue.QueueStats` no longer takes a maxTasks argument. That argument has been
|
||||||
|
deprecated and unused for a long time.
|
||||||
|
* `appengine.BackendHostname` and `appengine.BackendInstance` were for the deprecated backends feature.
|
||||||
|
Use `appengine.ModuleHostname`and `appengine.ModuleName` instead.
|
||||||
|
* Most of `appengine/file` and parts of `appengine/blobstore` are deprecated.
|
||||||
|
Use [Google Cloud Storage](https://godoc.org/google.golang.org/cloud/storage) instead.
|
||||||
|
* `appengine/socket` is not required on Managed VMs. Use the standard `net` package instead.
|
76
vendor/google.golang.org/appengine/appengine.go
generated
vendored
Normal file
76
vendor/google.golang.org/appengine/appengine.go
generated
vendored
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// Package appengine provides basic functionality for Google App Engine.
|
||||||
|
//
|
||||||
|
// For more information on how to write Go apps for Google App Engine, see:
|
||||||
|
// https://cloud.google.com/appengine/docs/go/
|
||||||
|
package appengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"google.golang.org/appengine/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsDevAppServer reports whether the App Engine app is running in the
|
||||||
|
// development App Server.
|
||||||
|
func IsDevAppServer() bool {
|
||||||
|
return internal.IsDevAppServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewContext returns a context for an in-flight HTTP request.
|
||||||
|
// This function is cheap.
|
||||||
|
func NewContext(req *http.Request) context.Context {
|
||||||
|
return WithContext(context.Background(), req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithContext returns a copy of the parent context
|
||||||
|
// and associates it with an in-flight HTTP request.
|
||||||
|
// This function is cheap.
|
||||||
|
func WithContext(parent context.Context, req *http.Request) context.Context {
|
||||||
|
return internal.WithContext(parent, req)
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dsymonds): Add a Call function here? Otherwise other packages can't access internal.Call.
|
||||||
|
|
||||||
|
// BlobKey is a key for a blobstore blob.
|
||||||
|
//
|
||||||
|
// Conceptually, this type belongs in the blobstore package, but it lives in
|
||||||
|
// the appengine package to avoid a circular dependency: blobstore depends on
|
||||||
|
// datastore, and datastore needs to refer to the BlobKey type.
|
||||||
|
type BlobKey string
|
||||||
|
|
||||||
|
// GeoPoint represents a location as latitude/longitude in degrees.
|
||||||
|
type GeoPoint struct {
|
||||||
|
Lat, Lng float64
|
||||||
|
}
|
||||||
|
|
||||||
|
// Valid returns whether a GeoPoint is within [-90, 90] latitude and [-180, 180] longitude.
|
||||||
|
func (g GeoPoint) Valid() bool {
|
||||||
|
return -90 <= g.Lat && g.Lat <= 90 && -180 <= g.Lng && g.Lng <= 180
|
||||||
|
}
|
||||||
|
|
||||||
|
// APICallFunc defines a function type for handling an API call.
|
||||||
|
// See WithCallOverride.
|
||||||
|
type APICallFunc func(ctx context.Context, service, method string, in, out proto.Message) error
|
||||||
|
|
||||||
|
// WithAPICallFunc returns a copy of the parent context
|
||||||
|
// that will cause API calls to invoke f instead of their normal operation.
|
||||||
|
//
|
||||||
|
// This is intended for advanced users only.
|
||||||
|
func WithAPICallFunc(ctx context.Context, f APICallFunc) context.Context {
|
||||||
|
return internal.WithCallOverride(ctx, internal.CallOverrideFunc(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
// APICall performs an API call.
|
||||||
|
//
|
||||||
|
// This is not intended for general use; it is exported for use in conjunction
|
||||||
|
// with WithAPICallFunc.
|
||||||
|
func APICall(ctx context.Context, service, method string, in, out proto.Message) error {
|
||||||
|
return internal.Call(ctx, service, method, in, out)
|
||||||
|
}
|
56
vendor/google.golang.org/appengine/appengine_vm.go
generated
vendored
Normal file
56
vendor/google.golang.org/appengine/appengine_vm.go
generated
vendored
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package appengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"google.golang.org/appengine/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// The comment below must not be changed.
|
||||||
|
// It is used by go-app-builder to recognise that this package has
|
||||||
|
// the Main function to use in the synthetic main.
|
||||||
|
// The gophers party all night; the rabbits provide the beats.
|
||||||
|
|
||||||
|
// Main is the principal entry point for a Managed VMs app.
|
||||||
|
// It installs a trivial health checker if one isn't already registered,
|
||||||
|
// and starts listening on port 8080 (overridden by the $PORT environment
|
||||||
|
// variable).
|
||||||
|
//
|
||||||
|
// See https://cloud.google.com/appengine/docs/managed-vms/custom-runtimes#health_check_requests
|
||||||
|
// for details on how to do your own health checking.
|
||||||
|
//
|
||||||
|
// Main never returns.
|
||||||
|
//
|
||||||
|
// Main is designed so that the app's main package looks like this:
|
||||||
|
//
|
||||||
|
// package main
|
||||||
|
//
|
||||||
|
// import (
|
||||||
|
// "google.golang.org/appengine"
|
||||||
|
//
|
||||||
|
// _ "myapp/package0"
|
||||||
|
// _ "myapp/package1"
|
||||||
|
// )
|
||||||
|
//
|
||||||
|
// func main() {
|
||||||
|
// appengine.Main()
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// The "myapp/packageX" packages are expected to register HTTP handlers
|
||||||
|
// in their init functions.
|
||||||
|
func Main() {
|
||||||
|
internal.Main()
|
||||||
|
}
|
||||||
|
|
||||||
|
// BackgroundContext returns a context not associated with a request.
|
||||||
|
// This should only be used when not servicing a request.
|
||||||
|
// This only works on Managed VMs.
|
||||||
|
func BackgroundContext() context.Context {
|
||||||
|
return internal.BackgroundContext()
|
||||||
|
}
|
46
vendor/google.golang.org/appengine/errors.go
generated
vendored
Normal file
46
vendor/google.golang.org/appengine/errors.go
generated
vendored
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// This file provides error functions for common API failure modes.
|
||||||
|
|
||||||
|
package appengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"google.golang.org/appengine/internal"
|
||||||
|
)
|
||||||
|
|
||||||
|
// IsOverQuota reports whether err represents an API call failure
|
||||||
|
// due to insufficient available quota.
|
||||||
|
func IsOverQuota(err error) bool {
|
||||||
|
callErr, ok := err.(*internal.CallError)
|
||||||
|
return ok && callErr.Code == 4
|
||||||
|
}
|
||||||
|
|
||||||
|
// MultiError is returned by batch operations when there are errors with
|
||||||
|
// particular elements. Errors will be in a one-to-one correspondence with
|
||||||
|
// the input elements; successful elements will have a nil entry.
|
||||||
|
type MultiError []error
|
||||||
|
|
||||||
|
func (m MultiError) Error() string {
|
||||||
|
s, n := "", 0
|
||||||
|
for _, e := range m {
|
||||||
|
if e != nil {
|
||||||
|
if n == 0 {
|
||||||
|
s = e.Error()
|
||||||
|
}
|
||||||
|
n++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch n {
|
||||||
|
case 0:
|
||||||
|
return "(0 errors)"
|
||||||
|
case 1:
|
||||||
|
return s
|
||||||
|
case 2:
|
||||||
|
return s + " (and 1 other error)"
|
||||||
|
}
|
||||||
|
return fmt.Sprintf("%s (and %d other errors)", s, n-1)
|
||||||
|
}
|
142
vendor/google.golang.org/appengine/identity.go
generated
vendored
Normal file
142
vendor/google.golang.org/appengine/identity.go
generated
vendored
Normal file
|
@ -0,0 +1,142 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package appengine
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
|
"google.golang.org/appengine/internal"
|
||||||
|
pb "google.golang.org/appengine/internal/app_identity"
|
||||||
|
modpb "google.golang.org/appengine/internal/modules"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AppID returns the application ID for the current application.
|
||||||
|
// The string will be a plain application ID (e.g. "appid"), with a
|
||||||
|
// domain prefix for custom domain deployments (e.g. "example.com:appid").
|
||||||
|
func AppID(c context.Context) string { return internal.AppID(c) }
|
||||||
|
|
||||||
|
// DefaultVersionHostname returns the standard hostname of the default version
|
||||||
|
// of the current application (e.g. "my-app.appspot.com"). This is suitable for
|
||||||
|
// use in constructing URLs.
|
||||||
|
func DefaultVersionHostname(c context.Context) string {
|
||||||
|
return internal.DefaultVersionHostname(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModuleName returns the module name of the current instance.
|
||||||
|
func ModuleName(c context.Context) string {
|
||||||
|
return internal.ModuleName(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ModuleHostname returns a hostname of a module instance.
|
||||||
|
// If module is the empty string, it refers to the module of the current instance.
|
||||||
|
// If version is empty, it refers to the version of the current instance if valid,
|
||||||
|
// or the default version of the module of the current instance.
|
||||||
|
// If instance is empty, ModuleHostname returns the load-balancing hostname.
|
||||||
|
func ModuleHostname(c context.Context, module, version, instance string) (string, error) {
|
||||||
|
req := &modpb.GetHostnameRequest{}
|
||||||
|
if module != "" {
|
||||||
|
req.Module = &module
|
||||||
|
}
|
||||||
|
if version != "" {
|
||||||
|
req.Version = &version
|
||||||
|
}
|
||||||
|
if instance != "" {
|
||||||
|
req.Instance = &instance
|
||||||
|
}
|
||||||
|
res := &modpb.GetHostnameResponse{}
|
||||||
|
if err := internal.Call(c, "modules", "GetHostname", req, res); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return *res.Hostname, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// VersionID returns the version ID for the current application.
|
||||||
|
// It will be of the form "X.Y", where X is specified in app.yaml,
|
||||||
|
// and Y is a number generated when each version of the app is uploaded.
|
||||||
|
// It does not include a module name.
|
||||||
|
func VersionID(c context.Context) string { return internal.VersionID(c) }
|
||||||
|
|
||||||
|
// InstanceID returns a mostly-unique identifier for this instance.
|
||||||
|
func InstanceID() string { return internal.InstanceID() }
|
||||||
|
|
||||||
|
// Datacenter returns an identifier for the datacenter that the instance is running in.
|
||||||
|
func Datacenter(c context.Context) string { return internal.Datacenter(c) }
|
||||||
|
|
||||||
|
// ServerSoftware returns the App Engine release version.
|
||||||
|
// In production, it looks like "Google App Engine/X.Y.Z".
|
||||||
|
// In the development appserver, it looks like "Development/X.Y".
|
||||||
|
func ServerSoftware() string { return internal.ServerSoftware() }
|
||||||
|
|
||||||
|
// RequestID returns a string that uniquely identifies the request.
|
||||||
|
func RequestID(c context.Context) string { return internal.RequestID(c) }
|
||||||
|
|
||||||
|
// AccessToken generates an OAuth2 access token for the specified scopes on
|
||||||
|
// behalf of service account of this application. This token will expire after
|
||||||
|
// the returned time.
|
||||||
|
func AccessToken(c context.Context, scopes ...string) (token string, expiry time.Time, err error) {
|
||||||
|
req := &pb.GetAccessTokenRequest{Scope: scopes}
|
||||||
|
res := &pb.GetAccessTokenResponse{}
|
||||||
|
|
||||||
|
err = internal.Call(c, "app_identity_service", "GetAccessToken", req, res)
|
||||||
|
if err != nil {
|
||||||
|
return "", time.Time{}, err
|
||||||
|
}
|
||||||
|
return res.GetAccessToken(), time.Unix(res.GetExpirationTime(), 0), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Certificate represents a public certificate for the app.
|
||||||
|
type Certificate struct {
|
||||||
|
KeyName string
|
||||||
|
Data []byte // PEM-encoded X.509 certificate
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicCertificates retrieves the public certificates for the app.
|
||||||
|
// They can be used to verify a signature returned by SignBytes.
|
||||||
|
func PublicCertificates(c context.Context) ([]Certificate, error) {
|
||||||
|
req := &pb.GetPublicCertificateForAppRequest{}
|
||||||
|
res := &pb.GetPublicCertificateForAppResponse{}
|
||||||
|
if err := internal.Call(c, "app_identity_service", "GetPublicCertificatesForApp", req, res); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var cs []Certificate
|
||||||
|
for _, pc := range res.PublicCertificateList {
|
||||||
|
cs = append(cs, Certificate{
|
||||||
|
KeyName: pc.GetKeyName(),
|
||||||
|
Data: []byte(pc.GetX509CertificatePem()),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ServiceAccount returns a string representing the service account name, in
|
||||||
|
// the form of an email address (typically app_id@appspot.gserviceaccount.com).
|
||||||
|
func ServiceAccount(c context.Context) (string, error) {
|
||||||
|
req := &pb.GetServiceAccountNameRequest{}
|
||||||
|
res := &pb.GetServiceAccountNameResponse{}
|
||||||
|
|
||||||
|
err := internal.Call(c, "app_identity_service", "GetServiceAccountName", req, res)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return res.GetServiceAccountName(), err
|
||||||
|
}
|
||||||
|
|
||||||
|
// SignBytes signs bytes using a private key unique to your application.
|
||||||
|
func SignBytes(c context.Context, bytes []byte) (keyName string, signature []byte, err error) {
|
||||||
|
req := &pb.SignForAppRequest{BytesToSign: bytes}
|
||||||
|
res := &pb.SignForAppResponse{}
|
||||||
|
|
||||||
|
if err := internal.Call(c, "app_identity_service", "SignForApp", req, res); err != nil {
|
||||||
|
return "", nil, err
|
||||||
|
}
|
||||||
|
return res.GetKeyName(), res.GetSignatureBytes(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
internal.RegisterErrorCodeMap("app_identity_service", pb.AppIdentityServiceError_ErrorCode_name)
|
||||||
|
internal.RegisterErrorCodeMap("modules", modpb.ModulesServiceError_ErrorCode_name)
|
||||||
|
}
|
640
vendor/google.golang.org/appengine/internal/api.go
generated
vendored
Normal file
640
vendor/google.golang.org/appengine/internal/api.go
generated
vendored
Normal file
|
@ -0,0 +1,640 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build !appengine
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"sync/atomic"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
netcontext "golang.org/x/net/context"
|
||||||
|
|
||||||
|
basepb "google.golang.org/appengine/internal/base"
|
||||||
|
logpb "google.golang.org/appengine/internal/log"
|
||||||
|
remotepb "google.golang.org/appengine/internal/remote_api"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
apiPath = "/rpc_http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// Incoming headers.
|
||||||
|
ticketHeader = http.CanonicalHeaderKey("X-AppEngine-API-Ticket")
|
||||||
|
dapperHeader = http.CanonicalHeaderKey("X-Google-DapperTraceInfo")
|
||||||
|
traceHeader = http.CanonicalHeaderKey("X-Cloud-Trace-Context")
|
||||||
|
curNamespaceHeader = http.CanonicalHeaderKey("X-AppEngine-Current-Namespace")
|
||||||
|
userIPHeader = http.CanonicalHeaderKey("X-AppEngine-User-IP")
|
||||||
|
remoteAddrHeader = http.CanonicalHeaderKey("X-AppEngine-Remote-Addr")
|
||||||
|
|
||||||
|
// Outgoing headers.
|
||||||
|
apiEndpointHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Endpoint")
|
||||||
|
apiEndpointHeaderValue = []string{"app-engine-apis"}
|
||||||
|
apiMethodHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Method")
|
||||||
|
apiMethodHeaderValue = []string{"/VMRemoteAPI.CallRemoteAPI"}
|
||||||
|
apiDeadlineHeader = http.CanonicalHeaderKey("X-Google-RPC-Service-Deadline")
|
||||||
|
apiContentType = http.CanonicalHeaderKey("Content-Type")
|
||||||
|
apiContentTypeValue = []string{"application/octet-stream"}
|
||||||
|
logFlushHeader = http.CanonicalHeaderKey("X-AppEngine-Log-Flush-Count")
|
||||||
|
|
||||||
|
apiHTTPClient = &http.Client{
|
||||||
|
Transport: &http.Transport{
|
||||||
|
Proxy: http.ProxyFromEnvironment,
|
||||||
|
Dial: limitDial,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
func apiURL() *url.URL {
|
||||||
|
host, port := "appengine.googleapis.internal", "10001"
|
||||||
|
if h := os.Getenv("API_HOST"); h != "" {
|
||||||
|
host = h
|
||||||
|
}
|
||||||
|
if p := os.Getenv("API_PORT"); p != "" {
|
||||||
|
port = p
|
||||||
|
}
|
||||||
|
return &url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: host + ":" + port,
|
||||||
|
Path: apiPath,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
c := &context{
|
||||||
|
req: r,
|
||||||
|
outHeader: w.Header(),
|
||||||
|
apiURL: apiURL(),
|
||||||
|
}
|
||||||
|
stopFlushing := make(chan int)
|
||||||
|
|
||||||
|
ctxs.Lock()
|
||||||
|
ctxs.m[r] = c
|
||||||
|
ctxs.Unlock()
|
||||||
|
defer func() {
|
||||||
|
ctxs.Lock()
|
||||||
|
delete(ctxs.m, r)
|
||||||
|
ctxs.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
// Patch up RemoteAddr so it looks reasonable.
|
||||||
|
if addr := r.Header.Get(userIPHeader); addr != "" {
|
||||||
|
r.RemoteAddr = addr
|
||||||
|
} else if addr = r.Header.Get(remoteAddrHeader); addr != "" {
|
||||||
|
r.RemoteAddr = addr
|
||||||
|
} else {
|
||||||
|
// Should not normally reach here, but pick a sensible default anyway.
|
||||||
|
r.RemoteAddr = "127.0.0.1"
|
||||||
|
}
|
||||||
|
// The address in the headers will most likely be of these forms:
|
||||||
|
// 123.123.123.123
|
||||||
|
// 2001:db8::1
|
||||||
|
// net/http.Request.RemoteAddr is specified to be in "IP:port" form.
|
||||||
|
if _, _, err := net.SplitHostPort(r.RemoteAddr); err != nil {
|
||||||
|
// Assume the remote address is only a host; add a default port.
|
||||||
|
r.RemoteAddr = net.JoinHostPort(r.RemoteAddr, "80")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start goroutine responsible for flushing app logs.
|
||||||
|
// This is done after adding c to ctx.m (and stopped before removing it)
|
||||||
|
// because flushing logs requires making an API call.
|
||||||
|
go c.logFlusher(stopFlushing)
|
||||||
|
|
||||||
|
executeRequestSafely(c, r)
|
||||||
|
c.outHeader = nil // make sure header changes aren't respected any more
|
||||||
|
|
||||||
|
stopFlushing <- 1 // any logging beyond this point will be dropped
|
||||||
|
|
||||||
|
// Flush any pending logs asynchronously.
|
||||||
|
c.pendingLogs.Lock()
|
||||||
|
flushes := c.pendingLogs.flushes
|
||||||
|
if len(c.pendingLogs.lines) > 0 {
|
||||||
|
flushes++
|
||||||
|
}
|
||||||
|
c.pendingLogs.Unlock()
|
||||||
|
go c.flushLog(false)
|
||||||
|
w.Header().Set(logFlushHeader, strconv.Itoa(flushes))
|
||||||
|
|
||||||
|
// Avoid nil Write call if c.Write is never called.
|
||||||
|
if c.outCode != 0 {
|
||||||
|
w.WriteHeader(c.outCode)
|
||||||
|
}
|
||||||
|
if c.outBody != nil {
|
||||||
|
w.Write(c.outBody)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func executeRequestSafely(c *context, r *http.Request) {
|
||||||
|
defer func() {
|
||||||
|
if x := recover(); x != nil {
|
||||||
|
logf(c, 4, "%s", renderPanic(x)) // 4 == critical
|
||||||
|
c.outCode = 500
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
http.DefaultServeMux.ServeHTTP(c, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func renderPanic(x interface{}) string {
|
||||||
|
buf := make([]byte, 16<<10) // 16 KB should be plenty
|
||||||
|
buf = buf[:runtime.Stack(buf, false)]
|
||||||
|
|
||||||
|
// Remove the first few stack frames:
|
||||||
|
// this func
|
||||||
|
// the recover closure in the caller
|
||||||
|
// That will root the stack trace at the site of the panic.
|
||||||
|
const (
|
||||||
|
skipStart = "internal.renderPanic"
|
||||||
|
skipFrames = 2
|
||||||
|
)
|
||||||
|
start := bytes.Index(buf, []byte(skipStart))
|
||||||
|
p := start
|
||||||
|
for i := 0; i < skipFrames*2 && p+1 < len(buf); i++ {
|
||||||
|
p = bytes.IndexByte(buf[p+1:], '\n') + p + 1
|
||||||
|
if p < 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if p >= 0 {
|
||||||
|
// buf[start:p+1] is the block to remove.
|
||||||
|
// Copy buf[p+1:] over buf[start:] and shrink buf.
|
||||||
|
copy(buf[start:], buf[p+1:])
|
||||||
|
buf = buf[:len(buf)-(p+1-start)]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add panic heading.
|
||||||
|
head := fmt.Sprintf("panic: %v\n\n", x)
|
||||||
|
if len(head) > len(buf) {
|
||||||
|
// Extremely unlikely to happen.
|
||||||
|
return head
|
||||||
|
}
|
||||||
|
copy(buf[len(head):], buf)
|
||||||
|
copy(buf, head)
|
||||||
|
|
||||||
|
return string(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
var ctxs = struct {
|
||||||
|
sync.Mutex
|
||||||
|
m map[*http.Request]*context
|
||||||
|
bg *context // background context, lazily initialized
|
||||||
|
// dec is used by tests to decorate the netcontext.Context returned
|
||||||
|
// for a given request. This allows tests to add overrides (such as
|
||||||
|
// WithAppIDOverride) to the context. The map is nil outside tests.
|
||||||
|
dec map[*http.Request]func(netcontext.Context) netcontext.Context
|
||||||
|
}{
|
||||||
|
m: make(map[*http.Request]*context),
|
||||||
|
}
|
||||||
|
|
||||||
|
// context represents the context of an in-flight HTTP request.
|
||||||
|
// It implements the appengine.Context and http.ResponseWriter interfaces.
|
||||||
|
type context struct {
|
||||||
|
req *http.Request
|
||||||
|
|
||||||
|
outCode int
|
||||||
|
outHeader http.Header
|
||||||
|
outBody []byte
|
||||||
|
|
||||||
|
pendingLogs struct {
|
||||||
|
sync.Mutex
|
||||||
|
lines []*logpb.UserAppLogLine
|
||||||
|
flushes int
|
||||||
|
}
|
||||||
|
|
||||||
|
apiURL *url.URL
|
||||||
|
}
|
||||||
|
|
||||||
|
var contextKey = "holds a *context"
|
||||||
|
|
||||||
|
func fromContext(ctx netcontext.Context) *context {
|
||||||
|
c, _ := ctx.Value(&contextKey).(*context)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
func withContext(parent netcontext.Context, c *context) netcontext.Context {
|
||||||
|
ctx := netcontext.WithValue(parent, &contextKey, c)
|
||||||
|
if ns := c.req.Header.Get(curNamespaceHeader); ns != "" {
|
||||||
|
ctx = withNamespace(ctx, ns)
|
||||||
|
}
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func toContext(c *context) netcontext.Context {
|
||||||
|
return withContext(netcontext.Background(), c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func IncomingHeaders(ctx netcontext.Context) http.Header {
|
||||||
|
if c := fromContext(ctx); c != nil {
|
||||||
|
return c.req.Header
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
|
||||||
|
ctxs.Lock()
|
||||||
|
c := ctxs.m[req]
|
||||||
|
d := ctxs.dec[req]
|
||||||
|
ctxs.Unlock()
|
||||||
|
|
||||||
|
if d != nil {
|
||||||
|
parent = d(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
if c == nil {
|
||||||
|
// Someone passed in an http.Request that is not in-flight.
|
||||||
|
// We panic here rather than panicking at a later point
|
||||||
|
// so that stack traces will be more sensible.
|
||||||
|
log.Panic("appengine: NewContext passed an unknown http.Request")
|
||||||
|
}
|
||||||
|
return withContext(parent, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func BackgroundContext() netcontext.Context {
|
||||||
|
ctxs.Lock()
|
||||||
|
defer ctxs.Unlock()
|
||||||
|
|
||||||
|
if ctxs.bg != nil {
|
||||||
|
return toContext(ctxs.bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute background security ticket.
|
||||||
|
appID := partitionlessAppID()
|
||||||
|
escAppID := strings.Replace(strings.Replace(appID, ":", "_", -1), ".", "_", -1)
|
||||||
|
majVersion := VersionID(nil)
|
||||||
|
if i := strings.Index(majVersion, "."); i > 0 {
|
||||||
|
majVersion = majVersion[:i]
|
||||||
|
}
|
||||||
|
ticket := fmt.Sprintf("%s/%s.%s.%s", escAppID, ModuleName(nil), majVersion, InstanceID())
|
||||||
|
|
||||||
|
ctxs.bg = &context{
|
||||||
|
req: &http.Request{
|
||||||
|
Header: http.Header{
|
||||||
|
ticketHeader: []string{ticket},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
apiURL: apiURL(),
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO(dsymonds): Wire up the shutdown handler to do a final flush.
|
||||||
|
go ctxs.bg.logFlusher(make(chan int))
|
||||||
|
|
||||||
|
return toContext(ctxs.bg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RegisterTestRequest registers the HTTP request req for testing, such that
|
||||||
|
// any API calls are sent to the provided URL. It returns a closure to delete
|
||||||
|
// the registration.
|
||||||
|
// It should only be used by aetest package.
|
||||||
|
func RegisterTestRequest(req *http.Request, apiURL *url.URL, decorate func(netcontext.Context) netcontext.Context) func() {
|
||||||
|
c := &context{
|
||||||
|
req: req,
|
||||||
|
apiURL: apiURL,
|
||||||
|
}
|
||||||
|
ctxs.Lock()
|
||||||
|
defer ctxs.Unlock()
|
||||||
|
if _, ok := ctxs.m[req]; ok {
|
||||||
|
log.Panic("req already associated with context")
|
||||||
|
}
|
||||||
|
if _, ok := ctxs.dec[req]; ok {
|
||||||
|
log.Panic("req already associated with context")
|
||||||
|
}
|
||||||
|
if ctxs.dec == nil {
|
||||||
|
ctxs.dec = make(map[*http.Request]func(netcontext.Context) netcontext.Context)
|
||||||
|
}
|
||||||
|
ctxs.m[req] = c
|
||||||
|
ctxs.dec[req] = decorate
|
||||||
|
|
||||||
|
return func() {
|
||||||
|
ctxs.Lock()
|
||||||
|
delete(ctxs.m, req)
|
||||||
|
delete(ctxs.dec, req)
|
||||||
|
ctxs.Unlock()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var errTimeout = &CallError{
|
||||||
|
Detail: "Deadline exceeded",
|
||||||
|
Code: int32(remotepb.RpcError_CANCELLED),
|
||||||
|
Timeout: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) Header() http.Header { return c.outHeader }
|
||||||
|
|
||||||
|
// Copied from $GOROOT/src/pkg/net/http/transfer.go. Some response status
|
||||||
|
// codes do not permit a response body (nor response entity headers such as
|
||||||
|
// Content-Length, Content-Type, etc).
|
||||||
|
func bodyAllowedForStatus(status int) bool {
|
||||||
|
switch {
|
||||||
|
case status >= 100 && status <= 199:
|
||||||
|
return false
|
||||||
|
case status == 204:
|
||||||
|
return false
|
||||||
|
case status == 304:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) Write(b []byte) (int, error) {
|
||||||
|
if c.outCode == 0 {
|
||||||
|
c.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
if len(b) > 0 && !bodyAllowedForStatus(c.outCode) {
|
||||||
|
return 0, http.ErrBodyNotAllowed
|
||||||
|
}
|
||||||
|
c.outBody = append(c.outBody, b...)
|
||||||
|
return len(b), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) WriteHeader(code int) {
|
||||||
|
if c.outCode != 0 {
|
||||||
|
logf(c, 3, "WriteHeader called multiple times on request.") // error level
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.outCode = code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) post(body []byte, timeout time.Duration) (b []byte, err error) {
|
||||||
|
hreq := &http.Request{
|
||||||
|
Method: "POST",
|
||||||
|
URL: c.apiURL,
|
||||||
|
Header: http.Header{
|
||||||
|
apiEndpointHeader: apiEndpointHeaderValue,
|
||||||
|
apiMethodHeader: apiMethodHeaderValue,
|
||||||
|
apiContentType: apiContentTypeValue,
|
||||||
|
apiDeadlineHeader: []string{strconv.FormatFloat(timeout.Seconds(), 'f', -1, 64)},
|
||||||
|
},
|
||||||
|
Body: ioutil.NopCloser(bytes.NewReader(body)),
|
||||||
|
ContentLength: int64(len(body)),
|
||||||
|
Host: c.apiURL.Host,
|
||||||
|
}
|
||||||
|
if info := c.req.Header.Get(dapperHeader); info != "" {
|
||||||
|
hreq.Header.Set(dapperHeader, info)
|
||||||
|
}
|
||||||
|
if info := c.req.Header.Get(traceHeader); info != "" {
|
||||||
|
hreq.Header.Set(traceHeader, info)
|
||||||
|
}
|
||||||
|
|
||||||
|
tr := apiHTTPClient.Transport.(*http.Transport)
|
||||||
|
|
||||||
|
var timedOut int32 // atomic; set to 1 if timed out
|
||||||
|
t := time.AfterFunc(timeout, func() {
|
||||||
|
atomic.StoreInt32(&timedOut, 1)
|
||||||
|
tr.CancelRequest(hreq)
|
||||||
|
})
|
||||||
|
defer t.Stop()
|
||||||
|
defer func() {
|
||||||
|
// Check if timeout was exceeded.
|
||||||
|
if atomic.LoadInt32(&timedOut) != 0 {
|
||||||
|
err = errTimeout
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
hresp, err := apiHTTPClient.Do(hreq)
|
||||||
|
if err != nil {
|
||||||
|
return nil, &CallError{
|
||||||
|
Detail: fmt.Sprintf("service bridge HTTP failed: %v", err),
|
||||||
|
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
defer hresp.Body.Close()
|
||||||
|
hrespBody, err := ioutil.ReadAll(hresp.Body)
|
||||||
|
if hresp.StatusCode != 200 {
|
||||||
|
return nil, &CallError{
|
||||||
|
Detail: fmt.Sprintf("service bridge returned HTTP %d (%q)", hresp.StatusCode, hrespBody),
|
||||||
|
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
return nil, &CallError{
|
||||||
|
Detail: fmt.Sprintf("service bridge response bad: %v", err),
|
||||||
|
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hrespBody, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
|
||||||
|
if f, ctx, ok := callOverrideFromContext(ctx); ok {
|
||||||
|
return f(ctx, service, method, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle already-done contexts quickly.
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
c := fromContext(ctx)
|
||||||
|
if c == nil {
|
||||||
|
// Give a good error message rather than a panic lower down.
|
||||||
|
return errors.New("not an App Engine context")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply transaction modifications if we're in a transaction.
|
||||||
|
if t := transactionFromContext(ctx); t != nil {
|
||||||
|
if t.finished {
|
||||||
|
return errors.New("transaction context has expired")
|
||||||
|
}
|
||||||
|
applyTransaction(in, &t.transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Default RPC timeout is 60s.
|
||||||
|
timeout := 60 * time.Second
|
||||||
|
if deadline, ok := ctx.Deadline(); ok {
|
||||||
|
timeout = deadline.Sub(time.Now())
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := proto.Marshal(in)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket := c.req.Header.Get(ticketHeader)
|
||||||
|
req := &remotepb.Request{
|
||||||
|
ServiceName: &service,
|
||||||
|
Method: &method,
|
||||||
|
Request: data,
|
||||||
|
RequestId: &ticket,
|
||||||
|
}
|
||||||
|
hreqBody, err := proto.Marshal(req)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
hrespBody, err := c.post(hreqBody, timeout)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := &remotepb.Response{}
|
||||||
|
if err := proto.Unmarshal(hrespBody, res); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if res.RpcError != nil {
|
||||||
|
ce := &CallError{
|
||||||
|
Detail: res.RpcError.GetDetail(),
|
||||||
|
Code: *res.RpcError.Code,
|
||||||
|
}
|
||||||
|
switch remotepb.RpcError_ErrorCode(ce.Code) {
|
||||||
|
case remotepb.RpcError_CANCELLED, remotepb.RpcError_DEADLINE_EXCEEDED:
|
||||||
|
ce.Timeout = true
|
||||||
|
}
|
||||||
|
return ce
|
||||||
|
}
|
||||||
|
if res.ApplicationError != nil {
|
||||||
|
return &APIError{
|
||||||
|
Service: *req.ServiceName,
|
||||||
|
Detail: res.ApplicationError.GetDetail(),
|
||||||
|
Code: *res.ApplicationError.Code,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if res.Exception != nil || res.JavaException != nil {
|
||||||
|
// This shouldn't happen, but let's be defensive.
|
||||||
|
return &CallError{
|
||||||
|
Detail: "service bridge returned exception",
|
||||||
|
Code: int32(remotepb.RpcError_UNKNOWN),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return proto.Unmarshal(res.Response, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) Request() *http.Request {
|
||||||
|
return c.req
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *context) addLogLine(ll *logpb.UserAppLogLine) {
|
||||||
|
// Truncate long log lines.
|
||||||
|
// TODO(dsymonds): Check if this is still necessary.
|
||||||
|
const lim = 8 << 10
|
||||||
|
if len(*ll.Message) > lim {
|
||||||
|
suffix := fmt.Sprintf("...(length %d)", len(*ll.Message))
|
||||||
|
ll.Message = proto.String((*ll.Message)[:lim-len(suffix)] + suffix)
|
||||||
|
}
|
||||||
|
|
||||||
|
c.pendingLogs.Lock()
|
||||||
|
c.pendingLogs.lines = append(c.pendingLogs.lines, ll)
|
||||||
|
c.pendingLogs.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
var logLevelName = map[int64]string{
|
||||||
|
0: "DEBUG",
|
||||||
|
1: "INFO",
|
||||||
|
2: "WARNING",
|
||||||
|
3: "ERROR",
|
||||||
|
4: "CRITICAL",
|
||||||
|
}
|
||||||
|
|
||||||
|
func logf(c *context, level int64, format string, args ...interface{}) {
|
||||||
|
s := fmt.Sprintf(format, args...)
|
||||||
|
s = strings.TrimRight(s, "\n") // Remove any trailing newline characters.
|
||||||
|
c.addLogLine(&logpb.UserAppLogLine{
|
||||||
|
TimestampUsec: proto.Int64(time.Now().UnixNano() / 1e3),
|
||||||
|
Level: &level,
|
||||||
|
Message: &s,
|
||||||
|
})
|
||||||
|
log.Print(logLevelName[level] + ": " + s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// flushLog attempts to flush any pending logs to the appserver.
|
||||||
|
// It should not be called concurrently.
|
||||||
|
func (c *context) flushLog(force bool) (flushed bool) {
|
||||||
|
c.pendingLogs.Lock()
|
||||||
|
// Grab up to 30 MB. We can get away with up to 32 MB, but let's be cautious.
|
||||||
|
n, rem := 0, 30<<20
|
||||||
|
for ; n < len(c.pendingLogs.lines); n++ {
|
||||||
|
ll := c.pendingLogs.lines[n]
|
||||||
|
// Each log line will require about 3 bytes of overhead.
|
||||||
|
nb := proto.Size(ll) + 3
|
||||||
|
if nb > rem {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
rem -= nb
|
||||||
|
}
|
||||||
|
lines := c.pendingLogs.lines[:n]
|
||||||
|
c.pendingLogs.lines = c.pendingLogs.lines[n:]
|
||||||
|
c.pendingLogs.Unlock()
|
||||||
|
|
||||||
|
if len(lines) == 0 && !force {
|
||||||
|
// Nothing to flush.
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
rescueLogs := false
|
||||||
|
defer func() {
|
||||||
|
if rescueLogs {
|
||||||
|
c.pendingLogs.Lock()
|
||||||
|
c.pendingLogs.lines = append(lines, c.pendingLogs.lines...)
|
||||||
|
c.pendingLogs.Unlock()
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
buf, err := proto.Marshal(&logpb.UserAppLogGroup{
|
||||||
|
LogLine: lines,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("internal.flushLog: marshaling UserAppLogGroup: %v", err)
|
||||||
|
rescueLogs = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
req := &logpb.FlushRequest{
|
||||||
|
Logs: buf,
|
||||||
|
}
|
||||||
|
res := &basepb.VoidProto{}
|
||||||
|
c.pendingLogs.Lock()
|
||||||
|
c.pendingLogs.flushes++
|
||||||
|
c.pendingLogs.Unlock()
|
||||||
|
if err := Call(toContext(c), "logservice", "Flush", req, res); err != nil {
|
||||||
|
log.Printf("internal.flushLog: Flush RPC: %v", err)
|
||||||
|
rescueLogs = true
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Log flushing parameters.
|
||||||
|
flushInterval = 1 * time.Second
|
||||||
|
forceFlushInterval = 60 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c *context) logFlusher(stop <-chan int) {
|
||||||
|
lastFlush := time.Now()
|
||||||
|
tick := time.NewTicker(flushInterval)
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case <-stop:
|
||||||
|
// Request finished.
|
||||||
|
tick.Stop()
|
||||||
|
return
|
||||||
|
case <-tick.C:
|
||||||
|
force := time.Now().Sub(lastFlush) > forceFlushInterval
|
||||||
|
if c.flushLog(force) {
|
||||||
|
lastFlush = time.Now()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func ContextForTesting(req *http.Request) netcontext.Context {
|
||||||
|
return toContext(&context{req: req})
|
||||||
|
}
|
133
vendor/google.golang.org/appengine/internal/api_classic.go
generated
vendored
Normal file
133
vendor/google.golang.org/appengine/internal/api_classic.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"appengine"
|
||||||
|
"appengine_internal"
|
||||||
|
basepb "appengine_internal/base"
|
||||||
|
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
netcontext "golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
var contextKey = "holds an appengine.Context"
|
||||||
|
|
||||||
|
func fromContext(ctx netcontext.Context) appengine.Context {
|
||||||
|
c, _ := ctx.Value(&contextKey).(appengine.Context)
|
||||||
|
return c
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is only for classic App Engine adapters.
|
||||||
|
func ClassicContextFromContext(ctx netcontext.Context) appengine.Context {
|
||||||
|
return fromContext(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func withContext(parent netcontext.Context, c appengine.Context) netcontext.Context {
|
||||||
|
ctx := netcontext.WithValue(parent, &contextKey, c)
|
||||||
|
|
||||||
|
s := &basepb.StringProto{}
|
||||||
|
c.Call("__go__", "GetNamespace", &basepb.VoidProto{}, s, nil)
|
||||||
|
if ns := s.GetValue(); ns != "" {
|
||||||
|
ctx = NamespacedContext(ctx, ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
return ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
func IncomingHeaders(ctx netcontext.Context) http.Header {
|
||||||
|
if c := fromContext(ctx); c != nil {
|
||||||
|
if req, ok := c.Request().(*http.Request); ok {
|
||||||
|
return req.Header
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func WithContext(parent netcontext.Context, req *http.Request) netcontext.Context {
|
||||||
|
c := appengine.NewContext(req)
|
||||||
|
return withContext(parent, c)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
|
||||||
|
if f, ctx, ok := callOverrideFromContext(ctx); ok {
|
||||||
|
return f(ctx, service, method, in, out)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handle already-done contexts quickly.
|
||||||
|
select {
|
||||||
|
case <-ctx.Done():
|
||||||
|
return ctx.Err()
|
||||||
|
default:
|
||||||
|
}
|
||||||
|
|
||||||
|
c := fromContext(ctx)
|
||||||
|
if c == nil {
|
||||||
|
// Give a good error message rather than a panic lower down.
|
||||||
|
return errors.New("not an App Engine context")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply transaction modifications if we're in a transaction.
|
||||||
|
if t := transactionFromContext(ctx); t != nil {
|
||||||
|
if t.finished {
|
||||||
|
return errors.New("transaction context has expired")
|
||||||
|
}
|
||||||
|
applyTransaction(in, &t.transaction)
|
||||||
|
}
|
||||||
|
|
||||||
|
var opts *appengine_internal.CallOptions
|
||||||
|
if d, ok := ctx.Deadline(); ok {
|
||||||
|
opts = &appengine_internal.CallOptions{
|
||||||
|
Timeout: d.Sub(time.Now()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
err := c.Call(service, method, in, out, opts)
|
||||||
|
switch v := err.(type) {
|
||||||
|
case *appengine_internal.APIError:
|
||||||
|
return &APIError{
|
||||||
|
Service: v.Service,
|
||||||
|
Detail: v.Detail,
|
||||||
|
Code: v.Code,
|
||||||
|
}
|
||||||
|
case *appengine_internal.CallError:
|
||||||
|
return &CallError{
|
||||||
|
Detail: v.Detail,
|
||||||
|
Code: v.Code,
|
||||||
|
Timeout: v.Timeout,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func handleHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
|
panic("handleHTTP called; this should be impossible")
|
||||||
|
}
|
||||||
|
|
||||||
|
func logf(c appengine.Context, level int64, format string, args ...interface{}) {
|
||||||
|
var fn func(format string, args ...interface{})
|
||||||
|
switch level {
|
||||||
|
case 0:
|
||||||
|
fn = c.Debugf
|
||||||
|
case 1:
|
||||||
|
fn = c.Infof
|
||||||
|
case 2:
|
||||||
|
fn = c.Warningf
|
||||||
|
case 3:
|
||||||
|
fn = c.Errorf
|
||||||
|
case 4:
|
||||||
|
fn = c.Criticalf
|
||||||
|
default:
|
||||||
|
// This shouldn't happen.
|
||||||
|
fn = c.Criticalf
|
||||||
|
}
|
||||||
|
fn(format, args...)
|
||||||
|
}
|
101
vendor/google.golang.org/appengine/internal/api_common.go
generated
vendored
Normal file
101
vendor/google.golang.org/appengine/internal/api_common.go
generated
vendored
Normal file
|
@ -0,0 +1,101 @@
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/golang/protobuf/proto"
|
||||||
|
netcontext "golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CallOverrideFunc func(ctx netcontext.Context, service, method string, in, out proto.Message) error
|
||||||
|
|
||||||
|
var callOverrideKey = "holds []CallOverrideFunc"
|
||||||
|
|
||||||
|
func WithCallOverride(ctx netcontext.Context, f CallOverrideFunc) netcontext.Context {
|
||||||
|
// We avoid appending to any existing call override
|
||||||
|
// so we don't risk overwriting a popped stack below.
|
||||||
|
var cofs []CallOverrideFunc
|
||||||
|
if uf, ok := ctx.Value(&callOverrideKey).([]CallOverrideFunc); ok {
|
||||||
|
cofs = append(cofs, uf...)
|
||||||
|
}
|
||||||
|
cofs = append(cofs, f)
|
||||||
|
return netcontext.WithValue(ctx, &callOverrideKey, cofs)
|
||||||
|
}
|
||||||
|
|
||||||
|
func callOverrideFromContext(ctx netcontext.Context) (CallOverrideFunc, netcontext.Context, bool) {
|
||||||
|
cofs, _ := ctx.Value(&callOverrideKey).([]CallOverrideFunc)
|
||||||
|
if len(cofs) == 0 {
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
// We found a list of overrides; grab the last, and reconstitute a
|
||||||
|
// context that will hide it.
|
||||||
|
f := cofs[len(cofs)-1]
|
||||||
|
ctx = netcontext.WithValue(ctx, &callOverrideKey, cofs[:len(cofs)-1])
|
||||||
|
return f, ctx, true
|
||||||
|
}
|
||||||
|
|
||||||
|
type logOverrideFunc func(level int64, format string, args ...interface{})
|
||||||
|
|
||||||
|
var logOverrideKey = "holds a logOverrideFunc"
|
||||||
|
|
||||||
|
func WithLogOverride(ctx netcontext.Context, f logOverrideFunc) netcontext.Context {
|
||||||
|
return netcontext.WithValue(ctx, &logOverrideKey, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
var appIDOverrideKey = "holds a string, being the full app ID"
|
||||||
|
|
||||||
|
func WithAppIDOverride(ctx netcontext.Context, appID string) netcontext.Context {
|
||||||
|
return netcontext.WithValue(ctx, &appIDOverrideKey, appID)
|
||||||
|
}
|
||||||
|
|
||||||
|
var namespaceKey = "holds the namespace string"
|
||||||
|
|
||||||
|
func withNamespace(ctx netcontext.Context, ns string) netcontext.Context {
|
||||||
|
return netcontext.WithValue(ctx, &namespaceKey, ns)
|
||||||
|
}
|
||||||
|
|
||||||
|
func NamespaceFromContext(ctx netcontext.Context) string {
|
||||||
|
// If there's no namespace, return the empty string.
|
||||||
|
ns, _ := ctx.Value(&namespaceKey).(string)
|
||||||
|
return ns
|
||||||
|
}
|
||||||
|
|
||||||
|
// FullyQualifiedAppID returns the fully-qualified application ID.
|
||||||
|
// This may contain a partition prefix (e.g. "s~" for High Replication apps),
|
||||||
|
// or a domain prefix (e.g. "example.com:").
|
||||||
|
func FullyQualifiedAppID(ctx netcontext.Context) string {
|
||||||
|
if id, ok := ctx.Value(&appIDOverrideKey).(string); ok {
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
return fullyQualifiedAppID(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Logf(ctx netcontext.Context, level int64, format string, args ...interface{}) {
|
||||||
|
if f, ok := ctx.Value(&logOverrideKey).(logOverrideFunc); ok {
|
||||||
|
f(level, format, args...)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
logf(fromContext(ctx), level, format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NamespacedContext wraps a Context to support namespaces.
|
||||||
|
func NamespacedContext(ctx netcontext.Context, namespace string) netcontext.Context {
|
||||||
|
n := &namespacedContext{
|
||||||
|
namespace: namespace,
|
||||||
|
}
|
||||||
|
return withNamespace(WithCallOverride(ctx, n.call), namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
type namespacedContext struct {
|
||||||
|
namespace string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (n *namespacedContext) call(ctx netcontext.Context, service, method string, in, out proto.Message) error {
|
||||||
|
// Apply any namespace mods.
|
||||||
|
if mod, ok := NamespaceMods[service]; ok {
|
||||||
|
mod(in, n.namespace)
|
||||||
|
}
|
||||||
|
return Call(ctx, service, method, in, out)
|
||||||
|
}
|
28
vendor/google.golang.org/appengine/internal/app_id.go
generated
vendored
Normal file
28
vendor/google.golang.org/appengine/internal/app_id.go
generated
vendored
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func parseFullAppID(appid string) (partition, domain, displayID string) {
|
||||||
|
if i := strings.Index(appid, "~"); i != -1 {
|
||||||
|
partition, appid = appid[:i], appid[i+1:]
|
||||||
|
}
|
||||||
|
if i := strings.Index(appid, ":"); i != -1 {
|
||||||
|
domain, appid = appid[:i], appid[i+1:]
|
||||||
|
}
|
||||||
|
return partition, domain, appid
|
||||||
|
}
|
||||||
|
|
||||||
|
// appID returns "appid" or "domain.com:appid".
|
||||||
|
func appID(fullAppID string) string {
|
||||||
|
_, dom, dis := parseFullAppID(fullAppID)
|
||||||
|
if dom != "" {
|
||||||
|
return dom + ":" + dis
|
||||||
|
}
|
||||||
|
return dis
|
||||||
|
}
|
296
vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.pb.go
generated
vendored
Normal file
296
vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,296 @@
|
||||||
|
// Code generated by protoc-gen-go.
|
||||||
|
// source: google.golang.org/appengine/internal/app_identity/app_identity_service.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package app_identity is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
google.golang.org/appengine/internal/app_identity/app_identity_service.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
AppIdentityServiceError
|
||||||
|
SignForAppRequest
|
||||||
|
SignForAppResponse
|
||||||
|
GetPublicCertificateForAppRequest
|
||||||
|
PublicCertificate
|
||||||
|
GetPublicCertificateForAppResponse
|
||||||
|
GetServiceAccountNameRequest
|
||||||
|
GetServiceAccountNameResponse
|
||||||
|
GetAccessTokenRequest
|
||||||
|
GetAccessTokenResponse
|
||||||
|
GetDefaultGcsBucketNameRequest
|
||||||
|
GetDefaultGcsBucketNameResponse
|
||||||
|
*/
|
||||||
|
package app_identity
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
type AppIdentityServiceError_ErrorCode int32
|
||||||
|
|
||||||
|
const (
|
||||||
|
AppIdentityServiceError_SUCCESS AppIdentityServiceError_ErrorCode = 0
|
||||||
|
AppIdentityServiceError_UNKNOWN_SCOPE AppIdentityServiceError_ErrorCode = 9
|
||||||
|
AppIdentityServiceError_BLOB_TOO_LARGE AppIdentityServiceError_ErrorCode = 1000
|
||||||
|
AppIdentityServiceError_DEADLINE_EXCEEDED AppIdentityServiceError_ErrorCode = 1001
|
||||||
|
AppIdentityServiceError_NOT_A_VALID_APP AppIdentityServiceError_ErrorCode = 1002
|
||||||
|
AppIdentityServiceError_UNKNOWN_ERROR AppIdentityServiceError_ErrorCode = 1003
|
||||||
|
AppIdentityServiceError_NOT_ALLOWED AppIdentityServiceError_ErrorCode = 1005
|
||||||
|
AppIdentityServiceError_NOT_IMPLEMENTED AppIdentityServiceError_ErrorCode = 1006
|
||||||
|
)
|
||||||
|
|
||||||
|
var AppIdentityServiceError_ErrorCode_name = map[int32]string{
|
||||||
|
0: "SUCCESS",
|
||||||
|
9: "UNKNOWN_SCOPE",
|
||||||
|
1000: "BLOB_TOO_LARGE",
|
||||||
|
1001: "DEADLINE_EXCEEDED",
|
||||||
|
1002: "NOT_A_VALID_APP",
|
||||||
|
1003: "UNKNOWN_ERROR",
|
||||||
|
1005: "NOT_ALLOWED",
|
||||||
|
1006: "NOT_IMPLEMENTED",
|
||||||
|
}
|
||||||
|
var AppIdentityServiceError_ErrorCode_value = map[string]int32{
|
||||||
|
"SUCCESS": 0,
|
||||||
|
"UNKNOWN_SCOPE": 9,
|
||||||
|
"BLOB_TOO_LARGE": 1000,
|
||||||
|
"DEADLINE_EXCEEDED": 1001,
|
||||||
|
"NOT_A_VALID_APP": 1002,
|
||||||
|
"UNKNOWN_ERROR": 1003,
|
||||||
|
"NOT_ALLOWED": 1005,
|
||||||
|
"NOT_IMPLEMENTED": 1006,
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x AppIdentityServiceError_ErrorCode) Enum() *AppIdentityServiceError_ErrorCode {
|
||||||
|
p := new(AppIdentityServiceError_ErrorCode)
|
||||||
|
*p = x
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
func (x AppIdentityServiceError_ErrorCode) String() string {
|
||||||
|
return proto.EnumName(AppIdentityServiceError_ErrorCode_name, int32(x))
|
||||||
|
}
|
||||||
|
func (x *AppIdentityServiceError_ErrorCode) UnmarshalJSON(data []byte) error {
|
||||||
|
value, err := proto.UnmarshalJSONEnum(AppIdentityServiceError_ErrorCode_value, data, "AppIdentityServiceError_ErrorCode")
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
*x = AppIdentityServiceError_ErrorCode(value)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type AppIdentityServiceError struct {
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *AppIdentityServiceError) Reset() { *m = AppIdentityServiceError{} }
|
||||||
|
func (m *AppIdentityServiceError) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*AppIdentityServiceError) ProtoMessage() {}
|
||||||
|
|
||||||
|
type SignForAppRequest struct {
|
||||||
|
BytesToSign []byte `protobuf:"bytes,1,opt,name=bytes_to_sign" json:"bytes_to_sign,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SignForAppRequest) Reset() { *m = SignForAppRequest{} }
|
||||||
|
func (m *SignForAppRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*SignForAppRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *SignForAppRequest) GetBytesToSign() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.BytesToSign
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type SignForAppResponse struct {
|
||||||
|
KeyName *string `protobuf:"bytes,1,opt,name=key_name" json:"key_name,omitempty"`
|
||||||
|
SignatureBytes []byte `protobuf:"bytes,2,opt,name=signature_bytes" json:"signature_bytes,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SignForAppResponse) Reset() { *m = SignForAppResponse{} }
|
||||||
|
func (m *SignForAppResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*SignForAppResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *SignForAppResponse) GetKeyName() string {
|
||||||
|
if m != nil && m.KeyName != nil {
|
||||||
|
return *m.KeyName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SignForAppResponse) GetSignatureBytes() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.SignatureBytes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPublicCertificateForAppRequest struct {
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetPublicCertificateForAppRequest) Reset() { *m = GetPublicCertificateForAppRequest{} }
|
||||||
|
func (m *GetPublicCertificateForAppRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetPublicCertificateForAppRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
type PublicCertificate struct {
|
||||||
|
KeyName *string `protobuf:"bytes,1,opt,name=key_name" json:"key_name,omitempty"`
|
||||||
|
X509CertificatePem *string `protobuf:"bytes,2,opt,name=x509_certificate_pem" json:"x509_certificate_pem,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PublicCertificate) Reset() { *m = PublicCertificate{} }
|
||||||
|
func (m *PublicCertificate) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*PublicCertificate) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *PublicCertificate) GetKeyName() string {
|
||||||
|
if m != nil && m.KeyName != nil {
|
||||||
|
return *m.KeyName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *PublicCertificate) GetX509CertificatePem() string {
|
||||||
|
if m != nil && m.X509CertificatePem != nil {
|
||||||
|
return *m.X509CertificatePem
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetPublicCertificateForAppResponse struct {
|
||||||
|
PublicCertificateList []*PublicCertificate `protobuf:"bytes,1,rep,name=public_certificate_list" json:"public_certificate_list,omitempty"`
|
||||||
|
MaxClientCacheTimeInSecond *int64 `protobuf:"varint,2,opt,name=max_client_cache_time_in_second" json:"max_client_cache_time_in_second,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetPublicCertificateForAppResponse) Reset() { *m = GetPublicCertificateForAppResponse{} }
|
||||||
|
func (m *GetPublicCertificateForAppResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetPublicCertificateForAppResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *GetPublicCertificateForAppResponse) GetPublicCertificateList() []*PublicCertificate {
|
||||||
|
if m != nil {
|
||||||
|
return m.PublicCertificateList
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetPublicCertificateForAppResponse) GetMaxClientCacheTimeInSecond() int64 {
|
||||||
|
if m != nil && m.MaxClientCacheTimeInSecond != nil {
|
||||||
|
return *m.MaxClientCacheTimeInSecond
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetServiceAccountNameRequest struct {
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetServiceAccountNameRequest) Reset() { *m = GetServiceAccountNameRequest{} }
|
||||||
|
func (m *GetServiceAccountNameRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetServiceAccountNameRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
type GetServiceAccountNameResponse struct {
|
||||||
|
ServiceAccountName *string `protobuf:"bytes,1,opt,name=service_account_name" json:"service_account_name,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetServiceAccountNameResponse) Reset() { *m = GetServiceAccountNameResponse{} }
|
||||||
|
func (m *GetServiceAccountNameResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetServiceAccountNameResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *GetServiceAccountNameResponse) GetServiceAccountName() string {
|
||||||
|
if m != nil && m.ServiceAccountName != nil {
|
||||||
|
return *m.ServiceAccountName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetAccessTokenRequest struct {
|
||||||
|
Scope []string `protobuf:"bytes,1,rep,name=scope" json:"scope,omitempty"`
|
||||||
|
ServiceAccountId *int64 `protobuf:"varint,2,opt,name=service_account_id" json:"service_account_id,omitempty"`
|
||||||
|
ServiceAccountName *string `protobuf:"bytes,3,opt,name=service_account_name" json:"service_account_name,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenRequest) Reset() { *m = GetAccessTokenRequest{} }
|
||||||
|
func (m *GetAccessTokenRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetAccessTokenRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenRequest) GetScope() []string {
|
||||||
|
if m != nil {
|
||||||
|
return m.Scope
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenRequest) GetServiceAccountId() int64 {
|
||||||
|
if m != nil && m.ServiceAccountId != nil {
|
||||||
|
return *m.ServiceAccountId
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenRequest) GetServiceAccountName() string {
|
||||||
|
if m != nil && m.ServiceAccountName != nil {
|
||||||
|
return *m.ServiceAccountName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetAccessTokenResponse struct {
|
||||||
|
AccessToken *string `protobuf:"bytes,1,opt,name=access_token" json:"access_token,omitempty"`
|
||||||
|
ExpirationTime *int64 `protobuf:"varint,2,opt,name=expiration_time" json:"expiration_time,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenResponse) Reset() { *m = GetAccessTokenResponse{} }
|
||||||
|
func (m *GetAccessTokenResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetAccessTokenResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenResponse) GetAccessToken() string {
|
||||||
|
if m != nil && m.AccessToken != nil {
|
||||||
|
return *m.AccessToken
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetAccessTokenResponse) GetExpirationTime() int64 {
|
||||||
|
if m != nil && m.ExpirationTime != nil {
|
||||||
|
return *m.ExpirationTime
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetDefaultGcsBucketNameRequest struct {
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetDefaultGcsBucketNameRequest) Reset() { *m = GetDefaultGcsBucketNameRequest{} }
|
||||||
|
func (m *GetDefaultGcsBucketNameRequest) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetDefaultGcsBucketNameRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
type GetDefaultGcsBucketNameResponse struct {
|
||||||
|
DefaultGcsBucketName *string `protobuf:"bytes,1,opt,name=default_gcs_bucket_name" json:"default_gcs_bucket_name,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *GetDefaultGcsBucketNameResponse) Reset() { *m = GetDefaultGcsBucketNameResponse{} }
|
||||||
|
func (m *GetDefaultGcsBucketNameResponse) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*GetDefaultGcsBucketNameResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *GetDefaultGcsBucketNameResponse) GetDefaultGcsBucketName() string {
|
||||||
|
if m != nil && m.DefaultGcsBucketName != nil {
|
||||||
|
return *m.DefaultGcsBucketName
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
}
|
64
vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto
generated
vendored
Normal file
64
vendor/google.golang.org/appengine/internal/app_identity/app_identity_service.proto
generated
vendored
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
option go_package = "app_identity";
|
||||||
|
|
||||||
|
package appengine;
|
||||||
|
|
||||||
|
message AppIdentityServiceError {
|
||||||
|
enum ErrorCode {
|
||||||
|
SUCCESS = 0;
|
||||||
|
UNKNOWN_SCOPE = 9;
|
||||||
|
BLOB_TOO_LARGE = 1000;
|
||||||
|
DEADLINE_EXCEEDED = 1001;
|
||||||
|
NOT_A_VALID_APP = 1002;
|
||||||
|
UNKNOWN_ERROR = 1003;
|
||||||
|
NOT_ALLOWED = 1005;
|
||||||
|
NOT_IMPLEMENTED = 1006;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignForAppRequest {
|
||||||
|
optional bytes bytes_to_sign = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message SignForAppResponse {
|
||||||
|
optional string key_name = 1;
|
||||||
|
optional bytes signature_bytes = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPublicCertificateForAppRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message PublicCertificate {
|
||||||
|
optional string key_name = 1;
|
||||||
|
optional string x509_certificate_pem = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetPublicCertificateForAppResponse {
|
||||||
|
repeated PublicCertificate public_certificate_list = 1;
|
||||||
|
optional int64 max_client_cache_time_in_second = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServiceAccountNameRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetServiceAccountNameResponse {
|
||||||
|
optional string service_account_name = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAccessTokenRequest {
|
||||||
|
repeated string scope = 1;
|
||||||
|
optional int64 service_account_id = 2;
|
||||||
|
optional string service_account_name = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetAccessTokenResponse {
|
||||||
|
optional string access_token = 1;
|
||||||
|
optional int64 expiration_time = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetDefaultGcsBucketNameRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetDefaultGcsBucketNameResponse {
|
||||||
|
optional string default_gcs_bucket_name = 1;
|
||||||
|
}
|
133
vendor/google.golang.org/appengine/internal/base/api_base.pb.go
generated
vendored
Normal file
133
vendor/google.golang.org/appengine/internal/base/api_base.pb.go
generated
vendored
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
// Code generated by protoc-gen-go.
|
||||||
|
// source: google.golang.org/appengine/internal/base/api_base.proto
|
||||||
|
// DO NOT EDIT!
|
||||||
|
|
||||||
|
/*
|
||||||
|
Package base is a generated protocol buffer package.
|
||||||
|
|
||||||
|
It is generated from these files:
|
||||||
|
google.golang.org/appengine/internal/base/api_base.proto
|
||||||
|
|
||||||
|
It has these top-level messages:
|
||||||
|
StringProto
|
||||||
|
Integer32Proto
|
||||||
|
Integer64Proto
|
||||||
|
BoolProto
|
||||||
|
DoubleProto
|
||||||
|
BytesProto
|
||||||
|
VoidProto
|
||||||
|
*/
|
||||||
|
package base
|
||||||
|
|
||||||
|
import proto "github.com/golang/protobuf/proto"
|
||||||
|
import fmt "fmt"
|
||||||
|
import math "math"
|
||||||
|
|
||||||
|
// Reference imports to suppress errors if they are not otherwise used.
|
||||||
|
var _ = proto.Marshal
|
||||||
|
var _ = fmt.Errorf
|
||||||
|
var _ = math.Inf
|
||||||
|
|
||||||
|
type StringProto struct {
|
||||||
|
Value *string `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *StringProto) Reset() { *m = StringProto{} }
|
||||||
|
func (m *StringProto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*StringProto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *StringProto) GetValue() string {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type Integer32Proto struct {
|
||||||
|
Value *int32 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Integer32Proto) Reset() { *m = Integer32Proto{} }
|
||||||
|
func (m *Integer32Proto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Integer32Proto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Integer32Proto) GetValue() int32 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type Integer64Proto struct {
|
||||||
|
Value *int64 `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Integer64Proto) Reset() { *m = Integer64Proto{} }
|
||||||
|
func (m *Integer64Proto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*Integer64Proto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *Integer64Proto) GetValue() int64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type BoolProto struct {
|
||||||
|
Value *bool `protobuf:"varint,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BoolProto) Reset() { *m = BoolProto{} }
|
||||||
|
func (m *BoolProto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*BoolProto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *BoolProto) GetValue() bool {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
type DoubleProto struct {
|
||||||
|
Value *float64 `protobuf:"fixed64,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *DoubleProto) Reset() { *m = DoubleProto{} }
|
||||||
|
func (m *DoubleProto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*DoubleProto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *DoubleProto) GetValue() float64 {
|
||||||
|
if m != nil && m.Value != nil {
|
||||||
|
return *m.Value
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type BytesProto struct {
|
||||||
|
Value []byte `protobuf:"bytes,1,req,name=value" json:"value,omitempty"`
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *BytesProto) Reset() { *m = BytesProto{} }
|
||||||
|
func (m *BytesProto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*BytesProto) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (m *BytesProto) GetValue() []byte {
|
||||||
|
if m != nil {
|
||||||
|
return m.Value
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type VoidProto struct {
|
||||||
|
XXX_unrecognized []byte `json:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *VoidProto) Reset() { *m = VoidProto{} }
|
||||||
|
func (m *VoidProto) String() string { return proto.CompactTextString(m) }
|
||||||
|
func (*VoidProto) ProtoMessage() {}
|
33
vendor/google.golang.org/appengine/internal/base/api_base.proto
generated
vendored
Normal file
33
vendor/google.golang.org/appengine/internal/base/api_base.proto
generated
vendored
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
// Built-in base types for API calls. Primarily useful as return types.
|
||||||
|
|
||||||
|
syntax = "proto2";
|
||||||
|
option go_package = "base";
|
||||||
|
|
||||||
|
package appengine.base;
|
||||||
|
|
||||||
|
message StringProto {
|
||||||
|
required string value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Integer32Proto {
|
||||||
|
required int32 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Integer64Proto {
|
||||||
|
required int64 value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BoolProto {
|
||||||
|
required bool value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DoubleProto {
|
||||||
|
required double value = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message BytesProto {
|
||||||
|
required bytes value = 1 [ctype=CORD];
|
||||||
|
}
|
||||||
|
|
||||||
|
message VoidProto {
|
||||||
|
}
|
2778
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go
generated
vendored
Normal file
2778
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.pb.go
generated
vendored
Normal file
File diff suppressed because it is too large
Load diff
541
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto
generated
vendored
Normal file
541
vendor/google.golang.org/appengine/internal/datastore/datastore_v3.proto
generated
vendored
Normal file
|
@ -0,0 +1,541 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
option go_package = "datastore";
|
||||||
|
|
||||||
|
package appengine;
|
||||||
|
|
||||||
|
message Action{}
|
||||||
|
|
||||||
|
message PropertyValue {
|
||||||
|
optional int64 int64Value = 1;
|
||||||
|
optional bool booleanValue = 2;
|
||||||
|
optional string stringValue = 3;
|
||||||
|
optional double doubleValue = 4;
|
||||||
|
|
||||||
|
optional group PointValue = 5 {
|
||||||
|
required double x = 6;
|
||||||
|
required double y = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional group UserValue = 8 {
|
||||||
|
required string email = 9;
|
||||||
|
required string auth_domain = 10;
|
||||||
|
optional string nickname = 11;
|
||||||
|
optional string federated_identity = 21;
|
||||||
|
optional string federated_provider = 22;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional group ReferenceValue = 12 {
|
||||||
|
required string app = 13;
|
||||||
|
optional string name_space = 20;
|
||||||
|
repeated group PathElement = 14 {
|
||||||
|
required string type = 15;
|
||||||
|
optional int64 id = 16;
|
||||||
|
optional string name = 17;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Property {
|
||||||
|
enum Meaning {
|
||||||
|
NO_MEANING = 0;
|
||||||
|
BLOB = 14;
|
||||||
|
TEXT = 15;
|
||||||
|
BYTESTRING = 16;
|
||||||
|
|
||||||
|
ATOM_CATEGORY = 1;
|
||||||
|
ATOM_LINK = 2;
|
||||||
|
ATOM_TITLE = 3;
|
||||||
|
ATOM_CONTENT = 4;
|
||||||
|
ATOM_SUMMARY = 5;
|
||||||
|
ATOM_AUTHOR = 6;
|
||||||
|
|
||||||
|
GD_WHEN = 7;
|
||||||
|
GD_EMAIL = 8;
|
||||||
|
GEORSS_POINT = 9;
|
||||||
|
GD_IM = 10;
|
||||||
|
|
||||||
|
GD_PHONENUMBER = 11;
|
||||||
|
GD_POSTALADDRESS = 12;
|
||||||
|
|
||||||
|
GD_RATING = 13;
|
||||||
|
|
||||||
|
BLOBKEY = 17;
|
||||||
|
ENTITY_PROTO = 19;
|
||||||
|
|
||||||
|
INDEX_VALUE = 18;
|
||||||
|
};
|
||||||
|
|
||||||
|
optional Meaning meaning = 1 [default = NO_MEANING];
|
||||||
|
optional string meaning_uri = 2;
|
||||||
|
|
||||||
|
required string name = 3;
|
||||||
|
|
||||||
|
required PropertyValue value = 5;
|
||||||
|
|
||||||
|
required bool multiple = 4;
|
||||||
|
|
||||||
|
optional bool searchable = 6 [default=false];
|
||||||
|
|
||||||
|
enum FtsTokenizationOption {
|
||||||
|
HTML = 1;
|
||||||
|
ATOM = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional FtsTokenizationOption fts_tokenization_option = 8;
|
||||||
|
|
||||||
|
optional string locale = 9 [default = "en"];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Path {
|
||||||
|
repeated group Element = 1 {
|
||||||
|
required string type = 2;
|
||||||
|
optional int64 id = 3;
|
||||||
|
optional string name = 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Reference {
|
||||||
|
required string app = 13;
|
||||||
|
optional string name_space = 20;
|
||||||
|
required Path path = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
message User {
|
||||||
|
required string email = 1;
|
||||||
|
required string auth_domain = 2;
|
||||||
|
optional string nickname = 3;
|
||||||
|
optional string federated_identity = 6;
|
||||||
|
optional string federated_provider = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message EntityProto {
|
||||||
|
required Reference key = 13;
|
||||||
|
required Path entity_group = 16;
|
||||||
|
optional User owner = 17;
|
||||||
|
|
||||||
|
enum Kind {
|
||||||
|
GD_CONTACT = 1;
|
||||||
|
GD_EVENT = 2;
|
||||||
|
GD_MESSAGE = 3;
|
||||||
|
}
|
||||||
|
optional Kind kind = 4;
|
||||||
|
optional string kind_uri = 5;
|
||||||
|
|
||||||
|
repeated Property property = 14;
|
||||||
|
repeated Property raw_property = 15;
|
||||||
|
|
||||||
|
optional int32 rank = 18;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CompositeProperty {
|
||||||
|
required int64 index_id = 1;
|
||||||
|
repeated string value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Index {
|
||||||
|
required string entity_type = 1;
|
||||||
|
required bool ancestor = 5;
|
||||||
|
repeated group Property = 2 {
|
||||||
|
required string name = 3;
|
||||||
|
enum Direction {
|
||||||
|
ASCENDING = 1;
|
||||||
|
DESCENDING = 2;
|
||||||
|
}
|
||||||
|
optional Direction direction = 4 [default = ASCENDING];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message CompositeIndex {
|
||||||
|
required string app_id = 1;
|
||||||
|
required int64 id = 2;
|
||||||
|
required Index definition = 3;
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
WRITE_ONLY = 1;
|
||||||
|
READ_WRITE = 2;
|
||||||
|
DELETED = 3;
|
||||||
|
ERROR = 4;
|
||||||
|
}
|
||||||
|
required State state = 4;
|
||||||
|
|
||||||
|
optional bool only_use_if_required = 6 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message IndexPostfix {
|
||||||
|
message IndexValue {
|
||||||
|
required string property_name = 1;
|
||||||
|
required PropertyValue value = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated IndexValue index_value = 1;
|
||||||
|
|
||||||
|
optional Reference key = 2;
|
||||||
|
|
||||||
|
optional bool before = 3 [default=true];
|
||||||
|
}
|
||||||
|
|
||||||
|
message IndexPosition {
|
||||||
|
optional string key = 1;
|
||||||
|
|
||||||
|
optional bool before = 2 [default=true];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Snapshot {
|
||||||
|
enum Status {
|
||||||
|
INACTIVE = 0;
|
||||||
|
ACTIVE = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
required int64 ts = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message InternalHeader {
|
||||||
|
optional string qos = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Transaction {
|
||||||
|
optional InternalHeader header = 4;
|
||||||
|
required fixed64 handle = 1;
|
||||||
|
required string app = 2;
|
||||||
|
optional bool mark_changes = 3 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message Query {
|
||||||
|
optional InternalHeader header = 39;
|
||||||
|
|
||||||
|
required string app = 1;
|
||||||
|
optional string name_space = 29;
|
||||||
|
|
||||||
|
optional string kind = 3;
|
||||||
|
optional Reference ancestor = 17;
|
||||||
|
|
||||||
|
repeated group Filter = 4 {
|
||||||
|
enum Operator {
|
||||||
|
LESS_THAN = 1;
|
||||||
|
LESS_THAN_OR_EQUAL = 2;
|
||||||
|
GREATER_THAN = 3;
|
||||||
|
GREATER_THAN_OR_EQUAL = 4;
|
||||||
|
EQUAL = 5;
|
||||||
|
IN = 6;
|
||||||
|
EXISTS = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
required Operator op = 6;
|
||||||
|
repeated Property property = 14;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional string search_query = 8;
|
||||||
|
|
||||||
|
repeated group Order = 9 {
|
||||||
|
enum Direction {
|
||||||
|
ASCENDING = 1;
|
||||||
|
DESCENDING = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
required string property = 10;
|
||||||
|
optional Direction direction = 11 [default = ASCENDING];
|
||||||
|
}
|
||||||
|
|
||||||
|
enum Hint {
|
||||||
|
ORDER_FIRST = 1;
|
||||||
|
ANCESTOR_FIRST = 2;
|
||||||
|
FILTER_FIRST = 3;
|
||||||
|
}
|
||||||
|
optional Hint hint = 18;
|
||||||
|
|
||||||
|
optional int32 count = 23;
|
||||||
|
|
||||||
|
optional int32 offset = 12 [default = 0];
|
||||||
|
|
||||||
|
optional int32 limit = 16;
|
||||||
|
|
||||||
|
optional CompiledCursor compiled_cursor = 30;
|
||||||
|
optional CompiledCursor end_compiled_cursor = 31;
|
||||||
|
|
||||||
|
repeated CompositeIndex composite_index = 19;
|
||||||
|
|
||||||
|
optional bool require_perfect_plan = 20 [default = false];
|
||||||
|
|
||||||
|
optional bool keys_only = 21 [default = false];
|
||||||
|
|
||||||
|
optional Transaction transaction = 22;
|
||||||
|
|
||||||
|
optional bool compile = 25 [default = false];
|
||||||
|
|
||||||
|
optional int64 failover_ms = 26;
|
||||||
|
|
||||||
|
optional bool strong = 32;
|
||||||
|
|
||||||
|
repeated string property_name = 33;
|
||||||
|
|
||||||
|
repeated string group_by_property_name = 34;
|
||||||
|
|
||||||
|
optional bool distinct = 24;
|
||||||
|
|
||||||
|
optional int64 min_safe_time_seconds = 35;
|
||||||
|
|
||||||
|
repeated string safe_replica_name = 36;
|
||||||
|
|
||||||
|
optional bool persist_offset = 37 [default=false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message CompiledQuery {
|
||||||
|
required group PrimaryScan = 1 {
|
||||||
|
optional string index_name = 2;
|
||||||
|
|
||||||
|
optional string start_key = 3;
|
||||||
|
optional bool start_inclusive = 4;
|
||||||
|
optional string end_key = 5;
|
||||||
|
optional bool end_inclusive = 6;
|
||||||
|
|
||||||
|
repeated string start_postfix_value = 22;
|
||||||
|
repeated string end_postfix_value = 23;
|
||||||
|
|
||||||
|
optional int64 end_unapplied_log_timestamp_us = 19;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated group MergeJoinScan = 7 {
|
||||||
|
required string index_name = 8;
|
||||||
|
|
||||||
|
repeated string prefix_value = 9;
|
||||||
|
|
||||||
|
optional bool value_prefix = 20 [default=false];
|
||||||
|
}
|
||||||
|
|
||||||
|
optional Index index_def = 21;
|
||||||
|
|
||||||
|
optional int32 offset = 10 [default = 0];
|
||||||
|
|
||||||
|
optional int32 limit = 11;
|
||||||
|
|
||||||
|
required bool keys_only = 12;
|
||||||
|
|
||||||
|
repeated string property_name = 24;
|
||||||
|
|
||||||
|
optional int32 distinct_infix_size = 25;
|
||||||
|
|
||||||
|
optional group EntityFilter = 13 {
|
||||||
|
optional bool distinct = 14 [default=false];
|
||||||
|
|
||||||
|
optional string kind = 17;
|
||||||
|
optional Reference ancestor = 18;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message CompiledCursor {
|
||||||
|
optional group Position = 2 {
|
||||||
|
optional string start_key = 27;
|
||||||
|
|
||||||
|
repeated group IndexValue = 29 {
|
||||||
|
optional string property = 30;
|
||||||
|
required PropertyValue value = 31;
|
||||||
|
}
|
||||||
|
|
||||||
|
optional Reference key = 32;
|
||||||
|
|
||||||
|
optional bool start_inclusive = 28 [default=true];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Cursor {
|
||||||
|
required fixed64 cursor = 1;
|
||||||
|
|
||||||
|
optional string app = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Error {
|
||||||
|
enum ErrorCode {
|
||||||
|
BAD_REQUEST = 1;
|
||||||
|
CONCURRENT_TRANSACTION = 2;
|
||||||
|
INTERNAL_ERROR = 3;
|
||||||
|
NEED_INDEX = 4;
|
||||||
|
TIMEOUT = 5;
|
||||||
|
PERMISSION_DENIED = 6;
|
||||||
|
BIGTABLE_ERROR = 7;
|
||||||
|
COMMITTED_BUT_STILL_APPLYING = 8;
|
||||||
|
CAPABILITY_DISABLED = 9;
|
||||||
|
TRY_ALTERNATE_BACKEND = 10;
|
||||||
|
SAFE_TIME_TOO_OLD = 11;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message Cost {
|
||||||
|
optional int32 index_writes = 1;
|
||||||
|
optional int32 index_write_bytes = 2;
|
||||||
|
optional int32 entity_writes = 3;
|
||||||
|
optional int32 entity_write_bytes = 4;
|
||||||
|
optional group CommitCost = 5 {
|
||||||
|
optional int32 requested_entity_puts = 6;
|
||||||
|
optional int32 requested_entity_deletes = 7;
|
||||||
|
};
|
||||||
|
optional int32 approximate_storage_delta = 8;
|
||||||
|
optional int32 id_sequence_updates = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetRequest {
|
||||||
|
optional InternalHeader header = 6;
|
||||||
|
|
||||||
|
repeated Reference key = 1;
|
||||||
|
optional Transaction transaction = 2;
|
||||||
|
|
||||||
|
optional int64 failover_ms = 3;
|
||||||
|
|
||||||
|
optional bool strong = 4;
|
||||||
|
|
||||||
|
optional bool allow_deferred = 5 [default=false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetResponse {
|
||||||
|
repeated group Entity = 1 {
|
||||||
|
optional EntityProto entity = 2;
|
||||||
|
optional Reference key = 4;
|
||||||
|
|
||||||
|
optional int64 version = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
repeated Reference deferred = 5;
|
||||||
|
|
||||||
|
optional bool in_order = 6 [default=true];
|
||||||
|
}
|
||||||
|
|
||||||
|
message PutRequest {
|
||||||
|
optional InternalHeader header = 11;
|
||||||
|
|
||||||
|
repeated EntityProto entity = 1;
|
||||||
|
optional Transaction transaction = 2;
|
||||||
|
repeated CompositeIndex composite_index = 3;
|
||||||
|
|
||||||
|
optional bool trusted = 4 [default = false];
|
||||||
|
|
||||||
|
optional bool force = 7 [default = false];
|
||||||
|
|
||||||
|
optional bool mark_changes = 8 [default = false];
|
||||||
|
repeated Snapshot snapshot = 9;
|
||||||
|
|
||||||
|
enum AutoIdPolicy {
|
||||||
|
CURRENT = 0;
|
||||||
|
SEQUENTIAL = 1;
|
||||||
|
}
|
||||||
|
optional AutoIdPolicy auto_id_policy = 10 [default = CURRENT];
|
||||||
|
}
|
||||||
|
|
||||||
|
message PutResponse {
|
||||||
|
repeated Reference key = 1;
|
||||||
|
optional Cost cost = 2;
|
||||||
|
repeated int64 version = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TouchRequest {
|
||||||
|
optional InternalHeader header = 10;
|
||||||
|
|
||||||
|
repeated Reference key = 1;
|
||||||
|
repeated CompositeIndex composite_index = 2;
|
||||||
|
optional bool force = 3 [default = false];
|
||||||
|
repeated Snapshot snapshot = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message TouchResponse {
|
||||||
|
optional Cost cost = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteRequest {
|
||||||
|
optional InternalHeader header = 10;
|
||||||
|
|
||||||
|
repeated Reference key = 6;
|
||||||
|
optional Transaction transaction = 5;
|
||||||
|
|
||||||
|
optional bool trusted = 4 [default = false];
|
||||||
|
|
||||||
|
optional bool force = 7 [default = false];
|
||||||
|
|
||||||
|
optional bool mark_changes = 8 [default = false];
|
||||||
|
repeated Snapshot snapshot = 9;
|
||||||
|
}
|
||||||
|
|
||||||
|
message DeleteResponse {
|
||||||
|
optional Cost cost = 1;
|
||||||
|
repeated int64 version = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message NextRequest {
|
||||||
|
optional InternalHeader header = 5;
|
||||||
|
|
||||||
|
required Cursor cursor = 1;
|
||||||
|
optional int32 count = 2;
|
||||||
|
|
||||||
|
optional int32 offset = 4 [default = 0];
|
||||||
|
|
||||||
|
optional bool compile = 3 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message QueryResult {
|
||||||
|
optional Cursor cursor = 1;
|
||||||
|
|
||||||
|
repeated EntityProto result = 2;
|
||||||
|
|
||||||
|
optional int32 skipped_results = 7;
|
||||||
|
|
||||||
|
required bool more_results = 3;
|
||||||
|
|
||||||
|
optional bool keys_only = 4;
|
||||||
|
|
||||||
|
optional bool index_only = 9;
|
||||||
|
|
||||||
|
optional bool small_ops = 10;
|
||||||
|
|
||||||
|
optional CompiledQuery compiled_query = 5;
|
||||||
|
|
||||||
|
optional CompiledCursor compiled_cursor = 6;
|
||||||
|
|
||||||
|
repeated CompositeIndex index = 8;
|
||||||
|
|
||||||
|
repeated int64 version = 11;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AllocateIdsRequest {
|
||||||
|
optional InternalHeader header = 4;
|
||||||
|
|
||||||
|
optional Reference model_key = 1;
|
||||||
|
|
||||||
|
optional int64 size = 2;
|
||||||
|
|
||||||
|
optional int64 max = 3;
|
||||||
|
|
||||||
|
repeated Reference reserve = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AllocateIdsResponse {
|
||||||
|
required int64 start = 1;
|
||||||
|
required int64 end = 2;
|
||||||
|
optional Cost cost = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message CompositeIndices {
|
||||||
|
repeated CompositeIndex index = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddActionsRequest {
|
||||||
|
optional InternalHeader header = 3;
|
||||||
|
|
||||||
|
required Transaction transaction = 1;
|
||||||
|
repeated Action action = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AddActionsResponse {
|
||||||
|
}
|
||||||
|
|
||||||
|
message BeginTransactionRequest {
|
||||||
|
optional InternalHeader header = 3;
|
||||||
|
|
||||||
|
required string app = 1;
|
||||||
|
optional bool allow_multiple_eg = 2 [default = false];
|
||||||
|
}
|
||||||
|
|
||||||
|
message CommitResponse {
|
||||||
|
optional Cost cost = 1;
|
||||||
|
|
||||||
|
repeated group Version = 3 {
|
||||||
|
required Reference root_entity_key = 4;
|
||||||
|
required int64 version = 5;
|
||||||
|
}
|
||||||
|
}
|
14
vendor/google.golang.org/appengine/internal/identity.go
generated
vendored
Normal file
14
vendor/google.golang.org/appengine/internal/identity.go
generated
vendored
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
// Copyright 2011 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import netcontext "golang.org/x/net/context"
|
||||||
|
|
||||||
|
// These functions are implementations of the wrapper functions
|
||||||
|
// in ../appengine/identity.go. See that file for commentary.
|
||||||
|
|
||||||
|
func AppID(c netcontext.Context) string {
|
||||||
|
return appID(FullyQualifiedAppID(c))
|
||||||
|
}
|
27
vendor/google.golang.org/appengine/internal/identity_classic.go
generated
vendored
Normal file
27
vendor/google.golang.org/appengine/internal/identity_classic.go
generated
vendored
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
// Copyright 2015 Google Inc. All rights reserved.
|
||||||
|
// Use of this source code is governed by the Apache 2.0
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
// +build appengine
|
||||||
|
|
||||||
|
package internal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"appengine"
|
||||||
|
|
||||||
|
netcontext "golang.org/x/net/context"
|
||||||
|
)
|
||||||
|
|
||||||
|
func DefaultVersionHostname(ctx netcontext.Context) string {
|
||||||
|
return appengine.DefaultVersionHostname(fromContext(ctx))
|
||||||
|
}
|
||||||
|
|
||||||
|
func RequestID(ctx netcontext.Context) string { return appengine.RequestID(fromContext(ctx)) }
|
||||||
|
func Datacenter(_ netcontext.Context) string { return appengine.Datacenter() }
|
||||||
|
func ServerSoftware() string { return appengine.ServerSoftware() }
|
||||||
|
func ModuleName(ctx netcontext.Context) string { return appengine.ModuleName(fromContext(ctx)) }
|
||||||
|
func VersionID(ctx netcontext.Context) string { return appengine.VersionID(fromContext(ctx)) }
|
||||||
|
func InstanceID() string { return appengine.InstanceID() }
|
||||||
|
func IsDevAppServer() bool { return appengine.IsDevAppServer() }
|
||||||
|
|
||||||
|
func fullyQualifiedAppID(ctx netcontext.Context) string { return fromContext(ctx).FullyQualifiedAppID() }
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue