Browse code

registry: remove v1 code not related to searching

Signed-off-by: Sebastiaan van Stijn <github@gone.nl>

Sebastiaan van Stijn authored on 2020/10/28 21:46:00
Showing 3 changed files
... ...
@@ -7,14 +7,6 @@ import (
7 7
 	"github.com/docker/docker/errdefs"
8 8
 )
9 9
 
10
-type notFoundError string
11
-
12
-func (e notFoundError) Error() string {
13
-	return string(e)
14
-}
15
-
16
-func (notFoundError) NotFound() {}
17
-
18 10
 func translateV2AuthError(err error) error {
19 11
 	switch e := err.(type) {
20 12
 	case *url.Error:
... ...
@@ -1,10 +1,8 @@
1 1
 package registry // import "github.com/docker/docker/registry"
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"net/http"
6 5
 	"net/http/httputil"
7
-	"net/url"
8 6
 	"os"
9 7
 	"strings"
10 8
 	"testing"
... ...
@@ -17,15 +15,6 @@ import (
17 17
 	"gotest.tools/v3/skip"
18 18
 )
19 19
 
20
-var (
21
-	token = []string{"fake-token"}
22
-)
23
-
24
-const (
25
-	imageID = "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d"
26
-	REPO    = "foo42/bar"
27
-)
28
-
29 20
 func spawnTestRegistrySession(t *testing.T) *Session {
30 21
 	authConfig := &types.AuthConfig{}
31 22
 	endpoint, err := NewV1Endpoint(makeIndex("/v1/"), "", nil)
... ...
@@ -50,7 +39,7 @@ func spawnTestRegistrySession(t *testing.T) *Session {
50 50
 	// Because we know that the client's transport is an `*authTransport` we simply cast it,
51 51
 	// in order to set the internal cached token to the fake token, and thus send that fake token
52 52
 	// upon every subsequent requests.
53
-	r.client.Transport.(*authTransport).token = token
53
+	r.client.Transport.(*authTransport).token = []string{"fake-token"}
54 54
 	return r
55 55
 }
56 56
 
... ...
@@ -148,153 +137,6 @@ func TestEndpoint(t *testing.T) {
148 148
 	}
149 149
 }
150 150
 
151
-func TestGetRemoteHistory(t *testing.T) {
152
-	r := spawnTestRegistrySession(t)
153
-	hist, err := r.GetRemoteHistory(imageID, makeURL("/v1/"))
154
-	if err != nil {
155
-		t.Fatal(err)
156
-	}
157
-	assertEqual(t, len(hist), 2, "Expected 2 images in history")
158
-	assertEqual(t, hist[0], imageID, "Expected "+imageID+"as first ancestry")
159
-	assertEqual(t, hist[1], "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
160
-		"Unexpected second ancestry")
161
-}
162
-
163
-func TestLookupRemoteImage(t *testing.T) {
164
-	r := spawnTestRegistrySession(t)
165
-	err := r.LookupRemoteImage(imageID, makeURL("/v1/"))
166
-	assertEqual(t, err, nil, "Expected error of remote lookup to nil")
167
-	if err := r.LookupRemoteImage("abcdef", makeURL("/v1/")); err == nil {
168
-		t.Fatal("Expected error of remote lookup to not nil")
169
-	}
170
-}
171
-
172
-func TestGetRemoteImageJSON(t *testing.T) {
173
-	r := spawnTestRegistrySession(t)
174
-	json, size, err := r.GetRemoteImageJSON(imageID, makeURL("/v1/"))
175
-	if err != nil {
176
-		t.Fatal(err)
177
-	}
178
-	assertEqual(t, size, int64(154), "Expected size 154")
179
-	if len(json) == 0 {
180
-		t.Fatal("Expected non-empty json")
181
-	}
182
-
183
-	_, _, err = r.GetRemoteImageJSON("abcdef", makeURL("/v1/"))
184
-	if err == nil {
185
-		t.Fatal("Expected image not found error")
186
-	}
187
-}
188
-
189
-func TestGetRemoteImageLayer(t *testing.T) {
190
-	r := spawnTestRegistrySession(t)
191
-	data, err := r.GetRemoteImageLayer(imageID, makeURL("/v1/"), 0)
192
-	if err != nil {
193
-		t.Fatal(err)
194
-	}
195
-	if data == nil {
196
-		t.Fatal("Expected non-nil data result")
197
-	}
198
-
199
-	_, err = r.GetRemoteImageLayer("abcdef", makeURL("/v1/"), 0)
200
-	if err == nil {
201
-		t.Fatal("Expected image not found error")
202
-	}
203
-}
204
-
205
-func TestGetRemoteTag(t *testing.T) {
206
-	r := spawnTestRegistrySession(t)
207
-	repoRef, err := reference.ParseNormalizedNamed(REPO)
208
-	if err != nil {
209
-		t.Fatal(err)
210
-	}
211
-	tag, err := r.GetRemoteTag([]string{makeURL("/v1/")}, repoRef, "test")
212
-	if err != nil {
213
-		t.Fatal(err)
214
-	}
215
-	assertEqual(t, tag, imageID, "Expected tag test to map to "+imageID)
216
-
217
-	bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
218
-	if err != nil {
219
-		t.Fatal(err)
220
-	}
221
-	_, err = r.GetRemoteTag([]string{makeURL("/v1/")}, bazRef, "foo")
222
-	if err != ErrRepoNotFound {
223
-		t.Fatal("Expected ErrRepoNotFound error when fetching tag for bogus repo")
224
-	}
225
-}
226
-
227
-func TestGetRemoteTags(t *testing.T) {
228
-	r := spawnTestRegistrySession(t)
229
-	repoRef, err := reference.ParseNormalizedNamed(REPO)
230
-	if err != nil {
231
-		t.Fatal(err)
232
-	}
233
-	tags, err := r.GetRemoteTags([]string{makeURL("/v1/")}, repoRef)
234
-	if err != nil {
235
-		t.Fatal(err)
236
-	}
237
-	assertEqual(t, len(tags), 2, "Expected two tags")
238
-	assertEqual(t, tags["latest"], imageID, "Expected tag latest to map to "+imageID)
239
-	assertEqual(t, tags["test"], imageID, "Expected tag test to map to "+imageID)
240
-
241
-	bazRef, err := reference.ParseNormalizedNamed("foo42/baz")
242
-	if err != nil {
243
-		t.Fatal(err)
244
-	}
245
-	_, err = r.GetRemoteTags([]string{makeURL("/v1/")}, bazRef)
246
-	if err != ErrRepoNotFound {
247
-		t.Fatal("Expected ErrRepoNotFound error when fetching tags for bogus repo")
248
-	}
249
-}
250
-
251
-func TestGetRepositoryData(t *testing.T) {
252
-	r := spawnTestRegistrySession(t)
253
-	parsedURL, err := url.Parse(makeURL("/v1/"))
254
-	if err != nil {
255
-		t.Fatal(err)
256
-	}
257
-	host := "http://" + parsedURL.Host + "/v1/"
258
-	repoRef, err := reference.ParseNormalizedNamed(REPO)
259
-	if err != nil {
260
-		t.Fatal(err)
261
-	}
262
-	data, err := r.GetRepositoryData(repoRef)
263
-	if err != nil {
264
-		t.Fatal(err)
265
-	}
266
-	assertEqual(t, len(data.ImgList), 2, "Expected 2 images in ImgList")
267
-	assertEqual(t, len(data.Endpoints), 2,
268
-		fmt.Sprintf("Expected 2 endpoints in Endpoints, found %d instead", len(data.Endpoints)))
269
-	assertEqual(t, data.Endpoints[0], host,
270
-		fmt.Sprintf("Expected first endpoint to be %s but found %s instead", host, data.Endpoints[0]))
271
-	assertEqual(t, data.Endpoints[1], "http://test.example.com/v1/",
272
-		fmt.Sprintf("Expected first endpoint to be http://test.example.com/v1/ but found %s instead", data.Endpoints[1]))
273
-
274
-}
275
-
276
-func TestPushImageJSONRegistry(t *testing.T) {
277
-	r := spawnTestRegistrySession(t)
278
-	imgData := &ImgData{
279
-		ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
280
-		Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
281
-	}
282
-
283
-	err := r.PushImageJSONRegistry(imgData, []byte{0x42, 0xdf, 0x0}, makeURL("/v1/"))
284
-	if err != nil {
285
-		t.Fatal(err)
286
-	}
287
-}
288
-
289
-func TestPushImageLayerRegistry(t *testing.T) {
290
-	r := spawnTestRegistrySession(t)
291
-	layer := strings.NewReader("")
292
-	_, _, err := r.PushImageLayerRegistry(imageID, layer, makeURL("/v1/"), []byte{})
293
-	if err != nil {
294
-		t.Fatal(err)
295
-	}
296
-}
297
-
298 151
 func TestParseRepositoryInfo(t *testing.T) {
299 152
 	type staticRepositoryInfo struct {
300 153
 		Index         *registrytypes.IndexInfo
... ...
@@ -701,50 +543,6 @@ func TestMirrorEndpointLookup(t *testing.T) {
701 701
 	}
702 702
 }
703 703
 
704
-func TestPushRegistryTag(t *testing.T) {
705
-	r := spawnTestRegistrySession(t)
706
-	repoRef, err := reference.ParseNormalizedNamed(REPO)
707
-	if err != nil {
708
-		t.Fatal(err)
709
-	}
710
-	err = r.PushRegistryTag(repoRef, imageID, "stable", makeURL("/v1/"))
711
-	if err != nil {
712
-		t.Fatal(err)
713
-	}
714
-}
715
-
716
-func TestPushImageJSONIndex(t *testing.T) {
717
-	r := spawnTestRegistrySession(t)
718
-	imgData := []*ImgData{
719
-		{
720
-			ID:       "77dbf71da1d00e3fbddc480176eac8994025630c6590d11cfc8fe1209c2a1d20",
721
-			Checksum: "sha256:1ac330d56e05eef6d438586545ceff7550d3bdcb6b19961f12c5ba714ee1bb37",
722
-		},
723
-		{
724
-			ID:       "42d718c941f5c532ac049bf0b0ab53f0062f09a03afd4aa4a02c098e46032b9d",
725
-			Checksum: "sha256:bea7bf2e4bacd479344b737328db47b18880d09096e6674165533aa994f5e9f2",
726
-		},
727
-	}
728
-	repoRef, err := reference.ParseNormalizedNamed(REPO)
729
-	if err != nil {
730
-		t.Fatal(err)
731
-	}
732
-	repoData, err := r.PushImageJSONIndex(repoRef, imgData, false, nil)
733
-	if err != nil {
734
-		t.Fatal(err)
735
-	}
736
-	if repoData == nil {
737
-		t.Fatal("Expected RepositoryData object")
738
-	}
739
-	repoData, err = r.PushImageJSONIndex(repoRef, imgData, true, []string{r.indexEndpoint.String()})
740
-	if err != nil {
741
-		t.Fatal(err)
742
-	}
743
-	if repoData == nil {
744
-		t.Fatal("Expected RepositoryData object")
745
-	}
746
-}
747
-
748 704
 func TestSearchRepositories(t *testing.T) {
749 705
 	r := spawnTestRegistrySession(t)
750 706
 	results, err := r.SearchRepositories("fakequery", 25)
... ...
@@ -1,43 +1,26 @@
1 1
 package registry // import "github.com/docker/docker/registry"
2 2
 
3 3
 import (
4
-	"bytes"
5
-	"crypto/sha256"
6
-
7 4
 	// this is required for some certificates
8 5
 	_ "crypto/sha512"
9
-	"encoding/hex"
10 6
 	"encoding/json"
11 7
 	"fmt"
12
-	"io"
13
-	"io/ioutil"
14 8
 	"net/http"
15 9
 	"net/http/cookiejar"
16 10
 	"net/url"
17
-	"strconv"
18 11
 	"strings"
19 12
 	"sync"
20 13
 
21
-	"github.com/docker/distribution/reference"
22
-	"github.com/docker/distribution/registry/api/errcode"
23 14
 	"github.com/docker/docker/api/types"
24 15
 	registrytypes "github.com/docker/docker/api/types/registry"
25 16
 	"github.com/docker/docker/errdefs"
26 17
 	"github.com/docker/docker/pkg/ioutils"
27 18
 	"github.com/docker/docker/pkg/jsonmessage"
28 19
 	"github.com/docker/docker/pkg/stringid"
29
-	"github.com/docker/docker/pkg/tarsum"
30
-	"github.com/docker/docker/registry/resumable"
31 20
 	"github.com/pkg/errors"
32 21
 	"github.com/sirupsen/logrus"
33 22
 )
34 23
 
35
-var (
36
-	// ErrRepoNotFound is returned if the repository didn't exist on the
37
-	// remote side
38
-	ErrRepoNotFound notFoundError = "Repository not found"
39
-)
40
-
41 24
 // A Session is used to communicate with a V1 registry
42 25
 type Session struct {
43 26
 	indexEndpoint *V1Endpoint
... ...
@@ -214,527 +197,6 @@ func NewSession(client *http.Client, authConfig *types.AuthConfig, endpoint *V1E
214 214
 	return newSession(client, authConfig, endpoint), nil
215 215
 }
216 216
 
217
-// ID returns this registry session's ID.
218
-func (r *Session) ID() string {
219
-	return r.id
220
-}
221
-
222
-// GetRemoteHistory retrieves the history of a given image from the registry.
223
-// It returns a list of the parent's JSON files (including the requested image).
224
-func (r *Session) GetRemoteHistory(imgID, registry string) ([]string, error) {
225
-	res, err := r.client.Get(registry + "images/" + imgID + "/ancestry")
226
-	if err != nil {
227
-		return nil, err
228
-	}
229
-	defer res.Body.Close()
230
-	if res.StatusCode != http.StatusOK {
231
-		if res.StatusCode == http.StatusUnauthorized {
232
-			return nil, errcode.ErrorCodeUnauthorized.WithArgs()
233
-		}
234
-		return nil, newJSONError(fmt.Sprintf("Server error: %d trying to fetch remote history for %s", res.StatusCode, imgID), res)
235
-	}
236
-
237
-	var history []string
238
-	if err := json.NewDecoder(res.Body).Decode(&history); err != nil {
239
-		return nil, fmt.Errorf("Error while reading the http response: %v", err)
240
-	}
241
-
242
-	logrus.Debugf("Ancestry: %v", history)
243
-	return history, nil
244
-}
245
-
246
-// LookupRemoteImage checks if an image exists in the registry
247
-func (r *Session) LookupRemoteImage(imgID, registry string) error {
248
-	res, err := r.client.Get(registry + "images/" + imgID + "/json")
249
-	if err != nil {
250
-		return err
251
-	}
252
-	res.Body.Close()
253
-	if res.StatusCode != http.StatusOK {
254
-		return newJSONError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
255
-	}
256
-	return nil
257
-}
258
-
259
-// GetRemoteImageJSON retrieves an image's JSON metadata from the registry.
260
-func (r *Session) GetRemoteImageJSON(imgID, registry string) ([]byte, int64, error) {
261
-	res, err := r.client.Get(registry + "images/" + imgID + "/json")
262
-	if err != nil {
263
-		return nil, -1, fmt.Errorf("Failed to download json: %s", err)
264
-	}
265
-	defer res.Body.Close()
266
-	if res.StatusCode != http.StatusOK {
267
-		return nil, -1, newJSONError(fmt.Sprintf("HTTP code %d", res.StatusCode), res)
268
-	}
269
-	// if the size header is not present, then set it to '-1'
270
-	imageSize := int64(-1)
271
-	if hdr := res.Header.Get("X-Docker-Size"); hdr != "" {
272
-		imageSize, err = strconv.ParseInt(hdr, 10, 64)
273
-		if err != nil {
274
-			return nil, -1, err
275
-		}
276
-	}
277
-
278
-	jsonString, err := ioutil.ReadAll(res.Body)
279
-	if err != nil {
280
-		return nil, -1, fmt.Errorf("Failed to parse downloaded json: %v (%s)", err, jsonString)
281
-	}
282
-	return jsonString, imageSize, nil
283
-}
284
-
285
-// GetRemoteImageLayer retrieves an image layer from the registry
286
-func (r *Session) GetRemoteImageLayer(imgID, registry string, imgSize int64) (io.ReadCloser, error) {
287
-	var (
288
-		statusCode = 0
289
-		res        *http.Response
290
-		err        error
291
-		imageURL   = fmt.Sprintf("%simages/%s/layer", registry, imgID)
292
-	)
293
-
294
-	req, err := http.NewRequest(http.MethodGet, imageURL, nil)
295
-	if err != nil {
296
-		return nil, fmt.Errorf("Error while getting from the server: %v", err)
297
-	}
298
-
299
-	res, err = r.client.Do(req)
300
-	if err != nil {
301
-		logrus.Debugf("Error contacting registry %s: %v", registry, err)
302
-		// the only case err != nil && res != nil is https://golang.org/src/net/http/client.go#L515
303
-		if res != nil {
304
-			if res.Body != nil {
305
-				res.Body.Close()
306
-			}
307
-			statusCode = res.StatusCode
308
-		}
309
-		return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)",
310
-			statusCode, imgID)
311
-	}
312
-
313
-	if res.StatusCode != http.StatusOK {
314
-		res.Body.Close()
315
-		return nil, fmt.Errorf("Server error: Status %d while fetching image layer (%s)",
316
-			res.StatusCode, imgID)
317
-	}
318
-
319
-	if res.Header.Get("Accept-Ranges") == "bytes" && imgSize > 0 {
320
-		logrus.Debug("server supports resume")
321
-		return resumable.NewRequestReaderWithInitialResponse(r.client, req, 5, imgSize, res), nil
322
-	}
323
-	logrus.Debug("server doesn't support resume")
324
-	return res.Body, nil
325
-}
326
-
327
-// GetRemoteTag retrieves the tag named in the askedTag argument from the given
328
-// repository. It queries each of the registries supplied in the registries
329
-// argument, and returns data from the first one that answers the query
330
-// successfully.
331
-func (r *Session) GetRemoteTag(registries []string, repositoryRef reference.Named, askedTag string) (string, error) {
332
-	repository := reference.Path(repositoryRef)
333
-
334
-	if strings.Count(repository, "/") == 0 {
335
-		// This will be removed once the registry supports auto-resolution on
336
-		// the "library" namespace
337
-		repository = "library/" + repository
338
-	}
339
-	for _, host := range registries {
340
-		endpoint := fmt.Sprintf("%srepositories/%s/tags/%s", host, repository, askedTag)
341
-		res, err := r.client.Get(endpoint)
342
-		if err != nil {
343
-			return "", err
344
-		}
345
-
346
-		logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
347
-		defer res.Body.Close()
348
-
349
-		if res.StatusCode == 404 {
350
-			return "", ErrRepoNotFound
351
-		}
352
-		if res.StatusCode != http.StatusOK {
353
-			continue
354
-		}
355
-
356
-		var tagID string
357
-		if err := json.NewDecoder(res.Body).Decode(&tagID); err != nil {
358
-			return "", err
359
-		}
360
-		return tagID, nil
361
-	}
362
-	return "", fmt.Errorf("Could not reach any registry endpoint")
363
-}
364
-
365
-// GetRemoteTags retrieves all tags from the given repository. It queries each
366
-// of the registries supplied in the registries argument, and returns data from
367
-// the first one that answers the query successfully. It returns a map with
368
-// tag names as the keys and image IDs as the values.
369
-func (r *Session) GetRemoteTags(registries []string, repositoryRef reference.Named) (map[string]string, error) {
370
-	repository := reference.Path(repositoryRef)
371
-
372
-	if strings.Count(repository, "/") == 0 {
373
-		// This will be removed once the registry supports auto-resolution on
374
-		// the "library" namespace
375
-		repository = "library/" + repository
376
-	}
377
-	for _, host := range registries {
378
-		endpoint := fmt.Sprintf("%srepositories/%s/tags", host, repository)
379
-		res, err := r.client.Get(endpoint)
380
-		if err != nil {
381
-			return nil, err
382
-		}
383
-
384
-		logrus.Debugf("Got status code %d from %s", res.StatusCode, endpoint)
385
-		defer res.Body.Close()
386
-
387
-		if res.StatusCode == 404 {
388
-			return nil, ErrRepoNotFound
389
-		}
390
-		if res.StatusCode != http.StatusOK {
391
-			continue
392
-		}
393
-
394
-		result := make(map[string]string)
395
-		if err := json.NewDecoder(res.Body).Decode(&result); err != nil {
396
-			return nil, err
397
-		}
398
-		return result, nil
399
-	}
400
-	return nil, fmt.Errorf("Could not reach any registry endpoint")
401
-}
402
-
403
-func buildEndpointsList(headers []string, indexEp string) ([]string, error) {
404
-	var endpoints []string
405
-	parsedURL, err := url.Parse(indexEp)
406
-	if err != nil {
407
-		return nil, err
408
-	}
409
-	var urlScheme = parsedURL.Scheme
410
-	// The registry's URL scheme has to match the Index'
411
-	for _, ep := range headers {
412
-		epList := strings.Split(ep, ",")
413
-		for _, epListElement := range epList {
414
-			endpoints = append(
415
-				endpoints,
416
-				fmt.Sprintf("%s://%s/v1/", urlScheme, strings.TrimSpace(epListElement)))
417
-		}
418
-	}
419
-	return endpoints, nil
420
-}
421
-
422
-// GetRepositoryData returns lists of images and endpoints for the repository
423
-func (r *Session) GetRepositoryData(name reference.Named) (*RepositoryData, error) {
424
-	repositoryTarget := fmt.Sprintf("%srepositories/%s/images", r.indexEndpoint.String(), reference.Path(name))
425
-
426
-	logrus.Debugf("[registry] Calling GET %s", repositoryTarget)
427
-
428
-	req, err := http.NewRequest(http.MethodGet, repositoryTarget, nil)
429
-	if err != nil {
430
-		return nil, err
431
-	}
432
-	// this will set basic auth in r.client.Transport and send cached X-Docker-Token headers for all subsequent requests
433
-	req.Header.Set("X-Docker-Token", "true")
434
-	res, err := r.client.Do(req)
435
-	if err != nil {
436
-		// check if the error is because of i/o timeout
437
-		// and return a non-obtuse error message for users
438
-		// "Get https://index.docker.io/v1/repositories/library/busybox/images: i/o timeout"
439
-		// was a top search on the docker user forum
440
-		if isTimeout(err) {
441
-			return nil, fmt.Errorf("network timed out while trying to connect to %s. You may want to check your internet connection or if you are behind a proxy", repositoryTarget)
442
-		}
443
-		return nil, fmt.Errorf("Error while pulling image: %v", err)
444
-	}
445
-	defer res.Body.Close()
446
-	if res.StatusCode == http.StatusUnauthorized {
447
-		return nil, errcode.ErrorCodeUnauthorized.WithArgs()
448
-	}
449
-	// TODO: Right now we're ignoring checksums in the response body.
450
-	// In the future, we need to use them to check image validity.
451
-	if res.StatusCode == 404 {
452
-		return nil, newJSONError(fmt.Sprintf("HTTP code: %d", res.StatusCode), res)
453
-	} else if res.StatusCode != http.StatusOK {
454
-		errBody, err := ioutil.ReadAll(res.Body)
455
-		if err != nil {
456
-			logrus.Debugf("Error reading response body: %s", err)
457
-		}
458
-		return nil, newJSONError(fmt.Sprintf("Error: Status %d trying to pull repository %s: %q", res.StatusCode, reference.Path(name), errBody), res)
459
-	}
460
-
461
-	var endpoints []string
462
-	if res.Header.Get("X-Docker-Endpoints") != "" {
463
-		endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.String())
464
-		if err != nil {
465
-			return nil, err
466
-		}
467
-	} else {
468
-		// Assume the endpoint is on the same host
469
-		endpoints = append(endpoints, fmt.Sprintf("%s://%s/v1/", r.indexEndpoint.URL.Scheme, req.URL.Host))
470
-	}
471
-
472
-	remoteChecksums := []*ImgData{}
473
-	if err := json.NewDecoder(res.Body).Decode(&remoteChecksums); err != nil {
474
-		return nil, err
475
-	}
476
-
477
-	// Forge a better object from the retrieved data
478
-	imgsData := make(map[string]*ImgData, len(remoteChecksums))
479
-	for _, elem := range remoteChecksums {
480
-		imgsData[elem.ID] = elem
481
-	}
482
-
483
-	return &RepositoryData{
484
-		ImgList:   imgsData,
485
-		Endpoints: endpoints,
486
-	}, nil
487
-}
488
-
489
-// PushImageChecksumRegistry uploads checksums for an image
490
-func (r *Session) PushImageChecksumRegistry(imgData *ImgData, registry string) error {
491
-	u := registry + "images/" + imgData.ID + "/checksum"
492
-
493
-	logrus.Debugf("[registry] Calling PUT %s", u)
494
-
495
-	req, err := http.NewRequest(http.MethodPut, u, nil)
496
-	if err != nil {
497
-		return err
498
-	}
499
-	req.Header.Set("X-Docker-Checksum", imgData.Checksum)
500
-	req.Header.Set("X-Docker-Checksum-Payload", imgData.ChecksumPayload)
501
-
502
-	res, err := r.client.Do(req)
503
-	if err != nil {
504
-		return fmt.Errorf("Failed to upload metadata: %v", err)
505
-	}
506
-	defer res.Body.Close()
507
-	if len(res.Cookies()) > 0 {
508
-		r.client.Jar.SetCookies(req.URL, res.Cookies())
509
-	}
510
-	if res.StatusCode != http.StatusOK {
511
-		errBody, err := ioutil.ReadAll(res.Body)
512
-		if err != nil {
513
-			return fmt.Errorf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err)
514
-		}
515
-		var jsonBody map[string]string
516
-		if err := json.Unmarshal(errBody, &jsonBody); err != nil {
517
-			errBody = []byte(err.Error())
518
-		} else if jsonBody["error"] == "Image already exists" {
519
-			return ErrAlreadyExists
520
-		}
521
-		return fmt.Errorf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody)
522
-	}
523
-	return nil
524
-}
525
-
526
-// PushImageJSONRegistry pushes JSON metadata for a local image to the registry
527
-func (r *Session) PushImageJSONRegistry(imgData *ImgData, jsonRaw []byte, registry string) error {
528
-
529
-	u := registry + "images/" + imgData.ID + "/json"
530
-
531
-	logrus.Debugf("[registry] Calling PUT %s", u)
532
-
533
-	req, err := http.NewRequest(http.MethodPut, u, bytes.NewReader(jsonRaw))
534
-	if err != nil {
535
-		return err
536
-	}
537
-	req.Header.Add("Content-type", "application/json")
538
-
539
-	res, err := r.client.Do(req)
540
-	if err != nil {
541
-		return fmt.Errorf("Failed to upload metadata: %s", err)
542
-	}
543
-	defer res.Body.Close()
544
-	if res.StatusCode == http.StatusUnauthorized && strings.HasPrefix(registry, "http://") {
545
-		return newJSONError("HTTP code 401, Docker will not send auth headers over HTTP.", res)
546
-	}
547
-	if res.StatusCode != http.StatusOK {
548
-		errBody, err := ioutil.ReadAll(res.Body)
549
-		if err != nil {
550
-			return newJSONError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
551
-		}
552
-		var jsonBody map[string]string
553
-		if err := json.Unmarshal(errBody, &jsonBody); err != nil {
554
-			errBody = []byte(err.Error())
555
-		} else if jsonBody["error"] == "Image already exists" {
556
-			return ErrAlreadyExists
557
-		}
558
-		return newJSONError(fmt.Sprintf("HTTP code %d while uploading metadata: %q", res.StatusCode, errBody), res)
559
-	}
560
-	return nil
561
-}
562
-
563
-// PushImageLayerRegistry sends the checksum of an image layer to the registry
564
-func (r *Session) PushImageLayerRegistry(imgID string, layer io.Reader, registry string, jsonRaw []byte) (checksum string, checksumPayload string, err error) {
565
-	u := registry + "images/" + imgID + "/layer"
566
-
567
-	logrus.Debugf("[registry] Calling PUT %s", u)
568
-
569
-	tarsumLayer, err := tarsum.NewTarSum(layer, false, tarsum.Version0)
570
-	if err != nil {
571
-		return "", "", err
572
-	}
573
-	h := sha256.New()
574
-	h.Write(jsonRaw)
575
-	h.Write([]byte{'\n'})
576
-	checksumLayer := io.TeeReader(tarsumLayer, h)
577
-
578
-	req, err := http.NewRequest(http.MethodPut, u, checksumLayer)
579
-	if err != nil {
580
-		return "", "", err
581
-	}
582
-	req.Header.Add("Content-Type", "application/octet-stream")
583
-	req.ContentLength = -1
584
-	req.TransferEncoding = []string{"chunked"}
585
-	res, err := r.client.Do(req)
586
-	if err != nil {
587
-		return "", "", fmt.Errorf("Failed to upload layer: %v", err)
588
-	}
589
-	if rc, ok := layer.(io.Closer); ok {
590
-		if err := rc.Close(); err != nil {
591
-			return "", "", err
592
-		}
593
-	}
594
-	defer res.Body.Close()
595
-
596
-	if res.StatusCode != http.StatusOK {
597
-		errBody, err := ioutil.ReadAll(res.Body)
598
-		if err != nil {
599
-			return "", "", newJSONError(fmt.Sprintf("HTTP code %d while uploading metadata and error when trying to parse response body: %s", res.StatusCode, err), res)
600
-		}
601
-		return "", "", newJSONError(fmt.Sprintf("Received HTTP code %d while uploading layer: %q", res.StatusCode, errBody), res)
602
-	}
603
-
604
-	checksumPayload = "sha256:" + hex.EncodeToString(h.Sum(nil))
605
-	return tarsumLayer.Sum(jsonRaw), checksumPayload, nil
606
-}
607
-
608
-// PushRegistryTag pushes a tag on the registry.
609
-// Remote has the format '<user>/<repo>
610
-func (r *Session) PushRegistryTag(remote reference.Named, revision, tag, registry string) error {
611
-	// "jsonify" the string
612
-	revision = "\"" + revision + "\""
613
-	path := fmt.Sprintf("repositories/%s/tags/%s", reference.Path(remote), tag)
614
-
615
-	req, err := http.NewRequest(http.MethodPut, registry+path, strings.NewReader(revision))
616
-	if err != nil {
617
-		return err
618
-	}
619
-	req.Header.Add("Content-type", "application/json")
620
-	req.ContentLength = int64(len(revision))
621
-	res, err := r.client.Do(req)
622
-	if err != nil {
623
-		return err
624
-	}
625
-	res.Body.Close()
626
-	if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
627
-		return newJSONError(fmt.Sprintf("Internal server error: %d trying to push tag %s on %s", res.StatusCode, tag, reference.Path(remote)), res)
628
-	}
629
-	return nil
630
-}
631
-
632
-// PushImageJSONIndex uploads an image list to the repository
633
-func (r *Session) PushImageJSONIndex(remote reference.Named, imgList []*ImgData, validate bool, regs []string) (*RepositoryData, error) {
634
-	cleanImgList := []*ImgData{}
635
-	if validate {
636
-		for _, elem := range imgList {
637
-			if elem.Checksum != "" {
638
-				cleanImgList = append(cleanImgList, elem)
639
-			}
640
-		}
641
-	} else {
642
-		cleanImgList = imgList
643
-	}
644
-
645
-	imgListJSON, err := json.Marshal(cleanImgList)
646
-	if err != nil {
647
-		return nil, err
648
-	}
649
-	var suffix string
650
-	if validate {
651
-		suffix = "images"
652
-	}
653
-	u := fmt.Sprintf("%srepositories/%s/%s", r.indexEndpoint.String(), reference.Path(remote), suffix)
654
-	logrus.Debugf("[registry] PUT %s", u)
655
-	logrus.Debugf("Image list pushed to index:\n%s", imgListJSON)
656
-	headers := map[string][]string{
657
-		"Content-type": {"application/json"},
658
-		// this will set basic auth in r.client.Transport and send cached X-Docker-Token headers for all subsequent requests
659
-		"X-Docker-Token": {"true"},
660
-	}
661
-	if validate {
662
-		headers["X-Docker-Endpoints"] = regs
663
-	}
664
-
665
-	// Redirect if necessary
666
-	var res *http.Response
667
-	for {
668
-		if res, err = r.putImageRequest(u, headers, imgListJSON); err != nil {
669
-			return nil, err
670
-		}
671
-		if !shouldRedirect(res) {
672
-			break
673
-		}
674
-		res.Body.Close()
675
-		u = res.Header.Get("Location")
676
-		logrus.Debugf("Redirected to %s", u)
677
-	}
678
-	defer res.Body.Close()
679
-
680
-	if res.StatusCode == http.StatusUnauthorized {
681
-		return nil, errcode.ErrorCodeUnauthorized.WithArgs()
682
-	}
683
-
684
-	var tokens, endpoints []string
685
-	if !validate {
686
-		if res.StatusCode != http.StatusOK && res.StatusCode != http.StatusCreated {
687
-			errBody, err := ioutil.ReadAll(res.Body)
688
-			if err != nil {
689
-				logrus.Debugf("Error reading response body: %s", err)
690
-			}
691
-			return nil, newJSONError(fmt.Sprintf("Error: Status %d trying to push repository %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
692
-		}
693
-		tokens = res.Header["X-Docker-Token"]
694
-		logrus.Debugf("Auth token: %v", tokens)
695
-
696
-		if res.Header.Get("X-Docker-Endpoints") == "" {
697
-			return nil, fmt.Errorf("Index response didn't contain any endpoints")
698
-		}
699
-		endpoints, err = buildEndpointsList(res.Header["X-Docker-Endpoints"], r.indexEndpoint.String())
700
-		if err != nil {
701
-			return nil, err
702
-		}
703
-	} else {
704
-		if res.StatusCode != http.StatusNoContent {
705
-			errBody, err := ioutil.ReadAll(res.Body)
706
-			if err != nil {
707
-				logrus.Debugf("Error reading response body: %s", err)
708
-			}
709
-			return nil, newJSONError(fmt.Sprintf("Error: Status %d trying to push checksums %s: %q", res.StatusCode, reference.Path(remote), errBody), res)
710
-		}
711
-	}
712
-
713
-	return &RepositoryData{
714
-		Endpoints: endpoints,
715
-	}, nil
716
-}
717
-
718
-func (r *Session) putImageRequest(u string, headers map[string][]string, body []byte) (*http.Response, error) {
719
-	req, err := http.NewRequest(http.MethodPut, u, bytes.NewReader(body))
720
-	if err != nil {
721
-		return nil, err
722
-	}
723
-	req.ContentLength = int64(len(body))
724
-	for k, v := range headers {
725
-		req.Header[k] = v
726
-	}
727
-	response, err := r.client.Do(req)
728
-	if err != nil {
729
-		return nil, err
730
-	}
731
-	return response, nil
732
-}
733
-
734
-func shouldRedirect(response *http.Response) bool {
735
-	return response.StatusCode >= 300 && response.StatusCode < 400
736
-}
737
-
738 217
 // SearchRepositories performs a search against the remote repository
739 218
 func (r *Session) SearchRepositories(term string, limit int) (*registrytypes.SearchResults, error) {
740 219
 	if limit < 1 || limit > 100 {
... ...
@@ -755,28 +217,11 @@ func (r *Session) SearchRepositories(term string, limit int) (*registrytypes.Sea
755 755
 	}
756 756
 	defer res.Body.Close()
757 757
 	if res.StatusCode != http.StatusOK {
758
-		return nil, newJSONError(fmt.Sprintf("Unexpected status code %d", res.StatusCode), res)
758
+		return nil, &jsonmessage.JSONError{
759
+			Message: fmt.Sprintf("Unexpected status code %d", res.StatusCode),
760
+			Code:    res.StatusCode,
761
+		}
759 762
 	}
760 763
 	result := new(registrytypes.SearchResults)
761 764
 	return result, errors.Wrap(json.NewDecoder(res.Body).Decode(result), "error decoding registry search results")
762 765
 }
763
-
764
-func isTimeout(err error) bool {
765
-	type timeout interface {
766
-		Timeout() bool
767
-	}
768
-	e := err
769
-	switch urlErr := err.(type) {
770
-	case *url.Error:
771
-		e = urlErr.Err
772
-	}
773
-	t, ok := e.(timeout)
774
-	return ok && t.Timeout()
775
-}
776
-
777
-func newJSONError(msg string, res *http.Response) error {
778
-	return &jsonmessage.JSONError{
779
-		Message: msg,
780
-		Code:    res.StatusCode,
781
-	}
782
-}