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

net/http: ServeContent() doesn't handle "If-Modified-Since" correctly with byte range requests #9158

Closed
gopherbot opened this issue Nov 24, 2014 · 5 comments

Comments

Projects
None yet
2 participants
@gopherbot
Copy link

commented Nov 24, 2014

by rjbrown:

If you pass the file's last modified time to ServeContent(), it will cause byte range
requests to fail after the first one.

go version go1.3.3 darwin/amd64

What steps reproduce the problem?
1. build the attached program
2. put a largish movie file in the current directory
3. run the program
3. open the movie file in Chrome browser ( localhost:3000/[moviename.mp4] )

What happened?

the movie does not play, or only plays a few seceonds 

What should have happened instead?

the movie should play

Attachments:

  1. serveContent.go (758 bytes)
@bradfitz

This comment has been minimized.

Copy link
Member

commented Nov 25, 2014

Comment 1:

This bug is too vague for me to take any action.
The subject hints at a problem with If-Modified-Since, but you don't describe what the
bug is.
"The movie should play" is too high level. Please tell me what Go is doing wrong and how
it is violating HTTP if you know or can easily find out.

Status changed to WaitingForReply.

@bradfitz

This comment has been minimized.

Copy link
Member

commented Nov 25, 2014

Comment 2:

Also, try Go 1.4beta1, as Go 1.3.3 won't get any more updates:
https://golang.org/dl/#go1.4rc1
@gopherbot

This comment has been minimized.

Copy link
Author

commented Nov 25, 2014

Comment 3 by rjbrown:

Sorry it's too vague.  The high level issue is that passing the file's last modified
time to ServeContent() causes it to fail when Chrome requests byte ranges, as it will do
when playing a movie.  
You can see the problem if you compile and run the file I sent, and try to use it to
serve a movie to chrome. (note I think I left in a extra import of "time").  You can see
it working better if you pass in time.Time{} for file modification time, but that turns
off caching altogether.
One option would be to simply ignore the last modified time if there are byte ranges,
and treat it as if time.Time{} was passed in instead.
If you want to go deeper, I think it may require using ETag header which I don't claim
to understand.
I have compared the relevant request and response headers between node.js/Express, which
seems to work well, and Go:
Go:
 request stuff:
  If-Range:Wed, 24 Sep 2014 03:40:19 GMT
  Range:bytes=311341427-311341481
 response stuff:
  Accept-Ranges: bytes
  Content-Length: 311341482 
  Content-Type: video/mp4
  Last-Modified: Wed, 24 Sep 2014 03:40:19 GMT
  Date: Tue, 25 Nov 2014 01:10:05 GMT
node.js / Express:
 request stuff:
  If-Modified-Since:Sun, 23 Nov 2014 02:57:25 GMT
  If-None-Match:W/"YDWPLS6jm+fU6uuI0DSUOg=="
  Range:bytes=1342296-2097151
 response stuff:
  Accept-Ranges:bytes
  Cache-Control:public, max-age=0
  Connection:keep-alive
  Date:Tue, 25 Nov 2014 01:21:33 GMT 
  ETag:W/"YDWPLS6jm+fU6uuI0DSUOg=="
  Last-Modified:Wed, 24 Sep 2014 03:40:19 GMT
@gopherbot

This comment has been minimized.

Copy link
Author

commented Nov 25, 2014

Comment 4 by rjbrown:

Sorry it's too vague.  The high level issue is that passing the file's last modified
time to ServeContent() causes it to fail when Chrome requests byte ranges, as it will do
when playing a movie.  
You can see the problem if you compile and run the file I sent, and try to use it to
serve a movie to chrome. (note I think I left in a extra import of "time").  You can see
it working better if you pass in time.Time{} for file modification time, but that turns
off caching altogether.
One option would be to simply ignore the last modified time if there are byte ranges,
and treat it as if time.Time{} was passed in instead.
If you want to go deeper, I think it may require using an ETag.
I have compared the relevant request and response headers between node.js/Express, which
seems to work well, and Go.
Go:
 request stuff:
  If-Range:Wed, 24 Sep 2014 03:40:19 GMT
  Range:bytes=311341427-311341481
 response stuff:
  Accept-Ranges: bytes
  Content-Length: 311341482 
  Content-Type: video/mp4
  Last-Modified: Wed, 24 Sep 2014 03:40:19 GMT
  Date: Tue, 25 Nov 2014 01:10:05 GMT
node.js / Express:
 request stuff:
  If-Modified-Since:Sun, 23 Nov 2014 02:57:25 GMT
  If-None-Match:W/"YDWPLS6jm+fU6uuI0DSUOg=="
  Range:bytes=1342296-2097151
 response stuff:
  Accept-Ranges:bytes
  Cache-Control:public, max-age=0
  Connection:keep-alive
  Date:Tue, 25 Nov 2014 01:21:33 GMT 
  ETag:W/"YDWPLS6jm+fU6uuI0DSUOg=="
  Last-Modified:Wed, 24 Sep 2014 03:40:19 GMT
@bradfitz

This comment has been minimized.

Copy link
Member

commented Mar 23, 2015

Closing due to timeout waiting for concrete information.

@bradfitz bradfitz closed this Mar 23, 2015

@golang golang locked and limited conversation to collaborators Jun 25, 2016

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.