Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(subdomain-gw): curl on localhost (Option A: HTTP301+payload) #6982

Merged
merged 1 commit into from
Mar 13, 2020

Conversation

lidel
Copy link
Member

@lidel lidel commented Mar 11, 2020

This is a PR against feat/gateway-subdomains branch to resolve concerns from #6975

TL;DR

Return payload with HTTP 301 response:

  • curl returns exit code 0 on 301, so no script will fail
  • web browsers close connection after reading HTTP 301 and Location header, so there should not be any bandwidth wasted
    • just to be sure browsers don't store anything we return Clear-Site-Data header with such response

Description

When request is sent to http://localhost:8080/ipfs/$cid HTTP 301 status code with "Location" header redirect client to subdomain destination at $cid.ipfs.localhost:8080

Redirects are not followed by curl in default mode, but will be respected by user agents that follow redirects by default, namely web browsers.

To fix curl, we return correct payload in body of HTTP 301 response, but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

Caveat

This comes with side effect of prometeus client making redundant WriteHeader call, which produces warning in logs:

2020/03/11 14:57:06 http: superfluous response.WriteHeader call from github.com/prometheus/client_golang/prometheus/promhttp.(*responseWriterDelegator).WriteHeader (delegator.go:58)

I attempted to fix prometeus and avoid redundant call in https://github.com/prometheus/client_golang/pull/724 but am not sure if that approach will be approved upstream.

Update: superfluous response.WriteHeader call fixed in e705f02

@lidel lidel changed the title fix(subdomain-gw): curl without redirect on localhost (Option A) fix(subdomain-gw): curl on localhost (Option A: HTTP301+payload) Mar 11, 2020
lidel added a commit that referenced this pull request Mar 12, 2020
This changes the way we return CID payload in body of HTTP 301 response.
We no longer get superfluous response.WriteHeader call, as it is
executed only once, in http.ServeContent()

Gist:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: #6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
Comment on lines 53 to 58
func (sw *statusResponseWriter) WriteHeader(code int) {
// Check if we need to adjust Status Code to account for scheduled redirect
// This enables us to return HTTP 301
// for subdomain redirect in web browsers while also returning body for cli
// tools which does not follow redirects by default (curl, wget).
redirect := sw.w.Header().Get("Location")
if redirect != "" {
code = http.StatusMovedPermanently
}
sw.w.WriteHeader(code)
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I came up with this surgical wrapper because status code is hardcoded to 200 inside http.ServeContent().

Is this idiomatic/acceptable in go? Not sure if we can make this change more elegant while keeping is small without duplicating http.ServeContent.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping is normal. Swapping the code like this is weird but fine.

@lidel lidel requested a review from Stebalien March 12, 2020 00:44
@lidel lidel linked an issue Mar 12, 2020 that may be closed by this pull request
Comment on lines 53 to 58
func (sw *statusResponseWriter) WriteHeader(code int) {
// Check if we need to adjust Status Code to account for scheduled redirect
// This enables us to return HTTP 301
// for subdomain redirect in web browsers while also returning body for cli
// tools which does not follow redirects by default (curl, wget).
redirect := sw.w.Header().Get("Location")
if redirect != "" {
code = http.StatusMovedPermanently
}
sw.w.WriteHeader(code)
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wrapping is normal. Swapping the code like this is weird but fine.

core/corehttp/gateway_handler.go Outdated Show resolved Hide resolved
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: #6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
@Stebalien Stebalien merged commit df3c593 into feat/gateway-subdomains Mar 13, 2020
@Stebalien Stebalien deleted the fix/curl-on-localhost branch March 13, 2020 20:32
Stebalien pushed a commit that referenced this pull request Mar 18, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: #6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
Stebalien pushed a commit that referenced this pull request Mar 18, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: #6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
dgrisham pushed a commit to dgrisham/go-ipfs that referenced this pull request Apr 3, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: ipfs#6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
ralendor pushed a commit to ralendor/go-ipfs that referenced this pull request Jun 6, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: ipfs#6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
ralendor pushed a commit to ralendor/go-ipfs that referenced this pull request Jun 8, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: ipfs#6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
ralendor pushed a commit to ralendor/go-ipfs that referenced this pull request Jun 8, 2020
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: ipfs#6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>
hacdias pushed a commit to ipfs/boxo that referenced this pull request Jan 27, 2023
When request is sent to http://localhost:8080/ipfs/$cid response has
HTTP 301 status code and "Location" header with redirect destination at
$cid.ipfs.localhost:8080

Redirect is followed by browsersi, but not by commandline tools.
Status 301 is ignored by curl in default mode: it will print response
and won't follow redirect, user needs to add -L for that.

To fix curl, we return correct payload in body of HTTP 301 response,
but set Clear-Site-Data header to ensure Origin sandbox can't be abused.

This requires a surgical workaround:
If Location header is present in ResponseWriter's Header map,
we ensure http.ServeContent() returns HTTP 301

Context: ipfs/kubo#6982

License: MIT
Signed-off-by: Marcin Rataj <lidel@lidel.org>


This commit was moved from ipfs/kubo@f9567a0
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Update subdomain redirection logic to only engage on browsers
2 participants