github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/moby/registry/resumable/resumablerequestreader_test.go (about)

     1  package resumable // import "github.com/docker/docker/registry/resumable"
     2  
     3  import (
     4  	"fmt"
     5  	"io"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"net/http/httptest"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"gotest.tools/v3/assert"
    14  	is "gotest.tools/v3/assert/cmp"
    15  )
    16  
    17  func TestResumableRequestHeaderSimpleErrors(t *testing.T) {
    18  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    19  		fmt.Fprintln(w, "Hello, world !")
    20  	}))
    21  	defer ts.Close()
    22  
    23  	client := &http.Client{}
    24  
    25  	var req *http.Request
    26  	req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
    27  	assert.NilError(t, err)
    28  
    29  	resreq := &requestReader{}
    30  	_, err = resreq.Read([]byte{})
    31  	assert.Check(t, is.Error(err, "client and request can't be nil"))
    32  
    33  	resreq = &requestReader{
    34  		client:    client,
    35  		request:   req,
    36  		totalSize: -1,
    37  	}
    38  	_, err = resreq.Read([]byte{})
    39  	assert.Check(t, is.Error(err, "failed to auto detect content length"))
    40  }
    41  
    42  // Not too much failures, bails out after some wait
    43  func TestResumableRequestHeaderNotTooMuchFailures(t *testing.T) {
    44  	client := &http.Client{}
    45  
    46  	var badReq *http.Request
    47  	badReq, err := http.NewRequest(http.MethodGet, "I'm not an url", nil)
    48  	assert.NilError(t, err)
    49  
    50  	resreq := &requestReader{
    51  		client:       client,
    52  		request:      badReq,
    53  		failures:     0,
    54  		maxFailures:  2,
    55  		waitDuration: 10 * time.Millisecond,
    56  	}
    57  	read, err := resreq.Read([]byte{})
    58  	assert.NilError(t, err)
    59  	assert.Check(t, is.Equal(0, read))
    60  }
    61  
    62  // Too much failures, returns the error
    63  func TestResumableRequestHeaderTooMuchFailures(t *testing.T) {
    64  	client := &http.Client{}
    65  
    66  	var badReq *http.Request
    67  	badReq, err := http.NewRequest(http.MethodGet, "I'm not an url", nil)
    68  	assert.NilError(t, err)
    69  
    70  	resreq := &requestReader{
    71  		client:      client,
    72  		request:     badReq,
    73  		failures:    0,
    74  		maxFailures: 1,
    75  	}
    76  	defer resreq.Close()
    77  
    78  	read, err := resreq.Read([]byte{})
    79  	assert.Assert(t, err != nil)
    80  	assert.Check(t, is.ErrorContains(err, "unsupported protocol scheme"))
    81  	assert.Check(t, is.ErrorContains(err, "I%27m%20not%20an%20url"))
    82  	assert.Check(t, is.Equal(0, read))
    83  }
    84  
    85  type errorReaderCloser struct{}
    86  
    87  func (errorReaderCloser) Close() error { return nil }
    88  
    89  func (errorReaderCloser) Read(p []byte) (n int, err error) {
    90  	return 0, fmt.Errorf("An error occurred")
    91  }
    92  
    93  // If an unknown error is encountered, return 0, nil and log it
    94  func TestResumableRequestReaderWithReadError(t *testing.T) {
    95  	var req *http.Request
    96  	req, err := http.NewRequest(http.MethodGet, "", nil)
    97  	assert.NilError(t, err)
    98  
    99  	client := &http.Client{}
   100  
   101  	response := &http.Response{
   102  		Status:        "500 Internal Server",
   103  		StatusCode:    http.StatusInternalServerError,
   104  		ContentLength: 0,
   105  		Close:         true,
   106  		Body:          errorReaderCloser{},
   107  	}
   108  
   109  	resreq := &requestReader{
   110  		client:          client,
   111  		request:         req,
   112  		currentResponse: response,
   113  		lastRange:       1,
   114  		totalSize:       1,
   115  	}
   116  	defer resreq.Close()
   117  
   118  	buf := make([]byte, 1)
   119  	read, err := resreq.Read(buf)
   120  	assert.NilError(t, err)
   121  
   122  	assert.Check(t, is.Equal(0, read))
   123  }
   124  
   125  func TestResumableRequestReaderWithEOFWith416Response(t *testing.T) {
   126  	var req *http.Request
   127  	req, err := http.NewRequest(http.MethodGet, "", nil)
   128  	assert.NilError(t, err)
   129  
   130  	client := &http.Client{}
   131  
   132  	response := &http.Response{
   133  		Status:        "416 Requested Range Not Satisfiable",
   134  		StatusCode:    http.StatusRequestedRangeNotSatisfiable,
   135  		ContentLength: 0,
   136  		Close:         true,
   137  		Body:          ioutil.NopCloser(strings.NewReader("")),
   138  	}
   139  
   140  	resreq := &requestReader{
   141  		client:          client,
   142  		request:         req,
   143  		currentResponse: response,
   144  		lastRange:       1,
   145  		totalSize:       1,
   146  	}
   147  	defer resreq.Close()
   148  
   149  	buf := make([]byte, 1)
   150  	_, err = resreq.Read(buf)
   151  	assert.Check(t, is.Error(err, io.EOF.Error()))
   152  }
   153  
   154  func TestResumableRequestReaderWithServerDoesntSupportByteRanges(t *testing.T) {
   155  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   156  		if r.Header.Get("Range") == "" {
   157  			t.Fatalf("Expected a Range HTTP header, got nothing")
   158  		}
   159  	}))
   160  	defer ts.Close()
   161  
   162  	var req *http.Request
   163  	req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
   164  	assert.NilError(t, err)
   165  
   166  	client := &http.Client{}
   167  
   168  	resreq := &requestReader{
   169  		client:    client,
   170  		request:   req,
   171  		lastRange: 1,
   172  	}
   173  	defer resreq.Close()
   174  
   175  	buf := make([]byte, 2)
   176  	_, err = resreq.Read(buf)
   177  	assert.Check(t, is.Error(err, "the server doesn't support byte ranges"))
   178  }
   179  
   180  func TestResumableRequestReaderWithZeroTotalSize(t *testing.T) {
   181  	srvtxt := "some response text data"
   182  
   183  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   184  		fmt.Fprintln(w, srvtxt)
   185  	}))
   186  	defer ts.Close()
   187  
   188  	var req *http.Request
   189  	req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
   190  	assert.NilError(t, err)
   191  
   192  	client := &http.Client{}
   193  	retries := uint32(5)
   194  
   195  	resreq := NewRequestReader(client, req, retries, 0)
   196  	defer resreq.Close()
   197  
   198  	data, err := ioutil.ReadAll(resreq)
   199  	assert.NilError(t, err)
   200  
   201  	resstr := strings.TrimSuffix(string(data), "\n")
   202  	assert.Check(t, is.Equal(srvtxt, resstr))
   203  }
   204  
   205  func TestResumableRequestReader(t *testing.T) {
   206  	srvtxt := "some response text data"
   207  
   208  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   209  		fmt.Fprintln(w, srvtxt)
   210  	}))
   211  	defer ts.Close()
   212  
   213  	var req *http.Request
   214  	req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
   215  	assert.NilError(t, err)
   216  
   217  	client := &http.Client{}
   218  	retries := uint32(5)
   219  	imgSize := int64(len(srvtxt))
   220  
   221  	resreq := NewRequestReader(client, req, retries, imgSize)
   222  	defer resreq.Close()
   223  
   224  	data, err := ioutil.ReadAll(resreq)
   225  	assert.NilError(t, err)
   226  
   227  	resstr := strings.TrimSuffix(string(data), "\n")
   228  	assert.Check(t, is.Equal(srvtxt, resstr))
   229  }
   230  
   231  func TestResumableRequestReaderWithInitialResponse(t *testing.T) {
   232  	srvtxt := "some response text data"
   233  
   234  	ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   235  		fmt.Fprintln(w, srvtxt)
   236  	}))
   237  	defer ts.Close()
   238  
   239  	var req *http.Request
   240  	req, err := http.NewRequest(http.MethodGet, ts.URL, nil)
   241  	assert.NilError(t, err)
   242  
   243  	client := &http.Client{}
   244  	retries := uint32(5)
   245  	imgSize := int64(len(srvtxt))
   246  
   247  	res, err := client.Do(req)
   248  	assert.NilError(t, err)
   249  
   250  	resreq := NewRequestReaderWithInitialResponse(client, req, retries, imgSize, res)
   251  	defer resreq.Close()
   252  
   253  	data, err := ioutil.ReadAll(resreq)
   254  	assert.NilError(t, err)
   255  
   256  	resstr := strings.TrimSuffix(string(data), "\n")
   257  	assert.Check(t, is.Equal(srvtxt, resstr))
   258  }