I was testing a HTTP servlet implementation (kindly shared by BalusC) which supports HTTP byte range requests.
I have found some peculiar differences between different HTTP clients, and was wondering if I am not missing anything. I have used a >2G mp4 video file for my tests and was capturing packets with Wireshark. This is roughly what happens:
Samsung Galaxy SII:
- HTTP GET request for file comes, asking for byte range
[0; <almost the end of the file>]
- server responds, starts to stream the file
each subsequent chunk is served within the bounds of the same HTTP response. No new HTTP request is sent (unless the video is fast forwarded to a certain position). Streaming code chunk for this is quite simple, it reads
RandomAccessFile input
and writes toOutputStream output
viabyte[] buffer
:while ((read = input.read(buffer)) > 0) { output.write(buffer, 0, read); }
- HTTP GET request for file comes, asking for byte range
- iPad 1
- HTTP GET request for file comes, asking for byte range
[0; <almost the end of the file>]
- server responds, starts to stream the file
- iPad gets a chunk or two and then unilaterally decides to stop accepting bytes from the server and issues a separate
GET
request for the next chunk of the file. New range boundaries are e.g.[100, almost the end of the file]
. The video is shown OK. - cycle repeats again from step 2. Left boundary always moves towards the end of the file.
- HTTP GET request for file comes, asking for byte range
I didn't investigate how exactly the connection is terminated. It could be that iPad stops sending TCP ACK packets, I suppose this doesn't really matter that much.
My problem is that for every terminated connection I get java.net.SocketException: Broken pipe
exception. This not only pollutes the logs (which is a minor/solvable problem) but I believe this can hurt performance as raising exceptions is quite expensive. When watching simple video, the exception rate was around 1 exception/sec, but if the server had 100 concurrent users, then the JVM would probably be spending loads of time just calculating stack traces instead of doing real work.
I have also tested this on iPhone using iOS 6 and was able to observe the same behaviour as iPad 1. Just to reiterate, this does not happen on Samsung Android nor any desktop browsers I have tried, including Safari on a desktop Mac.
Questions:
- is this a know bug/feature of iPad/iPhone?
- is there a workaround for this?