Merge lp:~axwalk/juju-core/httpstorage-cleanup into lp:~go-bot/juju-core/trunk

Proposed by Andrew Wilkins
Status: Merged
Approved by: Andrew Wilkins
Approved revision: no longer in the source branch.
Merged at revision: 1956
Proposed branch: lp:~axwalk/juju-core/httpstorage-cleanup
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 170 lines (+58/-25)
2 files modified
environs/httpstorage/backend.go (+31/-18)
environs/httpstorage/backend_test.go (+27/-7)
To merge this branch: bzr merge lp:~axwalk/juju-core/httpstorage-cleanup
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+189545@code.launchpad.net

Commit message

environs/httpstorage: cleanup

- s/authoris/authoriz/
- use net.SplitHostPort, and cater for req.Host
  not containing a port
- test HEAD response Location URL, to ensure
  it's valid for the storage

https://codereview.appspot.com/14483043/

Description of the change

environs/httpstorage: cleanup

- s/authoris/authoriz/
- use net.SplitHostPort, and cater for req.Host
  not containing a port
- test HEAD response Location URL, to ensure
  it's valid for the storage

https://codereview.appspot.com/14483043/

To post a comment you must log in.
Revision history for this message
Andrew Wilkins (axwalk) wrote :
Download full text (7.0 KiB)

Reviewers: mp+189545_code.launchpad.net,

Message:
Please take a look.

Description:
environs/httpstorage: cleanup

- s/authoris/authoriz/
- use net.SplitHostPort, and cater for req.Host
   not containing a port
- test HEAD response Location URL, to ensure
   it's valid for the storage

https://code.launchpad.net/~axwalk/juju-core/httpstorage-cleanup/+merge/189545

(do not edit description out of merge proposal)

Please review this at https://codereview.appspot.com/14483043/

Affected files (+60, -25 lines):
   [revision details]
   environs/httpstorage/backend.go
   environs/httpstorage/backend_test.go

Index: [revision details]
=== added file '[revision details]'
--- [revision details] 2012-01-01 00:00:00 +0000
+++ [revision details] 2012-01-01 00:00:00 +0000
@@ -0,0 +1,2 @@
+Old revision: tarmac-20131004160159-i9eoormyw24etfr4
+New revision: <email address hidden>

Index: environs/httpstorage/backend.go
=== modified file 'environs/httpstorage/backend.go'
--- environs/httpstorage/backend.go 2013-10-04 07:38:49 +0000
+++ environs/httpstorage/backend.go 2013-10-07 08:24:22 +0000
@@ -36,9 +36,9 @@
   switch req.Method {
   case "PUT", "DELETE":
    // Don't allow modifying operations if there's an HTTPS backend
- // to handle that, and ensure the user is authorised/authenticated.
- if s.httpsPort != 0 || !s.authorised(req) {
- http.Error(w, "unauthorised access", http.StatusUnauthorized)
+ // to handle that, and ensure the user is authorized/authenticated.
+ if s.httpsPort != 0 || !s.authorized(req) {
+ http.Error(w, "unauthorized access", http.StatusUnauthorized)
     return
    }
   }
@@ -60,30 +60,43 @@
   }
  }

