I have been writing a http server in Java for quite some time(almost two years now?) and I am still having issues getting byte range requests to work. I am only using the socket's input and output stream for raw byte data transfer(i.e. file downloads/uploads), and a PrintWriter for sending response headers/strings to connecting clients(such as HTTP/1.1 200 OK and so forth).
I do not wish to use any servlets or apis(such as HTTPURLConnection or whatever). I want to do it "vanilla style".
I am able to serve normal web pages quite nicely and quickly(such as file browsing, uploads and downloads, watching movies, listening to music, viewing pdf files, text, pictures, gif files, etc.), so that is not an issue.
However, whenever I try implementing byte range requests, the server receives the client's request perfectly, parses the given data, prepares the file input stream for sending, and then when I send the data to the client, the client always drops the connection with software caused connection abort: socket write error.(I need byte range requests for cases such as: watching an hour long video, then the dang wifi signal drops out and you don't want to re-watch the entire video from square one, resuming a 'paused download', etc.)
This really has me stumped, and I have indeed searched for java examples of serving byte range requests, all of which fail when I try to implement them. I have even tried starting from scratch and testing that, and it produces the same result. Here are the code snippets relevant to what I am trying to accomplish:
Sending and receiving normal web pages(works fine, this is an example):
...
OutputStream outStream = client.getOutputStream();
PrintWriter out = new PrintWriter(new OutputStreamWriter(outStream, StandardCharsets.UTF_8), true);
out.println("HTTP/1.1 200 OK");
out.println("Content-Type: text/html; charset=\"UTF-8\"");
String responseStr = "<!DOCTYPE html><html><head><title>Hello, world!</title></head><body><string>This is a simple example webpage!</string></body></html>";
if(acceptEncoding.contains("gzip") && responseStr.length() > 33) {
out.println("Content-Encoding: gzip");
byte[] r = StringUtil.compressString(responseStr, "UTF-8");
out.println("Content-Length: " + r.length);
out.println("");
if(protocol.equalsIgnoreCase("GET")) {
outStream.write(r);
}
} else {
out.println("Content-Length: " + responseStr.length());
out.println("");
if(request.protocol.equalsIgnoreCase("GET")) {
out.println(responseStr);
}
}
out.flush();
//followed by closing resources, etc.
...
Byte range serving(after client request data is parsed):
public static final long copyInputStreamToOutputStream(InputStream input, OutputStream output, long startBytes, long endBytes) throws IOException {
byte[] buffer = new byte[20480];//1024
long count = 0;
int read;
input.skip(startBytes);
long toRead = (endBytes - startBytes) + 1;
while((read = input.read(buffer)) > 0) {
if((toRead -= read) > 0) {
output.write(buffer, 0, read);//Socket error happens on this line mostly
output.flush();
} else {
output.write(buffer, 0, (int) toRead + read);//but also on this line sometimes
output.flush();
break;
}
count += read;
}
return count;
}
For anyone that is interested, the server running on this basic code is online at redsandbox.no-ip.org (points to my server), and at the moment I have byte requests disabled with Accept-Ranges: none instead of Accept-Ranges: bytes, but I can turn it on again to test it.
If I need to add more code in, please let me know! Thank you for your time. Alternately, if you wish to view my server's code in full, you can view it on github: https://github.com/br45entei/JavaWebServer