I've recently needed to develop a method to allow users to access files that are on a restricted domain. This domain is on an internal server that has no external access. However, it serves documents and files to a webserver that is accessible externally. So the webserver has access to the files, meaning they can upload files to the webserver, which will then save them to the internal server... But the reverse is not true. So we needed a way to "copy" files from the internal server to the end user.
My solution was to use an ASHX handler that will process the users request and retrieve the requested document, streaming it to the user through the response output stream. this is relatively new territory for me, but nothing ventured nothing gained!
The file is located by retrieving parameters passed through the querystring for the date, folder, and filename. This is mapped to a location on the webserver. I begin by validating the input. This probably isn't the best method for validating input but it should do the job until I have more time to optimize it. Please feel free to suggest anything I've overlooked!
// retrieve qstring fields, ensure all are present
string date = context.Request.QueryString["date"];
string folder = context.Request.QueryString["key"];
string file = context.Request.QueryString["file"];
if (string.IsNullOrEmpty(date) || string.IsNullOrEmpty(folder) || string.IsNullOrEmpty(file))
{
context.Response.Write("File not found");
context.Response.End();
}
// prevent directory attacks
if (date.Contains("../") || folder.Contains("../") || file.Contains("../"))
{
context.Response.Write("File not found");
context.Response.End();
}
Next I built a webrequest to retrieve the file by formatting a url string and retrieveing the response (which is the pdf file itself);
// build request stream
string url = string.Format("http://INTERNALIP/{0}/{1}/{2}", date, folder, file);
HttpWebRequest req = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse resp = null;
try
{
resp = (HttpWebResponse)req.GetResponse();
}
catch (Exception ex)
{
context.Response.Write("File not found");
context.Response.End();
}
Stream rStream = resp.GetResponseStream();
Finally, I initialize the response, filling it with the binary data from the pdf file, and writing to the stream as a pdf file attachment.
// initialize response
context.Response.Clear();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-disposition", string.Format("attachment; filename={0}", file));
// create buffer to input data
int buffersize = 1024 * 16;
byte[] buffer = new byte[buffersize];
int count = rStream.Read(buffer, 0, buffersize);
while (count > 0)
{
// write content to response
context.Response.OutputStream.Write(buffer, 0, count);
count = rStream.Read(buffer, 0, buffersize);
}
context.Response.End();
Now all that is necessary is to build the url to the handler with the appropriate fields in the querystring, like http://externalsite.com/pdf.ashx?date=20080828&folder=stuff&file=thefile.pdf and sure enough the handler does all the work! Not too shabby for my first real ashx application!
As always your comments are welcome and appreciated
Enjoyed this post and/or found it useful?