Experience on ASP. NET website construction on the Godaddy server-resumable download (2)

Source: Internet
Author: User
Tags file url godaddy server

Last article (http://blog.csdn.net/querw/archive/2009/08/24/4477182.aspx) talked about how to control File Download In APS. NET.

Design purpose and requirements

Assume that an application scenario is as follows:
A host contains a lot of file information and various file formats (PDF, DOC, EXE... and so on ).
This host runs an ASP. NET Website, which allows users to download data after registration and payment.

The file is stored on the IIS server. If you know the specific path, you can download the file at any time. (If you do not have or cannot set the access permission, the file can be downloaded at any time .)
If you directly send the download path to the paying user, it will certainly not work and will be spread out. therefore, you cannot let the client know the specific path. The file content is composed of ASP. NET Server Page read and sent to the client.

What I want to do is:Compile an ASP. NET page server code, read the specified file, and send it to the customer.

.

General idea

In. net, there are two functions that can be used to send files Response. WriteFile and Response. TransmiteFile
The main difference between them is: WriteFile first reads the file content to the Server Buffer and then sends it to the client. Therefore, for large files, it will cause a lot of pressure on the server.
It is generally used to process small files. For example, A. TransmiteFile sent to an excel report does not buffer data and is directly thrown to the client. Therefore, it can be used to send large files.
(I use TransmiteFile .)

Implementation

1. Give the customer a link, such as http: // xxxx/downloads. aspx? Key = ABCD123456

2. in downloads. in the server code of aspx, the database is queried based on the Key value to obtain the actual file path on the server. at this time, the control is in downloads. aspx, so you can write complex control functions, such as checking whether a user has logged on or paid, to avoid external leeching.

3. After obtaining the file path, call Response. TransmiteFile to send the file to the client.

4. because there is no file name information in the link for the customer, you should add a sentence in the HTTP Response header to tell the client file name: Response. addHeader ("Content-Disposition", "attachment; filename =/" "+ your file name +"/"); (to support Chinese characters, consider encoding, I will not talk about it here, it is not our topic .)

5. If a large file, such as 1 GB, does not support resumable data transfer, it is meaningless. How can this problem be achieved?

(1) To let the client know that our server supports resumable data transfer, the HTTP Response Header should contain Accept-Ranges: bytes and ETag: "XXXX ".
ETag is the identifier of a file for the client to determine that it is requesting the same file. The content of ETag has no specific requirements in the HTTP specification, as long as it is on the same server, the same file has the same ETag. Generally, you can generate a string based on the file name and the last modification time.
 
Sample Code:
Response. AddHeader ("Accept-Ranges", "bytes"); // resumable upload control.
Response. AddHeader ("ETag", "/" "+ strETag +"/"); // allows resumable upload.

(2) process the "Range" field in the client request. The general format is as follows: Range: bytes = 1234-or Range: bytes = 1234-12345.
It indicates that the data Between 1235 and 1,235th bytes is downloaded from the ground up.
The server first needs to add the Content-Range response header, and then uses TransmiteFile to send the specified data.

Sample Code:
Response. StatusCode = 206;
Response. AddHeader ("Content-Length", (lTo-lFrom + 1). ToString ());
Response. addHeader ("Content-Range", string. format ("bytes {0}-{1}/{2}", lFrom, lTo, fi. length); // parameters 0 and 1 are positions. parameter 2 indicates the file length.
Response. TransmitFile (strFilePath, lFrom, lTo-lFrom + 1 );


(LFrom and lTo are obtained based on the Range field in the client request .)

Summary

This function is completed after writing a few files. I also encountered a problem in the middle: I used VS2008 for development and did not install IIS on the machine. when debugging, it is found that the Accept-Ranges and Content-Range response headers are not added.
Later, I uploaded the code to a real server to test the code. It seems that the. net Server of VS2008 has a strange setting.

 

Advantages and disadvantages:

1. You can control the download as you like.
2. attackers can bypass the restrictions on downloading server files. For example, my server does not allow downloading files with the ISO and NRG file extensions. If you enter RUL directly, the system will prompt 404, but you can download the files using the above methods.

3. in this way, the download is in. if a large number of users need to maintain multiple responses, I don't know if it will affect server performance.

Currently, I do not know whether this method is different from directly entering a URL for download on the IIS server.

However, for IIS, If you directly enter the File URL and use the download tool to download multiple threads, this problem also occurs. You need to maintain multiple responses.

If you have any insights, please enlighten me, thank you. querw@sina.com

 

Note:

1. TransmitFile (String) (the function is added to. net 2.0.

2. TransmitFile (String, Int64,
Int64) the overload with the sending location parameter is only supported after. net 2.0 sp1. Therefore, we must use the method described in this article to implement resumable data transfer, at least. net 2.0 sp1 must be supported.

3. I have not detected If-Range and Unless-Modified-Since in the request header. If necessary, you can verify the file name after obtaining the ETag and Last-Modified.

4. This article was reproduced on www.diybl.com just two days after it was sent to CSDN, and the author "anonymous" was noted ",I have no objection to reprinting this article
To share with you,But I want to keep my signature
But what? (Maybe I was not the first one to use this method and publish it, but the article was originally written and tested .)

 

 

================================ ====================================
The above description may be relatively simple. I am posting a piece of code with comments and don't ask everyone to understand it. But if you are doing similar work, I believe it will be helpful.

// 1. Obtain the file path on the server // here, if the file path is incorrect and cannot be mapped, an exception is thrown. strURL is the real file path queried from the database based on the Key.
String strFilePath = Server. MapPath ("~ "+ StrURL );

// 2. Get the file name
String strFileName = System. IO. Path. GetFileName (strFilePath );

// 3. Check whether the file exists
FileInfo fi = new FileInfo (strFilePath );
If (! Fi. Exists)
{
// Exit point, the file does not exist
}

// 4. throwing it to the client
StrFileName. Replace ("", "% 20"); // process the case where the file name contains spaces
String strETag = strFileName. ToUpper () + ":" + fi. Length. ToString (); // my Etag is composed of a file name and number of nodes.
String strLastTime = fi. LastWriteTimeUtc. ToString ("r ");

Response. Clear (); // first Clear the Response stream
Response. ContentType = "application/octet-stream"; // specify the file type so that the client always pops up a box for saving files.
Response. AddHeader ("Content-Disposition", "attachment; filename =/" "+ strFileName + "/"");
Response. AddHeader ("Accept-Ranges", "bytes"); // resumable upload control.
Response. AddHeader ("ETag", "/" "+ strETag +"/"); // allows resumable upload.
Response. AddHeader ("Last-Modified", strLastTime); // write the Last Modified date to the Response

// Obtain the range of client requests and verify the validity of the range
Long lFrom = 0;
Long lTo = 0;
Bool bParts = false;
String strRange = Request. Headers ["Range"];
If (ParseRange (strRange, out lFrom, out lTo) // ParseRange is a function written by myself and reads two locations from the Range. The code is later.
{
If (-1 = lFrom &-1 = lTo)
{
// Two values are not allowed to be specified.
}
Else
{
If (lTo =-1) lTo = fi. Length-1; // if the client does not specify the end position, it is considered as the last character Range: bytes = 123-of the file.
If (lFrom =-1) // Range: bytes =-123, the last 123 bytes of the request
{
LFrom = fi. Length-lTo;
LTo = fi. Length-1;
}

If (lFrom <0 | lFrom> = fi. Length | lFrom> lTo | lTo <0 | lTo> = fi. Length)
{
// In the preceding cases, the range value can be parsed, but it is invalid.
// First, the From and To labels should be within the file length range.
// Second, From should be <=
}
Else
{
BParts = true;
}
}
}

// Return the data segment or the entire file according to the user's request
If (bParts)
{
Response. StatusCode = 206;
Response. AddHeader ("Content-Length", (lTo-lFrom + 1). ToString ());
Response. addHeader ("Content-Range", string. format ("bytes {0}-{1}/{2}", lFrom, lTo, fi. length); // parameters 0 and 1 are positions starting from 0. parameter 2 indicates the file length.
Response. TransmitFile (strFilePath, lFrom, lTo-lFrom + 1 );
}
Else
{
Response. AddHeader ("Content-Length", fi. Length. ToString ());
Response. TransmitFile (strFilePath );
}
Response. End ();
}

================================ ====================================
Protected bool ParseRange (string strRange, out long lFrom, out long lTo)
{
LFrom = 0;
LTo = 0;
Long lTemp = 0;
If (strRange = null | strRange = "")
{
Return false; // the string is null.
}
Else
{
StrRange = strRange. Replace ("", ""); // remove unnecessary Spaces
String [] range = strRange. Split (new char [] {'= ','-'});

// 1. After the split, the first part of the segment 3 is "Range: bytes", the second part is the start position, and the third part is the end position.
If (range. Length! = 3)
{
Return false; // The format is incorrect. Only the Range: bytes = 89294317-, Range: bytes = 1234-1235, or Range: bytes =-500 formats are supported.
}

// 2. Start position of resolution
If (range [1]. Length <= 0)
{
// The start position is not specified.
LFrom =-1;
}
Else
{
If (! Long. TryParse (range [1], out lTemp ))
{
Return false; // the start position cannot be parsed.
}
LFrom = lTemp;
}

// 3. Resolution end position
If (range [2]. Length <= 0)
{
LTo =-1; // The end position Range: bytes = 1234-is not specified.
}
Else
{
If (! Long. TryParse (range [2], out lTemp) // if you want to exclude byte = xxxx-, TryParse fails, and lTemp is set to zero.
{
Return false; // The third-level content is not empty, but cannot be parsed.
}
LTo = lTemp;
}
Return true;
}
}

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.