github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/api/v2/urls_test.go (about)

     1  package v2
     2  
     3  import (
     4  	"net/http"
     5  	"net/url"
     6  	"testing"
     7  )
     8  
     9  type urlBuilderTestCase struct {
    10  	description  string
    11  	expectedPath string
    12  	build        func() (string, error)
    13  }
    14  
    15  func makeURLBuilderTestCases(urlBuilder *URLBuilder) []urlBuilderTestCase {
    16  	return []urlBuilderTestCase{
    17  		{
    18  			description:  "test base url",
    19  			expectedPath: "/v2/",
    20  			build:        urlBuilder.BuildBaseURL,
    21  		},
    22  		{
    23  			description:  "test tags url",
    24  			expectedPath: "/v2/foo/bar/tags/list",
    25  			build: func() (string, error) {
    26  				return urlBuilder.BuildTagsURL("foo/bar")
    27  			},
    28  		},
    29  		{
    30  			description:  "test manifest url",
    31  			expectedPath: "/v2/foo/bar/manifests/tag",
    32  			build: func() (string, error) {
    33  				return urlBuilder.BuildManifestURL("foo/bar", "tag")
    34  			},
    35  		},
    36  		{
    37  			description:  "build blob url",
    38  			expectedPath: "/v2/foo/bar/blobs/sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5",
    39  			build: func() (string, error) {
    40  				return urlBuilder.BuildBlobURL("foo/bar", "sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5")
    41  			},
    42  		},
    43  		{
    44  			description:  "build blob upload url",
    45  			expectedPath: "/v2/foo/bar/blobs/uploads/",
    46  			build: func() (string, error) {
    47  				return urlBuilder.BuildBlobUploadURL("foo/bar")
    48  			},
    49  		},
    50  		{
    51  			description:  "build blob upload url with digest and size",
    52  			expectedPath: "/v2/foo/bar/blobs/uploads/?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
    53  			build: func() (string, error) {
    54  				return urlBuilder.BuildBlobUploadURL("foo/bar", url.Values{
    55  					"size":   []string{"10000"},
    56  					"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
    57  				})
    58  			},
    59  		},
    60  		{
    61  			description:  "build blob upload chunk url",
    62  			expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part",
    63  			build: func() (string, error) {
    64  				return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part")
    65  			},
    66  		},
    67  		{
    68  			description:  "build blob upload chunk url with digest and size",
    69  			expectedPath: "/v2/foo/bar/blobs/uploads/uuid-part?digest=sha256%3A3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5&size=10000",
    70  			build: func() (string, error) {
    71  				return urlBuilder.BuildBlobUploadChunkURL("foo/bar", "uuid-part", url.Values{
    72  					"size":   []string{"10000"},
    73  					"digest": []string{"sha256:3b3692957d439ac1928219a83fac91e7bf96c153725526874673ae1f2023f8d5"},
    74  				})
    75  			},
    76  		},
    77  	}
    78  }
    79  
    80  // TestURLBuilder tests the various url building functions, ensuring they are
    81  // returning the expected values.
    82  func TestURLBuilder(t *testing.T) {
    83  	roots := []string{
    84  		"http://example.com",
    85  		"https://example.com",
    86  		"http://localhost:5000",
    87  		"https://localhost:5443",
    88  	}
    89  
    90  	for _, root := range roots {
    91  		urlBuilder, err := NewURLBuilderFromString(root)
    92  		if err != nil {
    93  			t.Fatalf("unexpected error creating urlbuilder: %v", err)
    94  		}
    95  
    96  		for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
    97  			url, err := testCase.build()
    98  			if err != nil {
    99  				t.Fatalf("%s: error building url: %v", testCase.description, err)
   100  			}
   101  
   102  			expectedURL := root + testCase.expectedPath
   103  
   104  			if url != expectedURL {
   105  				t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
   106  			}
   107  		}
   108  	}
   109  }
   110  
   111  func TestURLBuilderWithPrefix(t *testing.T) {
   112  	roots := []string{
   113  		"http://example.com/prefix/",
   114  		"https://example.com/prefix/",
   115  		"http://localhost:5000/prefix/",
   116  		"https://localhost:5443/prefix/",
   117  	}
   118  
   119  	for _, root := range roots {
   120  		urlBuilder, err := NewURLBuilderFromString(root)
   121  		if err != nil {
   122  			t.Fatalf("unexpected error creating urlbuilder: %v", err)
   123  		}
   124  
   125  		for _, testCase := range makeURLBuilderTestCases(urlBuilder) {
   126  			url, err := testCase.build()
   127  			if err != nil {
   128  				t.Fatalf("%s: error building url: %v", testCase.description, err)
   129  			}
   130  
   131  			expectedURL := root[0:len(root)-1] + testCase.expectedPath
   132  
   133  			if url != expectedURL {
   134  				t.Fatalf("%s: %q != %q", testCase.description, url, expectedURL)
   135  			}
   136  		}
   137  	}
   138  }
   139  
   140  type builderFromRequestTestCase struct {
   141  	request *http.Request
   142  	base    string
   143  }
   144  
   145  func TestBuilderFromRequest(t *testing.T) {
   146  	u, err := url.Parse("http://example.com")
   147  	if err != nil {
   148  		t.Fatal(err)
   149  	}
   150  
   151  	forwardedProtoHeader := make(http.Header, 1)
   152  	forwardedProtoHeader.Set("X-Forwarded-Proto", "https")
   153  
   154  	forwardedHostHeader1 := make(http.Header, 1)
   155  	forwardedHostHeader1.Set("X-Forwarded-Host", "first.example.com")
   156  
   157  	forwardedHostHeader2 := make(http.Header, 1)
   158  	forwardedHostHeader2.Set("X-Forwarded-Host", "first.example.com, proxy1.example.com")
   159  
   160  	testRequests := []struct {
   161  		request    *http.Request
   162  		base       string
   163  		configHost url.URL
   164  	}{
   165  		{
   166  			request: &http.Request{URL: u, Host: u.Host},
   167  			base:    "http://example.com",
   168  		},
   169  
   170  		{
   171  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
   172  			base:    "http://example.com",
   173  		},
   174  		{
   175  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
   176  			base:    "https://example.com",
   177  		},
   178  		{
   179  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader1},
   180  			base:    "http://first.example.com",
   181  		},
   182  		{
   183  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader2},
   184  			base:    "http://first.example.com",
   185  		},
   186  		{
   187  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedHostHeader2},
   188  			base:    "https://third.example.com:5000",
   189  			configHost: url.URL{
   190  				Scheme: "https",
   191  				Host:   "third.example.com:5000",
   192  			},
   193  		},
   194  	}
   195  
   196  	for _, tr := range testRequests {
   197  		var builder *URLBuilder
   198  		if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
   199  			builder = NewURLBuilder(&tr.configHost)
   200  		} else {
   201  			builder = NewURLBuilderFromRequest(tr.request)
   202  		}
   203  
   204  		for _, testCase := range makeURLBuilderTestCases(builder) {
   205  			buildURL, err := testCase.build()
   206  			if err != nil {
   207  				t.Fatalf("%s: error building url: %v", testCase.description, err)
   208  			}
   209  
   210  			var expectedURL string
   211  			proto, ok := tr.request.Header["X-Forwarded-Proto"]
   212  			if !ok {
   213  				expectedURL = tr.base + testCase.expectedPath
   214  			} else {
   215  				urlBase, err := url.Parse(tr.base)
   216  				if err != nil {
   217  					t.Fatal(err)
   218  				}
   219  				urlBase.Scheme = proto[0]
   220  				expectedURL = urlBase.String() + testCase.expectedPath
   221  			}
   222  
   223  			if buildURL != expectedURL {
   224  				t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
   225  			}
   226  		}
   227  	}
   228  }
   229  
   230  func TestBuilderFromRequestWithPrefix(t *testing.T) {
   231  	u, err := url.Parse("http://example.com/prefix/v2/")
   232  	if err != nil {
   233  		t.Fatal(err)
   234  	}
   235  
   236  	forwardedProtoHeader := make(http.Header, 1)
   237  	forwardedProtoHeader.Set("X-Forwarded-Proto", "https")
   238  
   239  	testRequests := []struct {
   240  		request    *http.Request
   241  		base       string
   242  		configHost url.URL
   243  	}{
   244  		{
   245  			request: &http.Request{URL: u, Host: u.Host},
   246  			base:    "http://example.com/prefix/",
   247  		},
   248  
   249  		{
   250  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
   251  			base:    "http://example.com/prefix/",
   252  		},
   253  		{
   254  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
   255  			base:    "https://example.com/prefix/",
   256  		},
   257  		{
   258  			request: &http.Request{URL: u, Host: u.Host, Header: forwardedProtoHeader},
   259  			base:    "https://subdomain.example.com/prefix/",
   260  			configHost: url.URL{
   261  				Scheme: "https",
   262  				Host:   "subdomain.example.com",
   263  				Path:   "/prefix/",
   264  			},
   265  		},
   266  	}
   267  
   268  	for _, tr := range testRequests {
   269  		var builder *URLBuilder
   270  		if tr.configHost.Scheme != "" && tr.configHost.Host != "" {
   271  			builder = NewURLBuilder(&tr.configHost)
   272  		} else {
   273  			builder = NewURLBuilderFromRequest(tr.request)
   274  		}
   275  
   276  		for _, testCase := range makeURLBuilderTestCases(builder) {
   277  			buildURL, err := testCase.build()
   278  			if err != nil {
   279  				t.Fatalf("%s: error building url: %v", testCase.description, err)
   280  			}
   281  			var expectedURL string
   282  			proto, ok := tr.request.Header["X-Forwarded-Proto"]
   283  			if !ok {
   284  				expectedURL = tr.base[0:len(tr.base)-1] + testCase.expectedPath
   285  			} else {
   286  				urlBase, err := url.Parse(tr.base)
   287  				if err != nil {
   288  					t.Fatal(err)
   289  				}
   290  				urlBase.Scheme = proto[0]
   291  				expectedURL = urlBase.String()[0:len(urlBase.String())-1] + testCase.expectedPath
   292  			}
   293  
   294  			if buildURL != expectedURL {
   295  				t.Fatalf("%s: %q != %q", testCase.description, buildURL, expectedURL)
   296  			}
   297  		}
   298  	}
   299  }