简体   繁体   中英

Read Only Headers of Http POST request(with huge entity body) in Memory

I am using IIS 7/7.5. I have a page where users can upload huge data. Sometimes, I required to read the POST body and sometime not. Is there is any way in IIS/ASP.NET to defer reading the POST entity body until I signal.

You can safely read the request headers without worrying about the file size. Let me elaborate. Consider the following html page allowing to upload files to the /upload.aspx endpoint:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title></title>
</head>
<body>
    <form action="/upload.ashx" method="post" enctype="multipart/form-data">
        <input type="file" name="file" />
        <button type="submit">OK</button>
    </form>
</body>
</html>

We could then have a generic handler:

public class Upload: IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        var request = context.Request;
        var response = context.Response;
        response.ContentType = "text/plain";
        response.Write(request.Headers.ToString());
    }

    public bool IsReusable
    {
        get { return true; }
    }
}

and then ensure that we have increased the request limits in web.config in order to allow huge files to be uploaded:

<httpRuntime maxRequestLength="10485760" />

and:

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxAllowedContentLength="1073741824" />
      </requestFiltering>
    </security>
</system.webServer>

Now let's suppose that the user selects a very large file to upload (say 5GB) and hits the submit button. The ProcessRequest method of your generic handler will be hit immediately meaning that you could access the headers very quickly:

public void ProcessRequest(HttpContext context)
{
    var fileSize = context.Request.ContentLength;
}

And if you wanted to read the contents of this file you could start reading from the input stream of the file which will obviously take a lot of time until the entire file is uploaded:

public void ProcessRequest(HttpContext context)
{
    // We reach at that point pretty fast and we can read the headers here
    // and determine for example the total bytes to be uploaded
    var fileSize = context.Request.ContentLength;

    // now we can start reading the file which would obviously take quite a lot of time:
    context.Request.Files[0].InputStream.Read(...)
}

But then you might ask yourself: but if the ProcessRequest method is hit immediately after the user hits the submit button where is the uploaded file at that time? Actually as the bytes arrive from the client IIS is chunking them in temporary files (it is not in memory, you should not worry about that) and the InputStream is pointing to this location, so that when you start reading from it, you will actually be reading data that IIS has already received from the client and made available for you. Those temporary files will be created when you start reading from the input stream. So that's where you should be careful because when you are reading from this stream you are loading the data in memory. So if you can have potentially very large data coming from the client you should always read and process it in chunks. If you wanted to store the uploaded file on the server you should read the input stream in chunks and write those chunks to an output file on your server (or if you are using .NET 4.0, simply use the Stream.CopyTo method).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM