Creating a File Relay (proxy) using ASP.Net - Part 1 - Serving files.

In this series of posts I will walk you through implementing an ASP.Net based file relay mechanism using aspx pages. This will allow you to serve files hosted in the back-office (behind a firewall) from a frontend webserver.

To implement this solution we need to build two separate webpages, one for the backend server and one for the frontend server.

  • GetFile.aspx – The backend page which will surface the requested file to the frontend server.
  • RelayFile.aspx – The frontend page which will forward (relay/proxy) the request to the backend server.

In this first part I will show you how to send a file using an aspx page.

Implementing GetFile.aspx

The first thing we need to do is create the new aspx page and name it GetFile.aspx.

The Page Markup

Now let’s go ahead and remove all the content from the GetFile.aspx page, except for the Page directive; The purpose of this page is to return to contents of another file, so all the html markup is superfluous.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="GetFile.aspx.cs" Inherits="Backend.GetFile" %>

The Code Behind

With the markup out of the way, let’s focus on the actual code behind the page. The only method we will need to implement is Page_Load.

1. Ensure a clean response – We don’t want anything from the aspx processing pipeline to interfere with the result

Response.ClearHeaders();
Response.ClearContent();

2. Determine the target file – In this example the filepath will be passed with the querystring.

string filePath = (Request.QueryString["filePath"] ?? "").Trim();

3. Determine and set the response type – This will allow the browser to display the file correctly. Also, make sure you only serve expected file types! This feature circumvents the basic webserver file security mechanisms, avoid leaking your secrets to the world!

string contentType = null;
string extension = Path.GetExtension(filePath).ToLowerInvariant();
switch (extension)
{
   case ".csv":
      contentType = "text/csv";
      break;
   case ".mp4":
      contentType = "video/mp4";
      break;
   case ".pdf":
      contentType = "application/pdf";
      break;
   default:
      // Unsupported filetype
      // There are serious security implications with
      // serving up files from a webserver. Make sure
      // you do not open yourself up to an attack!
      throw new HttpException(403, "Forbidden."); 
      // Use an empty ContentType if the type is unknown
      //contentType = "";
      //break;
}
   
//Set the ContentType.
Response.ContentType = contentType;

4. Set the response content length so the client knows how much data to expect.

var fileInfo = new FileInfo(filePath);
Response.AddHeader("Content-Length", fileInfo.Length.ToString());

5. Write the file contents to the response stream.

Response.WriteFile(filePath);

6. Flush the output buffers and end the response.

Response.End();

 

It’s a Wrap!

These 6 simple steps (7 if you count the page markup change) are all you need to implement a simple page to serve files from the filesystem. In the next part we will have a look at making this code more production ready by adding error checking and handling.

 

The Complete Page_Load Method

   1:  protected void Page_Load(object sender, EventArgs e)
   2:  {
   3:     // Clear headers and content to ensure a clean response
   4:     Response.ClearHeaders();
   5:     Response.ClearContent();
   6:   
   7:     // get target file path from querystring
   8:     string filePath = (Request.QueryString["filePath"] ?? "").Trim();
   9:     Debug.WriteLine("GetFile: filePath: '" + filePath + "'");
  10:   
  11:     // determine content type
  12:     string contentType = null;
  13:     string extension = Path.GetExtension(filePath).ToLowerInvariant();
  14:     switch (extension)
  15:     {
  16:        case ".csv":
  17:           contentType = "text/csv";
  18:           break;
  19:        case ".mp4":
  20:           contentType = "video/mp4";
  21:           break;
  22:        case ".pdf":
  23:           contentType = "application/pdf";
  24:           break;
  25:        default:
  26:           // Unsupported filetype
  27:           // There are serious security implications with
  28:           // serving up files from a webserver. Make sure
  29:           // you do not open yourself up to an attack!
  30:           throw new HttpException(403, "Forbidden.");
  31:        // Use an empty ContentType if the type is unknown
  32:        //contentType = "";
  33:        //break;
  34:     }
  35:   
  36:     //Set the ContentType.
  37:     Response.ContentType = contentType;
  38:     Debug.WriteLine("Mapped extension '" + extension 
  39:            + "' to content type '" + contentType + "'.");
  40:   
  41:     // determine and set file length
  42:     var fileInfo = new FileInfo(filePath);
  43:     Response.AddHeader("Content-Length", fileInfo.Length.ToString());
  44:   
  45:     //Write the file directly to the HTTP content output stream.
  46:     Response.WriteFile(filePath);
  47:   
  48:     // flush and end the response
  49:     Response.End();
  50:  }

My Latest Track