Merge lp:~axwalk/juju-core/lp1235102-httpstorage-head 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: 1950
Proposed branch: lp:~axwalk/juju-core/lp1235102-httpstorage-head
Merge into: lp:~go-bot/juju-core/trunk
Diff against target: 77 lines (+19/-8)
2 files modified
environs/httpstorage/backend.go (+17/-6)
environs/httpstorage/backend_test.go (+2/-2)
To merge this branch: bzr merge lp:~axwalk/juju-core/lp1235102-httpstorage-head
Reviewer Review Type Date Requested Status
Juju Engineering Pending
Review via email: mp+189225@code.launchpad.net

Commit message

environs/httpstorage: use req.Host in HEAD

The HEAD response was returning the listening IP
address, rather than the host presented in the
original HTTP Request. This is changed to now use
the request's Host field.

Fixes #1235102

https://codereview.appspot.com/14388043/

Description of the change

environs/httpstorage: use req.Host in HEAD

The HEAD response was returning the listening IP
address, rather than the host presented in the
original HTTP Request. This is changed to now use
the request's Host field.

Fixes #1235102

https://codereview.appspot.com/14388043/

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

Reviewers: mp+189225_code.launchpad.net,

Message:
Please take a look.

Description:
environs/httpstorage: use req.Host in HEAD

The HEAD response was returning the listening IP
address, rather than the host presented in the
original HTTP Request. This is changed to now use
the request's Host field.

Fixes #1235102

https://code.launchpad.net/~axwalk/juju-core/lp1235102-httpstorage-head/+merge/189225

(do not edit description out of merge proposal)

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

Affected files (+19, -6 lines):
   A [revision details]
   M environs/httpstorage/backend.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-20131003170932-4tkr0tu40wb0nfgl
+New revision: <email address hidden>

Index: environs/httpstorage/backend.go
=== modified file 'environs/httpstorage/backend.go'
--- environs/httpstorage/backend.go 2013-10-02 05:48:00 +0000
+++ environs/httpstorage/backend.go 2013-10-04 07:38:49 +0000
@@ -22,9 +22,9 @@
  type storageBackend struct {
   backend storage.Storage

- // httpsBaseURL is the base URL to send to clients
+ // httpsPort is the port to send to clients
   // if they perform a HEAD request.
- httpsBaseURL string
+ httpsPort int

   // authkey is non-empty if modifying requests
   // require an auth key.
@@ -37,7 +37,7 @@
   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.httpsBaseURL != "" || !s.authorised(req) {
+ if s.httpsPort != 0 || !s.authorised(req) {
     http.Error(w, "unauthorised access", http.StatusUnauthorized)
     return
    }
@@ -72,8 +72,19 @@
  // 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.httpsBaseURL != "" {
- w.Header().Set("Location", s.httpsBaseURL+req.URL.Path)
+ 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]
+ }
+ }
+ url := fmt.Sprintf("https://%s:%d%s", hostonly, s.httpsPort,
req.URL.Path)
+ w.Header().Set("Location", url)
   } else {
    http.Error(w, "method HEAD is not supported",
http.StatusMethodNotAllowed)
    return
@@ -192,7 +203,7 @@
     listener.Close()
     return nil, fmt.Errorf("cannot start TLS listener: %v", err)
    }
- backend.httpsBaseURL = fmt.Sprintf("https://%s", tlsListener.Addr())
+ backend.httpsPort = tlsListener.Addr().(*net.TCPAddr).Port
    goServe(tlsListener, tlsBackend)
   }
   goServe(listener, backend)

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

