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

HTTP (not HTTPS) response has no Content-Length #288

Open
itaisod opened this issue May 5, 2019 · 14 comments
Open

HTTP (not HTTPS) response has no Content-Length #288

itaisod opened this issue May 5, 2019 · 14 comments
Labels

Comments

@itaisod
Copy link

itaisod commented May 5, 2019

Steps to reproduce (tested on both mac and ubuntu):

  1. go get github.com/google/martian/ && go install github.com/google/martian/cmd/proxy
  2. ~/go/bin/proxy
  3. curl -v "http://www.example.com/" --proxy localhost:8080

Result: curl hangs forever.

lab@ubuntu:~$ curl -v "http://www.example.com/" --proxy localhost:8080 > /dev/null
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0*   Trying ::1...
* TCP_NODELAY set
* Connected to localhost (::1) port 8080 (#0)
> GET http://www.example.com/ HTTP/1.1
> Host: www.example.com
> User-Agent: curl/7.58.0
> Accept: */*
> Proxy-Connection: Keep-Alive
>
< HTTP/1.1 200 OK
< Cache-Control: max-age=604800
< Content-Type: text/html; charset=UTF-8
< Date: Sun, 05 May 2019 15:22:16 GMT
< Etag: "1541025663+ident+gzip"
< Expires: Sun, 12 May 2019 15:22:16 GMT
< Last-Modified: Fri, 09 Aug 2013 23:54:35 GMT
< Server: ECS (dcb/7EA2)
< Vary: Accept-Encoding
< X-Cache: HIT
* no chunk, no close, no size. Assume close to signal end
<
{ [1270 bytes data]
100  1270    0  1270    0     0    172      0 --:--:--  0:00:07 --:--:--     0
@hueich
Copy link
Collaborator

hueich commented May 17, 2019

Thanks for the repro! This looks bad, we'll have someone take a look soon.

@hueich hueich added the bug label May 17, 2019
@permafrosh
Copy link

I was unable to reproduce the issue, but I had to take the following steps because Martian wasn't set up.

  1. go get github.com/google/martian/
  2. go install github.com/google/martian/cmd/proxy
  3. go get golang.org/x/net/websocket
  4. go install github.com/google/martian/cmd/proxy
  5. ~/go/bin/proxy
  6. curl -v "http://www.example.com/" --proxy localhost:8080

And curl returns the expected response.

@itaisod
Copy link
Author

itaisod commented Jun 3, 2019

It does not terminate though. curl does not know when the response body is complete. Try this:
curl "http://www.example.com/" --proxy localhost:8080 > /dev/null 2> /dev/null && echo SUCCESS
It won't display SUCCESS. This one however, will display SUCCESS:
curl "http://www.example.com/" > /dev/null 2> /dev/null && echo SUCCESS

@bramhaghosh bramhaghosh reopened this Jun 3, 2019
@hueich
Copy link
Collaborator

hueich commented Jun 9, 2019

@itaisod What's the version of Go you're using?

@itaisod
Copy link
Author

itaisod commented Jun 9, 2019

1.12.5

@hueich
Copy link
Collaborator

hueich commented Jul 6, 2019

After investigating, seems that example.com just doesn't respond with a Content-Length header, so Martian just faithfully proxies whatever it got. Try the same thing with another website without https, such as http://www.baidu.com/ and they return a Content-Length. Thanks for reporting this, and let us know if you find any more bugs in the future.

@hueich hueich closed this as completed Jul 6, 2019
@itaisod
Copy link
Author

itaisod commented Nov 5, 2019

image
image
image
I dunno, to me it clearly looks like it's returning a Content-Length. But whatever.

@hueich
Copy link
Collaborator

hueich commented Nov 5, 2019

You're right. During testing I somehow mistook the proxied output for the no proxy output and that was missing the Content-Length header. I'm starting to suspect there's some order dependency in the header processing, and perhaps anything after the X-Cache header is getting dropped, which in the case of example.com was the Content-Length header. Will take a closer look soon.

@hueich hueich reopened this Nov 5, 2019
@thanks173
Copy link

This is the behavior of Go's Transport, according to this issue.

If we want to retain the Content-Length header, we must set DisableCompression of http.Transport to true.

I want to create a PR, but should I add the Accept-Encoding: gzip header for every request like Go do, or I just let users decide if they want gzip or not?

@bramhaghosh
Copy link
Member

bramhaghosh commented Jun 17, 2020 via email

@thanks173
Copy link

So we just leave this bug there?

@itaisod
Copy link
Author

itaisod commented Jun 18, 2020

If martian can't provide Content-Length header in the response, at the very least it should close the connection when it's done and not just leave it hanging forever... Otherwise, it can either pipe the original data unmodified along with the original Content-Length and Content-Encoding, or read the whole data into a buffer first, and then set Content-Length in the response to whatever size it wants, compressed/uncompressed.

I'm 100% sure it's fixable. Not that I mind though, I'm not using martian.

@bramhaghosh
Copy link
Member

Yeah I think @itaisod is correct. The fix is to "pipe the original data unmodified along with the original Content-Length and Content-Encoding". My concern with setting DisableCompression to true is that it would be decompressed for all requests - regardless of whether they want it or not.

@thanks173
Copy link

My concern with setting DisableCompression to true is that it would be decompressed for all requests - regardless of whether they want it or not.

Setting DisableCompression to true will not disable compression for all request. Instead, it will respect the client's request: if the request contains the Accept-Encoding: gzip header, the response would be compressed, and then it's the client's responsibility to decompress the gzip response. The DisableCompression actually means DisableForcingCompression.

The fix is to "pipe the original data unmodified along with the original Content-Length and Content-Encoding".

With setting DisableCompression to false, all requests would be compressed by internal go package. go will do the decompression for us internally if the original request doesn't contain the Accept-Encoding: gzip header, so the original Content-Length and Content-Encoding would be incorrect, that's why they remove them.

I thinks that martian, as a proxy, should respect the client's request and let them decide if they want the Accept-Encoding: gzip header or not.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

5 participants