Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resuming downloading

The idea is simple, i am creating a service where user can put the direct link of a file that is being hosted on another website and my program will open a stream to that remote server and start reading the file in bytes and then return each readed byte to the user.

so far i managed to get that working and here is my code

    public void Index()
    {
        //Create a stream for the file
        Stream stream = null;

        //This controls how many bytes to read at a time and send to the client
        int bytesToRead = 10000; //10000

        // Buffer to read bytes in chunk size specified above
        byte[] buffer = new Byte[bytesToRead];

        // The number of bytes read
        try
        {
            //Create a WebRequest to get the file
            HttpWebRequest fileReq = (HttpWebRequest)HttpWebRequest.Create("http://SOME-OTHER-SERVER.com/File.rar");


            //Create a response for this request
            HttpWebResponse fileResp = (HttpWebResponse)fileReq.GetResponse();


            if (fileReq.ContentLength > 0)
                fileResp.ContentLength = fileReq.ContentLength;

            //Get the Stream returned from the response
            stream = fileResp.GetResponseStream();

            // prepare the response to the client. resp is the client Response
            var resp = HttpContext.Response;

            //Indicate the type of data being sent
            resp.ContentType = "application/octet-stream";

            //Name the file 
            resp.AddHeader("Content-Disposition", "attachment; filename=\"" + "fle.rar" + "\"");
            resp.AddHeader("Content-Length", (fileResp.ContentLength).ToString());

            int length;
            do
            {
                // Verify that the client is connected.
                if (resp.IsClientConnected)
                {
                    // Read data into the buffer.
                    length = stream.Read(buffer, 0, bytesToRead);

                    // and write it out to the response's output stream
                    resp.OutputStream.Write(buffer, 0, length);

                    // Flush the data
                    resp.Flush();

                    //Clear the buffer
                    buffer = new Byte[bytesToRead];
                }
                else
                {
                    // cancel the download if client has disconnected
                    length = -1;
                }
            } while (length > 0); //Repeat until no data is read
        }
        finally
        {
            if (stream != null)
            {
                //Close the input stream
                stream.Close();
            }
        }
    }

When i go to my page it downloads perfectly but the problem is if i stopped the download it won't resume again.

I searched for that issue and figured out that there is a header "Accept-Ranges" that must be defined in the connection in order to support resume.

so i added that header but didn't work.

like image 389
BOSS Avatar asked Mar 25 '13 07:03

BOSS


People also ask

Can I resume download after shutdown?

If the SERVER that is providing the download supports resuming downloads, then after you resume from hibernation, you should have no issues resuming the download. After you pause the download, there is no need to touch Chrome. Just pause, and hibernate. By that I mean, don't close Chrome.

How do I continue an unfinished download?

Alternatively, you can press Ctrl+J on Windows or Command+J on macOS. In the list of downloads, find the failed item and click “Resume”. If everything goes right, your download will resume from where it left off before you were disconnected.


1 Answers

Handling Range Requests is a little bit more complicated than that. In general you need to handle Range and If-Range headers in request and serve proper 206 Partial Content responses with Content-Range, Date and ETag or Content-Location headers.

The article Range Requests in ASP.NET MVC – RangeFileResult describes in details how to create an ASP.NET MVC ActionResult with Range Request support.

In your case you will also have to check if the other side (the one for which you use fileReq) support Range Request. If yes than you can request just the needed part (and preferably cache it somewhere locally), but if not than you need to get the entire file and seek to proper locations (in that situation you defintely want to have a local caching scenario).

like image 57
tpeczek Avatar answered Sep 22 '22 22:09

tpeczek