LGTM with some minor grumblings.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go
File environs/httpstorage/backend.go (right):

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode65
environs/httpstorage/backend.go:65: func (s *storageBackend)
authorised(req *http.Request) bool {
s/authorised/authorized/

We standardise on US spelling in this code base,
to match Go's conventions.
(I just spent a while grepping for "authorized")

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode76
environs/httpstorage/backend.go:76: hostonly := req.Host
Can't you use net.SplitHostPort here?

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode86
environs/httpstorage/backend.go:86: url :=
fmt.Sprintf("https://%s:%d%s", hostonly, s.httpsPort, req.URL.Path)
tbh this feel like abuse of the HEAD method.
It should at least check that req.URL.Path is /.
But if it's conventional, I *guess* it's ok.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend_test.go
File environs/httpstorage/backend_test.go (right):

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend_test.go#newcode152
environs/httpstorage/backend_test.go:152: c.Assert(location.String(),
gc.Matches, "https://localhost:[0-9]{5}/arbitrary")
We should continue with the test and check that we can
actually connect with the given URL.

https://codereview.appspot.com/14388043/

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

On 2013/10/04 12:08:36, rog wrote:
> LGTM with some minor grumblings.

Thanks, I'll address these in another CL since I've already landed this.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go
> File environs/httpstorage/backend.go (right):

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode65
> environs/httpstorage/backend.go:65: func (s *storageBackend)
authorised(req
> *http.Request) bool {
> s/authorised/authorized/

> We standardise on US spelling in this code base,
> to match Go's conventions.
> (I just spent a while grepping for "authorized")

Thanks, will update.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode76
> environs/httpstorage/backend.go:76: hostonly := req.Host
> Can't you use net.SplitHostPort here?

Yes. I thought there was a function, just didn't find it in my
admittedly short search.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend.go#newcode86
> environs/httpstorage/backend.go:86: url :=
fmt.Sprintf("https://%s:%d%s",
> hostonly, s.httpsPort, req.URL.Path)
> tbh this feel like abuse of the HEAD method.

Indeed :)
I considered doing redirects, but not all client methods follow them,
and it'd cause two requests for each Put/Remove.

> It should at least check that req.URL.Path is /.
> But if it's conventional, I *guess* it's ok.

So, the only way Path might be empty is if the request line had URI with
no path. Right?
Never going to happen for this, so I'd rather not complicate it.

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend_test.go
> File environs/httpstorage/backend_test.go (right):

https://codereview.appspot.com/14388043/diff/4001/environs/httpstorage/backend_test.go#newcode152
> environs/httpstorage/backend_test.go:152: c.Assert(location.String(),
> gc.Matches, "https://localhost:[0-9]{5}/arbitrary")
> We should continue with the test and check that we can
> actually connect with the given URL.

Okay.

https://codereview.appspot.com/14388043/

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-02 05:48:00 +0000
3+++ environs/httpstorage/backend.go 2013-10-04 08:07:30 +0000
4@@ -22,9 +22,9 @@
5 type storageBackend struct {
6 backend storage.Storage
7
8- // httpsBaseURL is the base URL to send to clients
9+ // httpsPort is the port to send to clients
10 // if they perform a HEAD request.
11- httpsBaseURL string
12+ httpsPort int
13
14 // authkey is non-empty if modifying requests
15 // require an auth key.
16@@ -37,7 +37,7 @@
17 case "PUT", "DELETE":
18 // Don't allow modifying operations if there's an HTTPS backend
19 // to handle that, and ensure the user is authorised/authenticated.
20- if s.httpsBaseURL != "" || !s.authorised(req) {
21+ if s.httpsPort != 0 || !s.authorised(req) {
22 http.Error(w, "unauthorised access", http.StatusUnauthorized)
23 return
24 }
25@@ -72,8 +72,19 @@
26 // handleHead returns the HTTPS URL for the specified
27 // path in the Location header.
28 func (s *storageBackend) handleHead(w http.ResponseWriter, req *http.Request) {
29- if s.httpsBaseURL != "" {
30- w.Header().Set("Location", s.httpsBaseURL+req.URL.Path)
31+ if s.httpsPort != 0 {
32+ hostonly := req.Host
33+ if i := strings.LastIndex(hostonly, "]"); i != -1 {
34+ // [ipv6]:port
35+ hostonly = hostonly[:i+1]
36+ } else {
37+ // host:port
38+ if i := strings.LastIndex(hostonly, ":"); i != -1 {
39+ hostonly = hostonly[:i]
40+ }
41+ }
42+ url := fmt.Sprintf("https://%s:%d%s", hostonly, s.httpsPort, req.URL.Path)
43+ w.Header().Set("Location", url)
44 } else {
45 http.Error(w, "method HEAD is not supported", http.StatusMethodNotAllowed)
46 return
47@@ -192,7 +203,7 @@
48 listener.Close()
49 return nil, fmt.Errorf("cannot start TLS listener: %v", err)
50 }
51- backend.httpsBaseURL = fmt.Sprintf("https://%s", tlsListener.Addr())
52+ backend.httpsPort = tlsListener.Addr().(*net.TCPAddr).Port
53 goServe(tlsListener, tlsBackend)
54 }
55 goServe(listener, backend)
56
57=== modified file 'environs/httpstorage/backend_test.go'
58--- environs/httpstorage/backend_test.go 2013-10-02 05:48:00 +0000
59+++ environs/httpstorage/backend_test.go 2013-10-04 08:07:30 +0000
60@@ -61,7 +61,7 @@
61 caKeyPEM := []byte(coretesting.CAKey)
62 listener, err = httpstorage.ServeTLS("127.0.0.1:0", embedded, caCertPEM, caKeyPEM, hostnames, testAuthkey)
63 c.Assert(err, gc.IsNil)
64- return listener, fmt.Sprintf("http://%s/", listener.Addr()), dataDir
65+ return listener, fmt.Sprintf("http://localhost:%d/", listener.Addr().(*net.TCPAddr).Port), dataDir
66 }
67
68 type testCase struct {
69@@ -149,7 +149,7 @@
70 c.Assert(resp.StatusCode, gc.Equals, http.StatusOK)
71 location, err := resp.Location()
72 c.Assert(err, gc.IsNil)
73- c.Assert(location.String(), gc.Matches, "https://127.0.0.1:[0-9]{5}/arbitrary")
74+ c.Assert(location.String(), gc.Matches, "https://localhost:[0-9]{5}/arbitrary")
75 }
76
77 func (s *backendSuite) TestGet(c *gc.C) {

Subscribers

People subscribed via source and target branches

to status/vote changes: