HttpServer - HttpExchange - Seekable Stream

江枫思渺然 提交于 2019-12-08 13:09:12

问题


I work on a sample java http server and a .Net client (on tablet). using my http sever, the .Net client must be able to download files.

It's working perfectly, but now I have to be able to resume download after a connection disruption.

Here some code :

Java server : ( It is launched in a seperate thread, hence the run method).

public void run() {

    try {
        server = com.sun.net.httpserver.HttpServer.create(
                new InetSocketAddress(
                        portNumber), this.maximumConnexion);

        server.setExecutor(executor);
        server.createContext("/", new ConnectionHandler(this.rootPath));
        server.start();


    } catch (IOException e1) {
        //For debugging
        e1.printStackTrace();
    }

}

my HttpHandler : (only the part dealing with GET request)

/**
 * handleGetMethod : handle GET request. If the file specified in the URI is
 * available, send it to the client.
 * 
 * @param httpExchange
 * @throws IOException
 */
private void handleGetMethod(HttpExchange httpExchange) throws IOException {

File file = new File(this.rootPath + this.fileRef).getCanonicalFile();

if (!file.isFile()) {
    this.handleError(httpExchange, 404);
} else if (!file.getPath().startsWith(this.rootPath.replace('/', '\\'))) { // windows work with anti-slash!
    // Suspected path traversal attack.
    System.out.println(file.getPath());
    this.handleError(httpExchange, 403);
} else {
    //Send the document.


    httpExchange.sendResponseHeaders(200, file.length());       
    System.out.println("file length : "+ file.length() + " bytes.");


    OutputStream os = httpExchange.getResponseBody();

    FileInputStream fs = new FileInputStream(file);

    final byte[] buffer = new byte[1024];
    int count = 0;
    while ((count = fs.read(buffer)) >= 0) {
        os.write(buffer, 0, count);
    }
    os.flush();
    fs.close();
    os.close();
}

}

And now my .Net Client: (simplified)

  try{

        Stream response = await httpClient.GetStreamAsync(URI + this.fileToDownload.Text);


    FileSavePicker savePicker = new FileSavePicker();
    savePicker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
    // Dropdown of file types the user can save the file as
    savePicker.FileTypeChoices.Add("Application/pdf", new List<string>() { ".pdf" });
    // Default file name if the user does not type one in or select a file to replace
    savePicker.SuggestedFileName = "new doc";

    StorageFile file = await savePicker.PickSaveFileAsync();

    if (file != null)
    {

        const int BUFFER_SIZE = 1024*1024;
        using (Stream outputFileStream = await file.OpenStreamForWriteAsync())
        {
            using (response)
            {
                var buffer = new byte[BUFFER_SIZE];
                int bytesRead;                          
                do
                {
                    bytesRead = response.Read(buffer, 0, BUFFER_SIZE);
                    outputFileStream.Write(buffer, 0, bytesRead);                                
                } while (bytesRead > 0);
            } 
            outputFileStream.Flush();
       }

   }

}
catch (HttpRequestException hre)
{   //For debugging
    this.Display.Text += hre.Message;
    this.Display.Text += hre.Source;
}
catch (Exception ex)
{
    //For debugging
    this.Display.Text += ex.Message;
    this.Display.Text += ex.Source;
}

So, to resume the download I would like to use some seek operation within the .Net client part. But every time I try something like response.Seek(offset, response.Position); , an error occurs informing that the Stream does not support seek operations. Yes, It does not, but how I can specify (in my server side) to use seekable Stream? Does the method HttpExchange.setStreams can be useful? Or, I do not need to modify the stream but to configure my HttpServer instance?

Thanks.


回答1:


Well use Range, Accept-Range and Content-Range fields works. There is just a little bit of work to do in order to send the correct part of the file and to set the response's headers.

The server may inform client that it support the Range field by setting the Accept-Range field:

responseHeader.set("Accept-Ranges", "bytes");

And then set the Content-range field when partial file are sent :

responseHeader.set("Content-range", "bytes " + this.offSet + "-" + this.range + "/" + this.fileLength);

Finally the return code must be set to 206 (Partial Content).

For more information about Range, Accept-Range and Content-Range fields see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html

NB : Opera 12.16 use the field "Range" to resume download but it seems that IE 10 and Firefox 22 do not use this field. May be some seekable streams as I was looking for originally. If anyone have an answer to this, I will be glad to read it =).



来源:https://stackoverflow.com/questions/18062088/httpserver-httpexchange-seekable-stream

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!