Вопрос

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:

  • it works fine inside Cassini (the .NET based web-server used by Visual Studio)
  • nothing is logged in the Windows Event log
  • Custom errors are off in the site's web.config
  • No verbs are being filtered (or all verbs are being included)
  • WebDAV module is disabled
  • LiveStreamingHandler module is not installed

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:

  • GET: works
  • POST: works
  • PUT: works
  • HEAD: works
  • TRACE: 501 Not Implemented
  • DELETE: 500 Internal Server Error
  • SEARCH: 405 Method Not Allowed
  • PROPFIND: 500 Internal Server Error
  • PROPPATCH: 500 Internal Server Error
  • PATCH: 405 Method Not Allowed
  • MKCOL: 405 Method Not Allowed
  • COPY: 500 Internal Server Error
  • MOVE: 500 Internal Server Error
  • LOCK: 500 Internal Server Error
  • UNLOCK: 500 Internal Server Error
  • OPTIONS: 200 OK
  • IISUCKSFOO 405 Method Not Allowed

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!

Это было полезно?

Решение

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>
    <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>

Другие советы

I found that removing webDav references from handlers and modules in the above solution still resulted in IIS 7.5, IIS 7 Windows server 2008 r2 (I never tested IIS 8) for http methods PUT, DELETE

HTTP Error 500.21 - Internal Server Error Handler "ExtensionlessUrlHandler-Integrated-4.0" has a bad module "ManagedPipelineHandler"

This server error is misleading and also given for improper .net installations where a handler is missing, and can be fixed by re-installing .Net, but that's probably not a solution, if it only affects PUT or DELETE requests to the extension-less route handler (GET, POST, and OPTIONS were fine). I read so many posts about enabling put and delete methods in MVC and Web api that seemed to claim this was a fix so I tried it anyway several times, restarted IIS etc, no change in the error.

the problem did not no go away until I added runManagedModulesForWebDavRequests="true" attribute to the modules element.

< modules runAllManagedModulesForAllRequests="true" runManagedModulesForWebDavRequests="true" >

http://www.iis.net/configreference/system.webserver/modules

By default runManagedModulesForWebDavRequests ="false" which means any webDav request is routed to WebDav. So far as I can deduce, A webdav request is all http PUT or DELETE requests as far as IIS is concerned, even if you have removed the webdav handler from web config and your request body doesn't conform to a webdav request. It's possible that uninstalling webDav might also correct the problem, but I never tried that; I have other sites running on the same server that depend on it.

I found the answer here:

ASP.NET Core with IIS - HTTP Verb Not Allowed

This is the web.config

<configuration>
<!-- To customize the asp.net core module uncomment and edit the following section. 
     For more info see https://go.microsoft.com/fwlink/?linkid=838655 -->
<system.webServer>
    <modules>
        <remove name="WebDAVModule" />
    </modules>
    <handlers>
        <remove name="aspNetCore" />
        <remove name="WebDAV" />
        <!-- I removed the following handlers too, but these
             can probably be ignored for most installations -->
        <remove name="ExtensionlessUrlHandler-Integrated-4.0" />
        <remove name="OPTIONSVerbHandler" />
        <remove name="TRACEVerbHandler" />

        <add name="aspNetCore" 
             path="*" 
             verb="*" 
             modules="AspNetCoreModule" 
             resourceType="Unspecified" />
    </handlers>
    <aspNetCore processPath="%LAUNCHER_PATH%" 
                arguments="%LAUNCHER_ARGS%" 
                stdoutLogEnabled="false"
                stdoutLogFile=".\logs\stdout" />
</system.webServer>

Something to note on this in the future is when you code gets deployed to anything not local, that you change possible hard coded credentials to you generic access accounts. I had this exact issue for a full day and a half and saw that a DELETE .net request that worked with an LDAP was using a hard coded employee ID of a former employee as the UserPrincipalName. It worked fine until his ID finally got removed from our system then everything went bad. Again after a day and half we found the hard coded credentials used for testing purposes. Simple example to illustrate the different things that have to be accounted for on different testing environments.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top