This is one of the first times where I felt I needed to ask a question as I can't seem to find an answer anywhere.
So, in this app I made an easy website page that uses html5 video for an background for my friend that's an photographer. To allow my friend to make future changes, I wanted to use the appengine blobstore to serve videos uploaded for the background. Everything seems to be fine except for in Safari, the video is never received or is received incorrectly.
Here's my servlet class that does the serving:
public class Serve extends HttpServlet {
private static final long serialVersionUID = 1L;
private BlobstoreService blobstore = BlobstoreServiceFactory.getBlobstoreService();
private DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
public void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String format = req.getParameter("video");
Key key = KeyFactory.createKey("Video", "None");
if(format.equals("mp4")){
key = KeyFactory.createKey("Video", "MP4");
resp.setHeader("Content-type", "video/mp4");
}
if(format.equals("webm")){
key = KeyFactory.createKey("Video", "WebM");
resp.setHeader("Content-type", "video/webm");
}
try{
Entity e = datastore.get(key);
String blobKey = (String)e.getProperty("Blob-Key");
BlobKey bKey = new BlobKey(blobKey);
resp.setHeader("Cache-Control", "max-age=31557600, must-revalidate");
//resp.setHeader("Transfer-Encoding", "chunked");
blobstore.serve(bKey, resp);
}
catch (EntityNotFoundException error){
resp.getWriter().print("No video found");
}
}
}
Edit: Removed Transfer-Encoding header.
Now on the development server I get this Exception when I try to access /serve?video=mp4 only in Safari:
[java] WARNING: IOException thrown while closing Closeable.
[java] org.mortbay.jetty.EofException
[java] at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:787)
[java] at org.mortbay.jetty.HttpConnection.flushResponse(HttpConnection.java:693)
[java] at org.mortbay.jetty.HttpConnection$Output.close(HttpConnection.java:992)
[java] at com.google.appengine.repackaged.com.google.common.io.Closeables.close(Closeables.java:77)
[java] at com.google.appengine.api.blobstore.dev.ServeBlobFilter.serveBlob(ServeBlobFilter.java:195)
[java] at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:67)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:368)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:351)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
[java] at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
[java] at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
[java] at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
[java] at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
[java] at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:97)
[java] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[java] at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:485)
[java] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[java] at org.mortbay.jetty.Server.handle(Server.java:326)
[java] at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
[java] at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
[java] at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
[java] at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
[java] at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
[java] at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
[java] at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
[java] Caused by: java.io.IOException: Broken pipe
[java] at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
[java] at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
[java] at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:89)
[java] at sun.nio.ch.IOUtil.write(IOUtil.java:46)
[java] at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:450)
[java] at org.mortbay.io.nio.ChannelEndPoint.flush(ChannelEndPoint.java:169)
[java] at org.mortbay.io.nio.SelectChannelEndPoint.flush(SelectChannelEndPoint.java:221)
[java] at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:721)
[java] ... 31 more
[java]
[java] Sep 20, 2013 2:48:25 PM com.google.appengine.repackaged.com.google.common.io.Closeables close
[java] WARNING: IOException thrown while closing Closeable.
[java] org.mortbay.jetty.EofException
[java] at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:787)
[java] at org.mortbay.jetty.HttpConnection.flushResponse(HttpConnection.java:693)
[java] at org.mortbay.jetty.HttpConnection$Output.close(HttpConnection.java:992)
[java] at com.google.appengine.repackaged.com.google.common.io.Closeables.close(Closeables.java:77)
[java] at com.google.appengine.api.blobstore.dev.ServeBlobFilter.serveBlob(ServeBlobFilter.java:195)
[java] at com.google.appengine.api.blobstore.dev.ServeBlobFilter.doFilter(ServeBlobFilter.java:67)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.apphosting.utils.servlet.TransactionCleanupFilter.doFilter(TransactionCleanupFilter.java:43)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.appengine.tools.development.StaticFileFilter.doFilter(StaticFileFilter.java:125)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectRequest(DevAppServerModulesFilter.java:368)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doDirectModuleRequest(DevAppServerModulesFilter.java:351)
[java] at com.google.appengine.tools.development.DevAppServerModulesFilter.doFilter(DevAppServerModulesFilter.java:116)
[java] at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1157)
[java] at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:388)
[java] at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
[java] at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
[java] at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
[java] at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:418)
[java] at com.google.appengine.tools.development.DevAppEngineWebAppContext.handle(DevAppEngineWebAppContext.java:97)
[java] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[java] at com.google.appengine.tools.development.JettyContainerService$ApiProxyHandler.handle(JettyContainerService.java:485)
[java] at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
[java] at org.mortbay.jetty.Server.handle(Server.java:326)
[java] at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
[java] at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:923)
[java] at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:547)
[java] at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
[java] at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
[java] at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:409)
[java] at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
[java] Caused by: java.io.IOException: Broken pipe
[java] at sun.nio.ch.FileDispatcherImpl.write0(Native Method)
[java] at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:47)
[java] at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:89)
[java] at sun.nio.ch.IOUtil.write(IOUtil.java:46)
[java] at sun.nio.ch.SocketChannelImpl.write(SocketChannelImpl.java:450)
[java] at org.mortbay.io.nio.ChannelEndPoint.flush(ChannelEndPoint.java:169)
[java] at org.mortbay.io.nio.SelectChannelEndPoint.flush(SelectChannelEndPoint.java:221)
[java] at org.mortbay.jetty.HttpGenerator.flush(HttpGenerator.java:721)
[java] ... 31 more
The video will still show on this page, however, in production nothing occurs. Also, I'm not getting any logs in the appengine console so I don't if there are other errors. I know that the video was uploaded properly as it works in google chrome. Google Chrome will send back the response headers and play the video. I've also tried using curl and it sends everything back also. Is there something I'm missing or something I need to take out for it to work properly in Safari.
Edit: I'm also wondering does the response header ever be received in Safari as it does in Firefox, Chrome, and Opera for blobstore requests?
Thanks for any advice given.