Anonymous HTTP PUT with IIS 7

by martin 22. June 2009 21:32

From googling around in trying to get HTTP put enabled on IIS 7, I have concluded that turning on HTTP PUT verb support requires the installation of the WebDAV handler extension and that even then it only works in integrated authentication mode.  If this is not true, please let me know as I was forced to write my own put HTTP handler.  It actually turned out to be a lot easier than I thought it was going to be though.  Implementing IHttpHandler, I ended up just having to binaryread the request into a byte array and then use a binarywriter to write it to a file after validating the PhysicalPath of the request for user permissions and validating that the "pattern" is safe (ex. file extension, path).  I haven't tested the performance against the IIS 6 native solution, but it seems quite fast on today's server hardware.

 

Update May '11:  Here is some code to get you started:

 

Web.Config
  1. <appSettings>
  2.     <add key="BasePutPath" value="C:\PutUploadDir\" />
  3.     <add key="PutSecurityRegularExpression" value="^.+\\UPLOAD\\(\{[0-9A-F]{8}\-[0-9A-F]{4}\-[0-9A-F]{4}\-[0-9A-F]{4}\-[0-9A-F]{12}\})\\(.+\.DOC)$"/>
  4. </appSettings>

 

PutHandler.cs
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Text;
  4. using System.Text.RegularExpressions;
  5. using System.Web;
  6. using System.Data.Sql;
  7. using System.Data;
  8. using System.Data.SqlClient;
  9. using System.IO;
  10. using System.Configuration;
  11. using System.Drawing;
  12. using System.Drawing.Imaging;
  13. using System.Drawing.Drawing2D;
  14. using log4net;
  15. using log4net.Config;
  16.  
  17. namespace IIS7Helper
  18. {
  19.     public class PutHandler : IHttpHandler
  20.     {
  21.         private static ILog log;
  22.         private static string strBasePutPath;
  23.         private static string strPutSecurityRegularExpression;
  24.  
  25.         static PutHandler()
  26.         {
  27.             log = LogManager.GetLogger(typeof(PutHandler));
  28.             strBasePutPath = ConfigurationManager.AppSettings["BasePutPath"];
  29.             strPutSecurityRegularExpression = ConfigurationManager.AppSettings["PutSecurityRegularExpression"];
  30.         }
  31.     
  32.  
  33.         public bool IsReusable
  34.         {
  35.             get { return true; }
  36.         }
  37.  
  38.         
  39.         public void ProcessRequest(HttpContext context)
  40.         {
  41.             try
  42.             {
  43.                 byte[] arrBytes = context.Request.BinaryRead(context.Request.ContentLength);
  44.                 string strLocation = context.Request.PhysicalPath.ToUpper();
  45.                 bool blnRequestSecure = false;   // trust no request by default
  46.  
  47.                 // sample url
  48.                 // https://xxx.yyy.com/Upload/{56DA31A8-15A8-4A0B-90F2-4A59909F5DCE}/MyFile.doc
  49.  
  50.                 string strDirName = string.Empty;
  51.                 string strFileName = string.Empty;
  52.                 string strPhysicalLocation = string.Empty;
  53.  
  54.                 Regex re = new Regex(strPutSecurityRegularExpression, RegexOptions.Singleline);
  55.                 Match m = re.Match(strLocation);
  56.                 if (m.Success)
  57.                 {
  58.                     strDirName = m.Groups[1].Captures[0].Value;
  59.                     strFileName = m.Groups[2].Captures[0].Value;
  60.  
  61.                     strPhysicalLocation = Path.Combine(strBasePutPath, strDirName);
  62.  
  63.                     if (Directory.Exists(strPhysicalLocation))
  64.                     {
  65.                         blnRequestSecure = true;
  66.                     }
  67.                     else
  68.                     {
  69.                         log.Error("Directory does not exist : " + strPhysicalLocation);
  70.                     }
  71.                 }
  72.                 else
  73.                 {
  74.                     log.Error("Security Alert : URL RegEx failed for " + strLocation);
  75.                 }
  76.                 strPhysicalLocation = Path.Combine(strPhysicalLocation, strFileName);
  77.                 if (blnRequestSecure)
  78.                 {
  79.                     log.Debug("About to write data to " + strPhysicalLocation);
  80.                     BinaryWriter bw = new BinaryWriter(new FileStream(strPhysicalLocation, FileMode.CreateNew));
  81.                     bw.Write(arrBytes);
  82.                     bw.Flush();
  83.                     bw.Close();
  84.                     bw = null;
  85.                     context.Response.StatusCode = 200;
  86.                     context.Response.Flush();
  87.                 }
  88.                 else
  89.                 {
  90.                     log.Error("Fall through due to either not matching regex or dir not existing. " );
  91.                     context.Response.StatusCode = 500;
  92.                     context.Response.Flush();
  93.                 }
  94.             }
  95.             catch (Exception ex)
  96.             {
  97.                 log.Error("An error occurred : " + ex.ToString());
  98.                 context.Response.StatusCode = 500;
  99.                 context.Response.Flush();
  100.             }
  101.         }     
  102.     }
  103. }

 

Currently rated 5.0 by 1 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , ,

ASP.Net | C# | Windows

Comments

Add comment


(Will show your Gravatar icon)  

biuquote
  • Comment
  • Preview
Loading



Welcome

Please contact me if you have a great idea for a project and need technical expertise in designing, developing, or integrating a custom software solution.

Recent Comments

Comment RSS