-// authorised checks that either the storage does not require
-// authorisation, or the user has specified the correct auth key.
-func (s *storageBackend) authorised(req *http.Request) bool {
+// authorized checks that either the storage does not require
+// authorization, or the user has specified the correct auth key.
+func (s *storageBackend) authorized(req *http.Request) bool {
   if s.authkey == "" {
    return true
   }
   return req.URL.Query().Get("authkey") == s.authkey
  }

+// hostOnly splits a host of the form host, or host:port,
+// into its host and port parts, and returns the host part.
+func hostOnly(host string) (string, error) {
+ hostonly, _, err := net.SplitHostPort(host)
+ if err != nil {
+ // err may be because of missing :port. Checking
+ // the error message is brittle, so let's try
+ // again with ":0" tacked on the end.
+ var err2 error
+ hostonly, _, err = net.SplitHostPort(host + ":0")
+ if err2 != nil {
+ // something heinous, return the original error
+ return "", err
+ }
+ }
+ return hostonly, nil
+}
+
  // handleHead returns the HTTPS URL for the specified
  // path in the Location header.
  func (s *storageBackend) handleHead(w http.ResponseWriter, req
*http.Request) {
   if s.httpsPort != 0 {
- hostonly := req.Host
- if i := strings.LastIndex(hostonly, "]"); i != -1 {
- // [ipv6]:port
- hostonly = hostonly[:i+1]
- } else {
- // host:port
- if i := strings.LastIndex(hostonly, ":"); i != -1 {
- hostonly = hostonly[:i]
- }
+...

Read more...

Revision history for this message
Andrew Wilkins (axwalk) wrote :
Revision history for this message
William Reade (fwereade) wrote :

LGTM, looks like an improvement to me :).

https://codereview.appspot.com/14483043/

Revision history for this message
Go Bot (go-bot) wrote :
Download full text (42.9 KiB)

The attempt to merge lp:~axwalk/juju-core/httpstorage-cleanup into lp:juju-core failed. Below is the output from the failed tests.

ok launchpad.net/juju-core/agent 0.291s
ok launchpad.net/juju-core/agent/tools 0.227s
ok launchpad.net/juju-core/bzr 24.417s
ok launchpad.net/juju-core/cert 3.888s
ok launchpad.net/juju-core/charm 0.765s
? launchpad.net/juju-core/charm/hooks [no test files]
ok launchpad.net/juju-core/cloudinit 0.100s
ok launchpad.net/juju-core/cmd 0.298s
? launchpad.net/juju-core/cmd/charmd [no test files]
? launchpad.net/juju-core/cmd/charmload [no test files]
ok launchpad.net/juju-core/cmd/juju 279.074s
ok launchpad.net/juju-core/cmd/jujud 76.216s
ok launchpad.net/juju-core/cmd/plugins/juju-metadata 2.171s
ok launchpad.net/juju-core/constraints 0.028s
ok launchpad.net/juju-core/container/lxc 0.377s
? launchpad.net/juju-core/container/lxc/mock [no test files]
ok launchpad.net/juju-core/downloader 5.293s
ok launchpad.net/juju-core/environs 13.326s
ok launchpad.net/juju-core/environs/bootstrap 4.940s
ok launchpad.net/juju-core/environs/cloudinit 0.472s
ok launchpad.net/juju-core/environs/config 0.747s
ok launchpad.net/juju-core/environs/configstore 0.098s
ok launchpad.net/juju-core/environs/filestorage 0.031s
ok launchpad.net/juju-core/environs/httpstorage 1.218s
ok launchpad.net/juju-core/environs/imagemetadata 0.505s
ok launchpad.net/juju-core/environs/instances 0.054s
ok launchpad.net/juju-core/environs/jujutest 0.261s
ok launchpad.net/juju-core/environs/manual 5.175s
ok launchpad.net/juju-core/environs/simplestreams 0.360s
? launchpad.net/juju-core/environs/simplestreams/testing [no test files]
ok launchpad.net/juju-core/environs/sshstorage 1.288s
ok launchpad.net/juju-core/environs/storage 1.176s
ok launchpad.net/juju-core/environs/sync 37.287s
ok launchpad.net/juju-core/environs/testing 0.227s
ok launchpad.net/juju-core/environs/tools 7.697s
? launchpad.net/juju-core/environs/tools/testing [no test files]
ok launchpad.net/juju-core/errors 0.022s
ok launchpad.net/juju-core/instance 0.036s
? launchpad.net/juju-core/instance/testing [no test files]

----------------------------------------------------------------------
FAIL: apiconn_test.go:0: DeployLocalSuite.TearDownTest

Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for sockets to die: 0 in use, 1 alive
Waiting for s...

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'environs/httpstorage/backend.go'
2--- environs/httpstorage/backend.go 2013-10-04 07:38:49 +0000
3+++ environs/httpstorage/backend.go 2013-10-07 08:39:18 +0000
4@@ -36,9 +36,9 @@
5 switch req.Method {
6 case "PUT", "DELETE":
7 // Don't allow modifying operations if there's an HTTPS backend
8- // to handle that, and ensure the user is authorised/authenticated.
9- if s.httpsPort != 0 || !s.authorised(req) {
10- http.Error(w, "unauthorised access", http.StatusUnauthorized)
11+ // to handle that, and ensure the user is authorized/authenticated.
12+ if s.httpsPort != 0 || !s.authorized(req) {
13+ http.Error(w, "unauthorized access", http.StatusUnauthorized)
14 return
15 }
16 }
17@@ -60,30 +60,43 @@
18 }
19 }
20
21-// authorised checks that either the storage does not require
22-// authorisation, or the user has specified the correct auth key.
23-func (s *storageBackend) authorised(req *http.Request) bool {
24+// authorized checks that either the storage does not require
25+// authorization, or the user has specified the correct auth key.
26+func (s *storageBackend) authorized(req *http.Request) bool {
27 if s.authkey == "" {
28 return true
29 }
30 return req.URL.Query().Get("authkey") == s.authkey
31 }
32
33+// hostOnly splits a host of the form host, or host:port,
34+// into its host and port parts, and returns the host part.
35+func hostOnly(host string) (string, error) {
36+ hostonly, _, err := net.SplitHostPort(host)
37+ if err != nil {
38+ // err may be because of missing :port. Checking
39+ // the error message is brittle, so let's try
40+ // again with ":0" tacked on the end.
41+ var err2 error
42+ hostonly, _, err = net.SplitHostPort(host + ":0")
43+ if err2 != nil {
44+ // something heinous, return the original error
45+ return "", err
46+ }
47+ }
48+ return hostonly, nil
49+}
50+
51 // handleHead returns the HTTPS URL for the specified
52 // path in the Location header.
53 func (s *storageBackend) handleHead(w http.ResponseWriter, req *http.Request) {
54 if s.httpsPort != 0 {
55- hostonly := req.Host
56- if i := strings.LastIndex(hostonly, "]"); i != -1 {
57- // [ipv6]:port
58- hostonly = hostonly[:i+1]
59- } else {
60- // host:port
61- if i := strings.LastIndex(hostonly, ":"); i != -1 {
62- hostonly = hostonly[:i]
63- }
64+ host, err := hostOnly(req.Host)
65+ if err != nil {
66+ http.Error(w, fmt.Sprintf("failed to split host: %v", err), http.StatusBadRequest)
67+ return
68 }
69- url := fmt.Sprintf("https://%s:%d%s", hostonly, s.httpsPort, req.URL.Path)
70+ url := fmt.Sprintf("https://%s:%d%s", host, s.httpsPort, req.URL.Path)
71 w.Header().Set("Location", url)
72 } else {
73 http.Error(w, "method HEAD is not supported", http.StatusMethodNotAllowed)
74@@ -139,8 +152,8 @@
75
76 // handleDelete removes a file from the storage.
77 func (s *storageBackend) handleDelete(w http.ResponseWriter, req *http.Request) {
78- if !s.authorised(req) {
79- http.Error(w, "unauthorised access", http.StatusUnauthorized)
80+ if !s.authorized(req) {
81+ http.Error(w, "unauthorized access", http.StatusUnauthorized)
82 return
83 }
84 err := s.backend.Remove(req.URL.Path[1:])
85
86=== modified file 'environs/httpstorage/backend_test.go'
87--- environs/httpstorage/backend_test.go 2013-10-04 08:06:32 +0000
88+++ environs/httpstorage/backend_test.go 2013-10-07 08:39:18 +0000
89@@ -134,22 +134,42 @@
90 },
91 }
92
93-func (s *backendSuite) TestHead(c *gc.C) {
94+func (s *backendSuite) TestHeadNonAuth(c *gc.C) {
95 // HEAD is unsupported for non-authenticating servers.
96 listener, url, _ := startServer(c)
97 defer listener.Close()
98 resp, err := http.Head(url)
99 c.Assert(err, gc.IsNil)
100 c.Assert(resp.StatusCode, gc.Equals, http.StatusMethodNotAllowed)
101+}
102
103+func (s *backendSuite) TestHeadAuth(c *gc.C) {
104 // HEAD on an authenticating server will return the HTTPS counterpart URL.
105+ client, url, datadir := s.tlsServerAndClient(c)
106+ createTestData(c, datadir)
107+
108+ resp, err := client.Head(url)
109+ c.Assert(err, gc.IsNil)
110+ c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
111+ location, err := resp.Location()
112+ c.Assert(err, gc.IsNil)
113+ c.Assert(location.String(), gc.Matches, "https://localhost:[0-9]{5}/")
114+ testGet(c, client, location.String())
115+}
116+
117+func (s *backendSuite) TestHeadCustomHost(c *gc.C) {
118+ // HEAD with a custom "Host:" header; the server should respond
119+ // with a Location with the specified Host header.
120 client, url, _ := s.tlsServerAndClient(c)
121- resp, err = client.Head(url + "arbitrary")
122+ req, err := http.NewRequest("HEAD", url+"arbitrary", nil)
123+ c.Assert(err, gc.IsNil)
124+ req.Host = "notarealhost"
125+ resp, err := client.Do(req)
126 c.Assert(err, gc.IsNil)
127 c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
128 location, err := resp.Location()
129 c.Assert(err, gc.IsNil)
130- c.Assert(location.String(), gc.Matches, "https://localhost:[0-9]{5}/arbitrary")
131+ c.Assert(location.String(), gc.Matches, "https://notarealhost:[0-9]{5}/arbitrary")
132 }
133
134 func (s *backendSuite) TestGet(c *gc.C) {
135@@ -283,7 +303,7 @@
136 testPut(c, http.DefaultClient, url, dataDir, true)
137 }
138
139-func testPut(c *gc.C, client *http.Client, url, dataDir string, authorised bool) {
140+func testPut(c *gc.C, client *http.Client, url, dataDir string, authorized bool) {
141 check := func(tc testCase) {
142 req, err := http.NewRequest("PUT", url+tc.name, bytes.NewBufferString(tc.content))
143 c.Assert(err, gc.IsNil)
144@@ -293,7 +313,7 @@
145 if tc.status != 0 {
146 c.Assert(resp.StatusCode, gc.Equals, tc.status)
147 return
148- } else if !authorised {
149+ } else if !authorized {
150 c.Assert(resp.StatusCode, gc.Equals, http.StatusUnauthorized)
151 return
152 }
153@@ -341,7 +361,7 @@
154 testRemove(c, http.DefaultClient, url, dataDir, true)
155 }
156
157-func testRemove(c *gc.C, client *http.Client, url, dataDir string, authorised bool) {
158+func testRemove(c *gc.C, client *http.Client, url, dataDir string, authorized bool) {
159 check := func(tc testCase) {
160 fp := filepath.Join(dataDir, tc.name)
161 dir, _ := filepath.Split(fp)
162@@ -357,7 +377,7 @@
163 if tc.status != 0 {
164 c.Assert(resp.StatusCode, gc.Equals, tc.status)
165 return
166- } else if !authorised {
167+ } else if !authorized {
168 c.Assert(resp.StatusCode, gc.Equals, http.StatusUnauthorized)
169 return
170 }

Subscribers

People subscribed via source and target branches

to status/vote changes: