drive: disable HTTP/2 by default to work around INTERNAL_ERROR problems

Before this change when rclone was compiled with go1.13 it used HTTP/2
to contact drive by default.

This causes lockups and INTERNAL_ERRORs from the HTTP/2 code.

This is a workaround disabling the HTTP/2 code on an option.

It can be re-enabled with `--drive-disable-http2=false`

See #3631
This commit is contained in:
Nick Craig-Wood 2019-10-16 11:22:25 +01:00
parent 0b6cdb7677
commit 38652d046d
1 changed files with 30 additions and 2 deletions

View File

@ -10,6 +10,7 @@ package drive
import ( import (
"bytes" "bytes"
"context" "context"
"crypto/tls"
"fmt" "fmt"
"io" "io"
"io/ioutil" "io/ioutil"
@ -405,6 +406,20 @@ different Google drives. Note that this isn't enabled by default
because it isn't easy to tell if it will work beween any two because it isn't easy to tell if it will work beween any two
configurations.`, configurations.`,
Advanced: true, Advanced: true,
}, {
Name: "disable_http2",
Default: true,
Help: `Disable drive using http2
There is currently an unsolved issue with the google drive backend and
HTTP/2. HTTP/2 is therefore disabled by default for the drive backend
but can be re-enabled here. When the issue is solved this flag will
be removed.
See: https://github.com/rclone/rclone/issues/3631
`,
Advanced: true,
}}, }},
}) })
@ -452,6 +467,7 @@ type Options struct {
PacerMinSleep fs.Duration `config:"pacer_min_sleep"` PacerMinSleep fs.Duration `config:"pacer_min_sleep"`
PacerBurst int `config:"pacer_burst"` PacerBurst int `config:"pacer_burst"`
ServerSideAcrossConfigs bool `config:"server_side_across_configs"` ServerSideAcrossConfigs bool `config:"server_side_across_configs"`
DisableHTTP2 bool `config:"disable_http2"`
} }
// Fs represents a remote drive server // Fs represents a remote drive server
@ -840,6 +856,18 @@ func newPacer(opt *Options) *fs.Pacer {
return fs.NewPacer(pacer.NewGoogleDrive(pacer.MinSleep(opt.PacerMinSleep), pacer.Burst(opt.PacerBurst))) return fs.NewPacer(pacer.NewGoogleDrive(pacer.MinSleep(opt.PacerMinSleep), pacer.Burst(opt.PacerBurst)))
} }
// getClient makes an http client according to the options
func getClient(opt *Options) *http.Client {
t := fshttp.NewTransportCustom(fs.Config, func(t *http.Transport) {
if opt.DisableHTTP2 {
t.TLSNextProto = map[string]func(string, *tls.Conn) http.RoundTripper{}
}
})
return &http.Client{
Transport: t,
}
}
func getServiceAccountClient(opt *Options, credentialsData []byte) (*http.Client, error) { func getServiceAccountClient(opt *Options, credentialsData []byte) (*http.Client, error) {
scopes := driveScopes(opt.Scope) scopes := driveScopes(opt.Scope)
conf, err := google.JWTConfigFromJSON(credentialsData, scopes...) conf, err := google.JWTConfigFromJSON(credentialsData, scopes...)
@ -849,7 +877,7 @@ func getServiceAccountClient(opt *Options, credentialsData []byte) (*http.Client
if opt.Impersonate != "" { if opt.Impersonate != "" {
conf.Subject = opt.Impersonate conf.Subject = opt.Impersonate
} }
ctxWithSpecialClient := oauthutil.Context(fshttp.NewClient(fs.Config)) ctxWithSpecialClient := oauthutil.Context(getClient(opt))
return oauth2.NewClient(ctxWithSpecialClient, conf.TokenSource(ctxWithSpecialClient)), nil return oauth2.NewClient(ctxWithSpecialClient, conf.TokenSource(ctxWithSpecialClient)), nil
} }
@ -871,7 +899,7 @@ func createOAuthClient(opt *Options, name string, m configmap.Mapper) (*http.Cli
return nil, errors.Wrap(err, "failed to create oauth client from service account") return nil, errors.Wrap(err, "failed to create oauth client from service account")
} }
} else { } else {
oAuthClient, _, err = oauthutil.NewClient(name, m, driveConfig) oAuthClient, _, err = oauthutil.NewClientWithBaseClient(name, m, driveConfig, getClient(opt))
if err != nil { if err != nil {
return nil, errors.Wrap(err, "failed to create oauth client") return nil, errors.Wrap(err, "failed to create oauth client")
} }