restiisiis-7.5http-delete

IIS7.5 Gives 500 Internal Server Error when trying to use DELETE verb


I am trying to issue a DELETE to an IIS7.5 resource:

DELETE http://198.252.206.16:48251/Test/foo.ashx HTTP/1.1
Accept: */*
Accept-Language: en-us
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.1; WOW64; Trident/7.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; .NET4.0E)
Host: 198.252.206.16:48251
Content-Length: 0
Connection: Keep-Alive
Pragma: no-cache

And the server responds with:

HTTP/1.1 500 Internal Server Error
Server: Microsoft-IIS/7.5
X-Powered-By: ASP.NET
Date: Wed, 12 Feb 2014 01:01:30 GMT
Content-Length: 0

The damnedest thing is:

Why does IIS not work?

Steps to reproduce

Create a web-site with the generic handler:

Foo.ashx

<%@ WebHandler Language="C#" Class="Foo" %>

using System;
using System.Web;

public class Foo : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
    }

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

and then issue a DELETE verb to the resource. You can use Fiddler to compose the request, if you like:

enter image description here

What about other verbs you ask?

You didn't try to reproduce it, did you? Well, i'll show you the results here:

And just to be anal retentive, a snippet of the relevant portions from web.config:

<?xml version="1.0"?>
<configuration>
    <system.web>
        <httpRuntime/>
        <!-- IISFIX: By default IIS hides errors-->
        <customErrors mode="Off"/>
        <!-- IISFIX: By default IIS ignores the browser's culture -->
        <globalization culture="auto" uiCulture="auto"/>
        <!--Doesn't work for ASP.net web-sites, only ASP.net applications-->
        <trace enabled="true" requestLimit="40" localOnly="false" />

        <compilation debug="true" targetFramework="4.0">
            <assemblies>
                <add assembly="System.DirectoryServices, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B03F5F7F11D50A3A"/>
                <add assembly="System.DirectoryServices.AccountManagement, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
                <add assembly="System.Data.Linq, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089"/>
            </assemblies>
        </compilation>
    </system.web>

    <!-- ASP.net web-sites do not support WebPageTraceListener (only ASP.net web-applications) 
  So this section doesn't work; and does nothing. 
  But if Microsoft ever fixes IIS, we will start working automagically. -->
    <system.diagnostics>
        <trace>
            <listeners>
                <add name="WebPageTraceListener" type="System.Web.WebPageTraceListener, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
            </listeners>
        </trace>
    </system.diagnostics>

    <system.webServer>
        <!-- IISFIX: By default IIS ignores custom error pages -->
        <httpErrors existingResponse="PassThrough"/>
        <defaultDocument>
            <files>
                <clear/>
                <add value="Default.htm"/>
                <add value="Default.asp"/>
                <add value="index.htm"/>
                <add value="index.html"/>
                <add value="iisstart.htm"/>
                <add value="default.aspx"/>
                <add value="test.htm"/>
            </files>
        </defaultDocument>

        <!--IISFIX: By default IIS doesn't understand HTTP protocol-->
        <security>
            <requestFiltering>
                <verbs>
                    <add verb="OPTIONS" allowed="true" />
                    <add verb="GET" allowed="true" />
                    <add verb="HEAD" allowed="true" />
                    <add verb="POST" allowed="true" />
                    <add verb="PUT" allowed="true" />
                    <add verb="TRACE" allowed="true" />
                    <add verb="DELETE" allowed="true" />
                </verbs>
            </requestFiltering>
        </security>

        <modules runAllManagedModulesForAllRequests="true">
            <!--IISFIX: Whatever this is, it causes 405 Method Not Allowed errors on IIS when using PUT. (Microsoft's broken by defult)-->
            <remove name="WebDAVModule"/>
        </modules>

    </system.webServer>
</configuration>

Edit - forgot the screenshot of verbs:

enter image description here

The question was sufficiently asked in the title. The rest of the post is just filler to make it look like it shows research effort; which means you have to upvote it - the tooltip on the upvote arrow says so!


Solution

  • The answer turns out to be caused by more of Microsoft's Broken by default policy.

    Rather than acting as a web-server, accepting requests and handling them, ASP.net by default decides to ignore the majority of requests - because it thinks the user shouldn't be doing them.

    The solution is to rip everything related to ASP.net out of IIS, and then re-add it correctly:

    web.config

    <?xml version="1.0"?>
    <configuration>
    </system.webServer>
        <modules runAllManagedModulesForAllRequests="true">
          <!--IISFIX: Whatever this is, it causes 405 Method Not Allowed errors on IIS when using PUT. (Microsoft's broken by defult)-->
          <remove name="WebDAVModule"/>
        </modules>
        <handlers>
             <!--IISFIX: ASP.net is broken by default. By default they will not accept verbs from the client.
             First we have to rip out everything related to ASP.net-->
          <remove name="ExtensionlessUrlHandler-ISAPI-4.0_64bit"/>
          <remove name="ExtensionlessUrlHandler-Integrated-4.0"/>
          <remove name="ExtensionlessUrlHandler-ISAPI-4.0_32bit"/>
          <remove name="SimpleHandlerFactory-ISAPI-2.0-64"/>
          <remove name="SimpleHandlerFactory-ISAPI-2.0"/>
          <remove name="SimpleHandlerFactory-Integrated"/>
          <remove name="SimpleHandlerFactory-Integrated-4.0"/>
          <remove name="SimpleHandlerFactory-ISAPI-4.0_64bit"/>
          <remove name="SimpleHandlerFactory-ISAPI-4.0_32bit"/>
             <!-- IISFIX: Now that we're ripped out everything related to ASP.net, put them back correctly.-->
          <add name="SimpleHandlerFactory-ISAPI-4.0_32bit" path="*.ashx" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0"/>
          <add name="SimpleHandlerFactory-ISAPI-4.0_64bit" path="*.ashx" verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0"/>
          <add name="SimpleHandlerFactory-Integrated-4.0" path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0"/>
          <add name="SimpleHandlerFactory-Integrated" path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode"/>
          <add name="SimpleHandlerFactory-ISAPI-2.0" path="*.ashx" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv2.0,bitness32" responseBufferLimit="0"/>
          <add name="SimpleHandlerFactory-ISAPI-2.0-64" path="*.ashx" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework64\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv2.0,bitness64" responseBufferLimit="0"/>
          <add name="ExtensionlessUrlHandler-ISAPI-4.0_32bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness32" responseBufferLimit="0"/>
          <add name="ExtensionlessUrlHandler-Integrated-4.0" path="*." verb="*" type="System.Web.Handlers.TransferRequestHandler" resourceType="Unspecified" requireAccess="Script" preCondition="integratedMode,runtimeVersionv4.0"/>
          <add name="ExtensionlessUrlHandler-ISAPI-4.0_64bit" path="*." verb="*" modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\Framework64\v4.0.30319\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="Script" preCondition="classicMode,runtimeVersionv4.0,bitness64" responseBufferLimit="0"/>
    
          <!--IISFIX: WebDAV is also buggy, and interferes with client requests-->
          <remove name="WebDAV"/>
    
        </handlers>
      </system.webServer>
    </configuration>
    

    The problem now is that the web-site will not work on anyone else's machine; there are now hard-coded paths to files in web.config.

    Why, oh why, couldn't Microsoft just do things right.

    For completeness

    For my own reference, here are the other things that i need to add to web.config every time because the defaults are wrong:

      <system.web>
        <httpRuntime/>
        <!-- IISFIX: By default IIS hides errors-->
        <customErrors mode="Off"/>
        <!-- IISFIX: By default IIS ignores the browser's culture -->
        <globalization culture="auto" uiCulture="auto"/>
      </system.web>
    
      <!-- ASP.net web-sites do not support WebPageTraceListener (only ASP.net web-applications) 
      So this section doesn't work; and does nothing. 
      But if Microsoft ever fixes IIS, we will start working automagically. -->
      <system.diagnostics>
        <trace>
          <listeners>
            <add name="WebPageTraceListener" type="System.Web.WebPageTraceListener, System.Web, Version=2.0.3600.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
          </listeners>
        </trace>
      </system.diagnostics>
    
      <system.webServer>
        <!-- IISFIX: By default IIS ignores custom error pages -->
        <httpErrors existingResponse="PassThrough"/>
      </system.webServer>