vendor: update all dependencies to latest versions

This commit is contained in:
Nick Craig-Wood
2017-09-30 15:27:27 +01:00
parent 911d121bb9
commit b017fcfe9a
3048 changed files with 537055 additions and 189679 deletions
+117 -17
View File
@@ -174,26 +174,126 @@ func typeHeader(contentType string) textproto.MIMEHeader {
// 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
// MediaBuffer. Otherwise, media will be returned as a Reader.
//
// If chunkSize is zero, media is returned as the first value, and the other
// two return values are nil, true.
//
// Otherwise, a MediaBuffer is returned, along with a bool indicating whether the
// contents of media fit in a single chunk.
//
// 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, *MediaBuffer) {
func PrepareUpload(media io.Reader, chunkSize int) (r io.Reader, mb *MediaBuffer, singleChunk bool) {
if chunkSize == 0 { // do not chunk
return media, nil
return media, nil, true
}
mb = NewMediaBuffer(media, chunkSize)
_, _, _, err := mb.Chunk()
// If err is io.EOF, we can upload this in a single request. Otherwise, err is
// either nil or a non-EOF error. If it is the latter, then the next call to
// mb.Chunk will return the same error. Returning a MediaBuffer ensures that this
// error will be handled at some point.
return nil, mb, err == io.EOF
}
// MediaInfo holds information for media uploads. It is intended for use by generated
// code only.
type MediaInfo struct {
// At most one of Media and MediaBuffer will be set.
media io.Reader
buffer *MediaBuffer
singleChunk bool
mType string
size int64 // mediaSize, if known. Used only for calls to progressUpdater_.
progressUpdater googleapi.ProgressUpdater
}
// NewInfoFromMedia should be invoked from the Media method of a call. It returns a
// MediaInfo populated with chunk size and content type, and a reader or MediaBuffer
// if needed.
func NewInfoFromMedia(r io.Reader, options []googleapi.MediaOption) *MediaInfo {
mi := &MediaInfo{}
opts := googleapi.ProcessMediaOptions(options)
if !opts.ForceEmptyContentType {
r, mi.mType = DetermineContentType(r, opts.ContentType)
}
mi.media, mi.buffer, mi.singleChunk = PrepareUpload(r, opts.ChunkSize)
return mi
}
// NewInfoFromResumableMedia should be invoked from the ResumableMedia method of a
// call. It returns a MediaInfo using the given reader, size and media type.
func NewInfoFromResumableMedia(r io.ReaderAt, size int64, mediaType string) *MediaInfo {
rdr := ReaderAtToReader(r, size)
rdr, mType := DetermineContentType(rdr, mediaType)
return &MediaInfo{
size: size,
mType: mType,
buffer: NewMediaBuffer(rdr, googleapi.DefaultUploadChunkSize),
media: nil,
singleChunk: false,
}
}
func (mi *MediaInfo) SetProgressUpdater(pu googleapi.ProgressUpdater) {
if mi != nil {
mi.progressUpdater = pu
}
}
// UploadType determines the type of upload: a single request, or a resumable
// series of requests.
func (mi *MediaInfo) UploadType() string {
if mi.singleChunk {
return "multipart"
}
return "resumable"
}
// UploadRequest sets up an HTTP request for media upload. It adds headers
// as necessary, and returns a replacement for the body.
func (mi *MediaInfo) UploadRequest(reqHeaders http.Header, body io.Reader) (newBody io.Reader, cleanup func()) {
cleanup = func() {}
if mi == nil {
return body, cleanup
}
var media io.Reader
if mi.media != nil {
// This only happens when the caller has turned off chunking. In that
// case, we write all of media in a single non-retryable request.
media = mi.media
} else if mi.singleChunk {
// The data fits in a single chunk, which has now been read into the MediaBuffer.
// We obtain that chunk so we can write it in a single request. The request can
// be retried because the data is stored in the MediaBuffer.
media, _, _, _ = mi.buffer.Chunk()
}
if media != nil {
combined, ctype := CombineBodyMedia(body, "application/json", media, mi.mType)
cleanup = func() { combined.Close() }
reqHeaders.Set("Content-Type", ctype)
body = combined
}
if mi.buffer != nil && mi.mType != "" && !mi.singleChunk {
reqHeaders.Set("X-Upload-Content-Type", mi.mType)
}
return body, cleanup
}
// ResumableUpload returns an appropriately configured ResumableUpload value if the
// upload is resumable, or nil otherwise.
func (mi *MediaInfo) ResumableUpload(locURI string) *ResumableUpload {
if mi == nil || mi.singleChunk {
return nil
}
return &ResumableUpload{
URI: locURI,
Media: mi.buffer,
MediaType: mi.mType,
Callback: func(curr int64) {
if mi.progressUpdater != nil {
mi.progressUpdater(curr, mi.size)
}
},
}
mb := NewMediaBuffer(media, chunkSize)
rdr, _, _, err := mb.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 mb.Chunk will
// return the same error. Returning a MediaBuffer ensures that this error
// will be handled at some point.
return nil, mb
}
+196
View File
@@ -8,8 +8,12 @@ import (
"bytes"
"io"
"io/ioutil"
"net/http"
"reflect"
"strings"
"testing"
"google.golang.org/api/googleapi"
)
func TestContentSniffing(t *testing.T) {
@@ -140,3 +144,195 @@ func TestDetermineContentType(t *testing.T) {
}
}
}
func TestNewInfoFromMedia(t *testing.T) {
const textType = "text/plain; charset=utf-8"
for _, test := range []struct {
desc string
r io.Reader
opts []googleapi.MediaOption
wantType string
wantMedia, wantBuffer, wantSingleChunk bool
}{
{
desc: "an empty reader results in a MediaBuffer with a single, empty chunk",
r: new(bytes.Buffer),
opts: nil,
wantType: textType,
wantBuffer: true,
wantSingleChunk: true,
},
{
desc: "ContentType is observed",
r: new(bytes.Buffer),
opts: []googleapi.MediaOption{googleapi.ContentType("xyz")},
wantType: "xyz",
wantBuffer: true,
wantSingleChunk: true,
},
{
desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk",
r: strings.NewReader("12345"),
opts: []googleapi.MediaOption{googleapi.ChunkSize(0)},
wantType: textType,
wantMedia: true,
wantSingleChunk: true,
},
{
desc: "chunk size > data size: MediaBuffer with single chunk",
r: strings.NewReader("12345"),
opts: []googleapi.MediaOption{googleapi.ChunkSize(100)},
wantType: textType,
wantBuffer: true,
wantSingleChunk: true,
},
{
desc: "chunk size == data size: MediaBuffer with single chunk",
r: &nullReader{googleapi.MinUploadChunkSize},
opts: []googleapi.MediaOption{googleapi.ChunkSize(1)},
wantType: "application/octet-stream",
wantBuffer: true,
wantSingleChunk: true,
},
{
desc: "chunk size < data size: MediaBuffer, not single chunk",
// Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize.
r: &nullReader{2 * googleapi.MinUploadChunkSize},
opts: []googleapi.MediaOption{googleapi.ChunkSize(1)},
wantType: "application/octet-stream",
wantBuffer: true,
wantSingleChunk: false,
},
} {
mi := NewInfoFromMedia(test.r, test.opts)
if got, want := mi.mType, test.wantType; got != want {
t.Errorf("%s: type: got %q, want %q", test.desc, got, want)
}
if got, want := (mi.media != nil), test.wantMedia; got != want {
t.Errorf("%s: media non-nil: got %t, want %t", test.desc, got, want)
}
if got, want := (mi.buffer != nil), test.wantBuffer; got != want {
t.Errorf("%s: buffer non-nil: got %t, want %t", test.desc, got, want)
}
if got, want := mi.singleChunk, test.wantSingleChunk; got != want {
t.Errorf("%s: singleChunk: got %t, want %t", test.desc, got, want)
}
}
}
func TestUploadRequest(t *testing.T) {
for _, test := range []struct {
desc string
r io.Reader
chunkSize int
wantContentType string
wantUploadType string
}{
{
desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk",
r: strings.NewReader("12345"),
chunkSize: 0,
wantContentType: "multipart/related;",
},
{
desc: "chunk size > data size: MediaBuffer with single chunk",
r: strings.NewReader("12345"),
chunkSize: 100,
wantContentType: "multipart/related;",
},
{
desc: "chunk size == data size: MediaBuffer with single chunk",
r: &nullReader{googleapi.MinUploadChunkSize},
chunkSize: 1,
wantContentType: "multipart/related;",
},
{
desc: "chunk size < data size: MediaBuffer, not single chunk",
// Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize.
r: &nullReader{2 * googleapi.MinUploadChunkSize},
chunkSize: 1,
wantUploadType: "application/octet-stream",
},
} {
mi := NewInfoFromMedia(test.r, []googleapi.MediaOption{googleapi.ChunkSize(test.chunkSize)})
h := http.Header{}
mi.UploadRequest(h, new(bytes.Buffer))
if got, want := h.Get("Content-Type"), test.wantContentType; !strings.HasPrefix(got, want) {
t.Errorf("%s: Content-Type: got %q, want prefix %q", test.desc, got, want)
}
if got, want := h.Get("X-Upload-Content-Type"), test.wantUploadType; got != want {
t.Errorf("%s: X-Upload-Content-Type: got %q, want %q", test.desc, got, want)
}
}
}
func TestResumableUpload(t *testing.T) {
for _, test := range []struct {
desc string
r io.Reader
chunkSize int
wantUploadType string
wantResumableUpload bool
}{
{
desc: "chunk size of zero: don't use a MediaBuffer; upload as a single chunk",
r: strings.NewReader("12345"),
chunkSize: 0,
wantUploadType: "multipart",
wantResumableUpload: false,
},
{
desc: "chunk size > data size: MediaBuffer with single chunk",
r: strings.NewReader("12345"),
chunkSize: 100,
wantUploadType: "multipart",
wantResumableUpload: false,
},
{
desc: "chunk size == data size: MediaBuffer with single chunk",
// (Because nullReader returns EOF with the last bytes.)
r: &nullReader{googleapi.MinUploadChunkSize},
chunkSize: googleapi.MinUploadChunkSize,
wantUploadType: "multipart",
wantResumableUpload: false,
},
{
desc: "chunk size < data size: MediaBuffer, not single chunk",
// Note that ChunkSize = 1 is rounded up to googleapi.MinUploadChunkSize.
r: &nullReader{2 * googleapi.MinUploadChunkSize},
chunkSize: 1,
wantUploadType: "resumable",
wantResumableUpload: true,
},
} {
mi := NewInfoFromMedia(test.r, []googleapi.MediaOption{googleapi.ChunkSize(test.chunkSize)})
if got, want := mi.UploadType(), test.wantUploadType; got != want {
t.Errorf("%s: upload type: got %q, want %q", test.desc, got, want)
}
if got, want := mi.ResumableUpload("") != nil, test.wantResumableUpload; got != want {
t.Errorf("%s: resumable upload non-nil: got %t, want %t", test.desc, got, want)
}
}
}
// A nullReader simulates reading a fixed number of bytes.
type nullReader struct {
remain int
}
// Read doesn't touch buf, but it does reduce the amount of bytes remaining
// by len(buf).
func (r *nullReader) Read(buf []byte) (int, error) {
n := len(buf)
if r.remain < n {
n = r.remain
}
r.remain -= n
var err error
if r.remain == 0 {
err = io.EOF
}
return n, err
}
+6
View File
@@ -5,6 +5,7 @@
package gensupport
import (
"errors"
"net/http"
"golang.org/x/net/context"
@@ -32,6 +33,11 @@ func RegisterHook(h Hook) {
// If ctx is non-nil, it calls all hooks, then sends the request with
// ctxhttp.Do, then calls any functions returned by the hooks in reverse order.
func SendRequest(ctx context.Context, client *http.Client, req *http.Request) (*http.Response, error) {
// Disallow Accept-Encoding because it interferes with the automatic gzip handling
// done by the default http.Transport. See https://github.com/google/google-api-go-client/issues/219.
if _, ok := req.Header["Accept-Encoding"]; ok {
return nil, errors.New("google api: custom Accept-Encoding headers not allowed")
}
if ctx == nil {
return client.Do(req)
}
+20
View File
@@ -0,0 +1,20 @@
// Copyright 2017 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/http"
"testing"
)
func TestSendRequest(t *testing.T) {
// Setting Accept-Encoding should give an error immediately.
req, _ := http.NewRequest("GET", "url", nil)
req.Header.Set("Accept-Encoding", "")
_, err := SendRequest(nil, nil, req)
if err == nil {
t.Error("got nil, want error")
}
}