2018-02-05 16:05:59 -05:00
|
|
|
package resumable // import "github.com/docker/docker/registry/resumable"
|
2015-03-24 12:27:09 -04:00
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
2015-09-09 08:59:25 -04:00
|
|
|
"io"
|
2015-03-24 12:27:09 -04:00
|
|
|
"io/ioutil"
|
|
|
|
"net/http"
|
|
|
|
"net/http/httptest"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
2016-12-23 15:09:29 -05:00
|
|
|
"time"
|
2017-08-21 17:06:56 -04:00
|
|
|
|
2018-06-11 09:32:11 -04:00
|
|
|
"gotest.tools/assert"
|
|
|
|
is "gotest.tools/assert/cmp"
|
2015-03-24 12:27:09 -04:00
|
|
|
)
|
|
|
|
|
2015-09-09 08:59:25 -04:00
|
|
|
func TestResumableRequestHeaderSimpleErrors(t *testing.T) {
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, "Hello, world !")
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{}
|
2015-09-09 08:59:25 -04:00
|
|
|
_, err = resreq.Read([]byte{})
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Error(err, "client and request can't be nil"))
|
2015-09-09 08:59:25 -04:00
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq = &requestReader{
|
2015-09-09 08:59:25 -04:00
|
|
|
client: client,
|
|
|
|
request: req,
|
|
|
|
totalSize: -1,
|
|
|
|
}
|
|
|
|
_, err = resreq.Read([]byte{})
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Error(err, "failed to auto detect content length"))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Not too much failures, bails out after some wait
|
|
|
|
func TestResumableRequestHeaderNotTooMuchFailures(t *testing.T) {
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
var badReq *http.Request
|
|
|
|
badReq, err := http.NewRequest("GET", "I'm not an url", nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{
|
2016-12-23 15:09:29 -05:00
|
|
|
client: client,
|
|
|
|
request: badReq,
|
|
|
|
failures: 0,
|
|
|
|
maxFailures: 2,
|
|
|
|
waitDuration: 10 * time.Millisecond,
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
read, err := resreq.Read([]byte{})
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
|
|
|
assert.Check(t, is.Equal(0, read))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
// Too much failures, returns the error
|
|
|
|
func TestResumableRequestHeaderTooMuchFailures(t *testing.T) {
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
var badReq *http.Request
|
|
|
|
badReq, err := http.NewRequest("GET", "I'm not an url", nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{
|
2015-09-09 08:59:25 -04:00
|
|
|
client: client,
|
|
|
|
request: badReq,
|
|
|
|
failures: 0,
|
|
|
|
maxFailures: 1,
|
|
|
|
}
|
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
expectedError := `Get I%27m%20not%20an%20url: unsupported protocol scheme ""`
|
|
|
|
read, err := resreq.Read([]byte{})
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Error(err, expectedError))
|
|
|
|
assert.Check(t, is.Equal(0, read))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
type errorReaderCloser struct{}
|
|
|
|
|
|
|
|
func (errorReaderCloser) Close() error { return nil }
|
|
|
|
|
|
|
|
func (errorReaderCloser) Read(p []byte) (n int, err error) {
|
2016-02-22 14:22:20 -05:00
|
|
|
return 0, fmt.Errorf("An error occurred")
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
2016-05-07 21:36:10 -04:00
|
|
|
// If an unknown error is encountered, return 0, nil and log it
|
2015-09-09 08:59:25 -04:00
|
|
|
func TestResumableRequestReaderWithReadError(t *testing.T) {
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", "", nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
response := &http.Response{
|
|
|
|
Status: "500 Internal Server",
|
|
|
|
StatusCode: 500,
|
|
|
|
ContentLength: 0,
|
|
|
|
Close: true,
|
|
|
|
Body: errorReaderCloser{},
|
|
|
|
}
|
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{
|
2015-09-09 08:59:25 -04:00
|
|
|
client: client,
|
|
|
|
request: req,
|
|
|
|
currentResponse: response,
|
|
|
|
lastRange: 1,
|
|
|
|
totalSize: 1,
|
|
|
|
}
|
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
buf := make([]byte, 1)
|
|
|
|
read, err := resreq.Read(buf)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Equal(0, read))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResumableRequestReaderWithEOFWith416Response(t *testing.T) {
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", "", nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
|
|
|
|
response := &http.Response{
|
|
|
|
Status: "416 Requested Range Not Satisfiable",
|
|
|
|
StatusCode: 416,
|
|
|
|
ContentLength: 0,
|
|
|
|
Close: true,
|
|
|
|
Body: ioutil.NopCloser(strings.NewReader("")),
|
|
|
|
}
|
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{
|
2015-09-09 08:59:25 -04:00
|
|
|
client: client,
|
|
|
|
request: req,
|
|
|
|
currentResponse: response,
|
|
|
|
lastRange: 1,
|
|
|
|
totalSize: 1,
|
|
|
|
}
|
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
buf := make([]byte, 1)
|
|
|
|
_, err = resreq.Read(buf)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Error(err, io.EOF.Error()))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResumableRequestReaderWithServerDoesntSupportByteRanges(t *testing.T) {
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
if r.Header.Get("Range") == "" {
|
|
|
|
t.Fatalf("Expected a Range HTTP header, got nothing")
|
|
|
|
}
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := &requestReader{
|
2015-09-09 08:59:25 -04:00
|
|
|
client: client,
|
|
|
|
request: req,
|
|
|
|
lastRange: 1,
|
|
|
|
}
|
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
buf := make([]byte, 2)
|
|
|
|
_, err = resreq.Read(buf)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Error(err, "the server doesn't support byte ranges"))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResumableRequestReaderWithZeroTotalSize(t *testing.T) {
|
|
|
|
srvtxt := "some response text data"
|
|
|
|
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, srvtxt)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
retries := uint32(5)
|
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := NewRequestReader(client, req, retries, 0)
|
2015-09-09 08:59:25 -04:00
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(resreq)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-09-09 08:59:25 -04:00
|
|
|
|
|
|
|
resstr := strings.TrimSuffix(string(data), "\n")
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Equal(srvtxt, resstr))
|
2015-09-09 08:59:25 -04:00
|
|
|
}
|
|
|
|
|
2015-03-24 12:27:09 -04:00
|
|
|
func TestResumableRequestReader(t *testing.T) {
|
|
|
|
srvtxt := "some response text data"
|
|
|
|
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, srvtxt)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-03-24 12:27:09 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
retries := uint32(5)
|
|
|
|
imgSize := int64(len(srvtxt))
|
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := NewRequestReader(client, req, retries, imgSize)
|
2015-03-24 12:27:09 -04:00
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(resreq)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-03-24 12:27:09 -04:00
|
|
|
|
|
|
|
resstr := strings.TrimSuffix(string(data), "\n")
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Equal(srvtxt, resstr))
|
2015-03-24 12:27:09 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
func TestResumableRequestReaderWithInitialResponse(t *testing.T) {
|
|
|
|
srvtxt := "some response text data"
|
|
|
|
|
|
|
|
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
fmt.Fprintln(w, srvtxt)
|
|
|
|
}))
|
|
|
|
defer ts.Close()
|
|
|
|
|
|
|
|
var req *http.Request
|
|
|
|
req, err := http.NewRequest("GET", ts.URL, nil)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-03-24 12:27:09 -04:00
|
|
|
|
|
|
|
client := &http.Client{}
|
|
|
|
retries := uint32(5)
|
|
|
|
imgSize := int64(len(srvtxt))
|
|
|
|
|
|
|
|
res, err := client.Do(req)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-03-24 12:27:09 -04:00
|
|
|
|
2017-06-01 15:59:24 -04:00
|
|
|
resreq := NewRequestReaderWithInitialResponse(client, req, retries, imgSize, res)
|
2015-03-24 12:27:09 -04:00
|
|
|
defer resreq.Close()
|
|
|
|
|
|
|
|
data, err := ioutil.ReadAll(resreq)
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.NilError(t, err)
|
2015-03-24 12:27:09 -04:00
|
|
|
|
|
|
|
resstr := strings.TrimSuffix(string(data), "\n")
|
2018-03-13 15:28:34 -04:00
|
|
|
assert.Check(t, is.Equal(srvtxt, resstr))
|
2015-03-24 12:27:09 -04:00
|
|
|
}
|