IIS: 405 (Method not allowed) when posting to default page - iis

i want to POST form data to the default page of a web-server, e.g.:
POST http://errorreporting.example.com/ HTTP/1.1
i want the server to be responsible for 302 redirecting the client to where the POST should go. The default.asp file on the server performs this task (which is the technique Microsoft recommends), by performing the Redirect:
default.asp:
<%
Response.Redirect "SubmitError.ashx"
%>
When i simply browse the server:
GET http://errorreporting.example.com/ HTTP/1.1
i get the expected response from the server:
HTTP/1.1 302 Object moved
Server: Microsoft-IIS/5.0
Location: SubmitError.ashx
...
But when i POST to the server:
POST http://errorreporting.example.com/ HTTP/1.1
The server gets very grumpy with me:
HTTP/1.1 405 Method not allowed
Connection: close
Allow: OPTIONS, TRACE, GET, HEAD
...
i want the server to be able to redirect the client to the appropriate submit URL, rather than hard-coding the client with the URL. This is, of course, because the URL could (i.e. has) changed:
http://errorreporting.example.com/SubmitError.asp
http://errorreporting.example.com/SubmitError.aspx
http://errorreporting.example.com/SubmitError.ashx
http://errorreporting.example.com/ErrorReporting/Submit.ashx
http://errorreporting.example.com/submiterror.php
http://errorreporting.example.com/submit/submiterror.ashx
etc.
Note: If i change the URL to include the document location:
/* SErrorReportingUrl = 'http://www.example.com:8088/ErrorReporting/SubmitError.ashx';
SErrorReportingUrl = 'http://www.example.com/ErrorReporting/SubmitError.ashx';
SErrorReportingUrl = 'http://errorreporting.example.com:8088/ErrorReporting/SubmitError.ashx';
SErrorReportingUrl = 'http://errorreporting.example.com/SubmitError.ashx';
SErrorReportingUrl = 'http://errorreporting.example.com';
SErrorReportingUrl = 'http://errorreporting.example.com/SubmitError.ashx';
*/
SErrorReportingUrl = 'http://errorreporting.example.com/submit/SubmitError.ashx';
It works fine:
HTTP/1.1 200 OK

Turns out getting IIS to support POST doesn't really help.
i'm using XMLHttpRequest to perform the POSTs. Nearly every implementation of XMLHttpRequest out there (e.g. Chrome, Internet Explorer, MSXML) has a bug where it performs a GET, instead of a POST, after following the redirect.
The W3C's XMLHttpReqest specification says that redirects should be followed and requests reissued:
If the response is an HTTP redirect:
If the redirect does not violate security
(it is same origin for instance),
infinite loop precautions, and the
scheme is supported, transparently
follow the redirect while observing
the same-origin request event rules.
Note: HTTP places requirements on the user
agent regarding the preservation of
the request method and request entity
body during redirects, and also
requires end users to be notified of
certain kinds of automatic
redirections.
And here's a site where you can test the bug in your browser's XmlHttpRequest implementation.
In the end, i'll work around an IIS bug, and an XMLHttpRequest bug, by having my "default" page do everything that a 302 redirect would, but return 200 OK instead:
HTTP/1.1200 OK
Connection: close
Date: Sun, 27 Jun 2010 13:28:14 GMT
Server: Microsoft-IIS/6.0
Location: http://errorreporting.example.com/submit/SubmitError.ashx
Content-Length: 92
Content-Type: text/html
Cache-control: private
<HTML><BODY>This content has moved here.</BODY></HTML>
i'm forcing the client to do two hits anyway - might as well have it work right.

I'm running Vue.js on Express/Node. The back-end is running on server port 3300, but we didn't want to expose that publicly.
I installed the requirements (Application Request Writing and URL Rewrite) and then added an Inbound Rule to rewrite the back-end requests to Express, but I kept getting 405 (Method not allowed).
Eventually I got it going by gleaning a few ideas from Stefano Scerra's Blog.
Here's my final web.config:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Handle History Mode and custom 404/500" stopProcessing="true">
<match url="(.*)" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true"/>
</conditions>
<action type="Rewrite" url="/" />
</rule>
<rule name="api" stopProcessing="true">
<match url="^api/(.*)$" />
<action type="Rewrite" url="http://10.1.1.217:3300/{R:1}" logRewrittenUrl="true" />
</rule>
</rules>
</rewrite>
<tracing>
<traceFailedRequests>
<add path="*">
<traceAreas>
<add provider="WWW Server" areas="Filter" verbosity="Verbose" />
</traceAreas>
<failureDefinitions timeTaken="00:00:00" statusCodes="100-999" />
</add>
</traceFailedRequests>
</tracing>
</system.webServer>
</configuration>

Related

Windows server 2019 and IIS 10 GET,POST work fine but can't use PUT,DELETE from external

I try to install react(axios) in IIS and use node.js as server GET,POST work fine but PUT,DELETE (can use in internal) did not
I tested in Linux server node.js work fine, I try to solve for week such as ExtensionlessUrlHandler ,cors, etc. now I disable Request filter in IIS still did not work.
Failed to load resource: net::ERR_CONNECTION_RESET
(I can not upload picture.)
Common HTTP Features (4 of 6 installed)
Default Document
Directory Browsing
HTTP Errors
Static Content
Health and Diagnostics
HTTP Logging
Performance
Static Content Compression
Application Development
CGI
ISAPI Extensions
ISAPI Filters
WebSocket Protocol
Management Tools
IIS Management Console
web.config
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
This error may be caused by cookies and most often seen with chrome users.
You can try the following steps to solve your problem.
Go to Chrome settings > Privacy and security > Cookies and other site data > Cookie > All cookie and Site Data > Delete domain problem
Or you can refer to this link: Failed to load resource: net::ERR_CONNECTION_RESET

Azure Http to Https redirect not working for SPA

I am trying to enable http to https redirection in our Azure App Service using web.config rewrite rules. According to all documentation I can find, web config redirect using rewrite rules is the official way to get this feature. One of the features that I like and want to support is gzip as an Accepted-Encoding, this is enabled be default. But those two features seem to conflict. Is there another way to do the redirect? Do I have to disable compression?
Here is my redirect rule:
<rule name="Redirect to https" stopProcessing="true">
<match url="(.*)"/>
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="Off"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" appendQueryString="true" />
</rule>
Curl command that responds with the content that I only want to be delivered over SSL:
curl "http://[MyUrl]/" -H "Accept-Encoding: gzip, deflate" --compressed
Curl command that executes as expected:
curl "http://[MyUrl]/"
Response:
HTTP/1.1 301 Moved Permanently
Content-Length: 154
Content-Type: text/html; charset=UTF-8
Location: https://[MyUrl]/
Server: Microsoft-IIS/8.0
X-Powered-By: ASP.NET
Date: Tue, 29 Aug 2017 19:29:29 GMT
Thanks in advance.
In case this is valuable, requests outside of the root url seem to work as expected. Only the root url seems to return the content without the redirect.
Update
I think this might have to do with my SPA rewrite rule, although I am not sure of the interference as the first rule has stopProcessing on it. I was able to recreate the issue at cdwredirecttest.azurewebsites.net. If you hit the site, it will redirect you to https, but only the first time. Open another browser and try again, this time it will load the site over http. After the server caches the gzip response you no longer get redirected. Here is my full web.config:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to https" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="Off" ignoreCase="true"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" appendQueryString="true" />
</rule>
<rule name="Redirect all requests">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="index.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
According to your description, I followed your URL rewrite rule and tested on my azure web app. I specified the -L option in order to enable curl to follow HTTP redirects as follows:
curl "http://{your-webapp}.azurewebsites.net/" -L -H "Accept-Encoding: gzip, deflate" --compressed -v
curl "http://{your-webapp}.azurewebsites.net/home/index" -L -H "Accept-Encoding: gzip, deflate" --compressed -v
I could retrieved the response with the Content-Encoding: gzip header from the above commands as follows:
After digging around and recreating the issue, I opened a ticket with Microsoft. The issue is specifically around Single Page Applications and SSL redirecting using rewrite rules when compressed content is accepted. Apparently IIS is caching the gzip response so the SSL redirection never occurs. The solution is to disable caching:
<system.webServer>
...
<caching enabled="false" enableKernelCache="false"/>
...
</system.webServer>
These are the steps that I came up with to recreate the issue:
Create a new Azure App Service
Rename hostingstart.html to index.html (probably not necessary except the rewrite rule later uses it)
Add the following web.config
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Redirect to HTTPS" stopProcessing="true">
<match url="^(.*)$" ignoreCase="true" />
<conditions logicalGrouping="MatchAny">
<add input="{HTTPS}" pattern="Off" ignoreCase="true"/>
</conditions>
<action type="Redirect" url="https://{HTTP_HOST}/{R:1}" redirectType="Permanent" appendQueryString="true" />
</rule>
<rule name="Single Page App">
<match url="^(.*)$" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" pattern="" ignoreCase="false" />
</conditions>
<action type="Rewrite" url="index.html" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Load the http site in a curl. This will cause the redirect response to happen as expected.
curl "http://cdwredirecttest.azurewebsites.net" -H "Accept-Encoding: gzip, deflate" --compressed
Load the https site in curl. You will get the page content as expected (I believe IIS is caching this gzip response and using it later).
curl "https://cdwredirecttest.azurewebsites.net" -H "Accept-Encoding: gzip, deflate" --compressed
Load the http site in a curl. If you get a redirect response, you will need to repeat 5 and 6. Eventually the response will return the content.
curl "http://cdwredirecttest.azurewebsites.net" -H "Accept-Encoding: gzip, deflate" --compressed
Now load a web browser that has not cached the redirect response. You will load the site over http instead of redirecting to https.
As soon as IIS gives up the cached response, you can use curl to see the redirect and you can repeat 5 and 6 to get the app into the failing state again.

Access-Control-Allow-Origin issue with CORS and HTTPS redirect (IIS / IISNode / NodeJS)

I have a web application that is in two parts:
The "front-end" based in Angular (under Chrome) running on localhost:8000
The "back-end" based in ExpressJS/NodeJS, running on localhost:3000
In trying to gradually convert the application to entirely use HTTPS, I thought it would be better to convert the back-end, first. I have built it so that I can toggle the ability to enable/disable HTTPS on the back-end.
I have set up the back-end to run:
With two bindings under IIS: http and https
The NodeJS application under IISNode.
The problem comes about when I attempt to run the entire application (front- and back-end) under localhost in a local development environment, but with an HTTP-to-HTTPS rewrite (redirect) rule. After that I receive CORS errors on the front-end.
In short, in my local development environment, I am attempting:
After reading on all things CORS for hours, I adjusted the web.config and the applicationHost.config based upon this blog post and this StackOverflow article in an attempt to capture the Request Origin header value. Here is what they look like.
My applicationHost.config contains this section:
<location path="Default Web Site">
<system.webServer>
<rewrite>
<allowedServerVariables>
<add name="CAPTURED_ORIGIN" />
<add name="RESPONSE_Access-Control-Allow-Origin" />
</allowedServerVariables>
</rewrite>
</system.webServer>
</location>
And here is my Web.config:
<?xml version="1.0" encoding="utf-8"?>
<!--
This configuration file is required if iisnode is used to run node processes behind
IIS or IIS Express. For more information, visit:
https://github.com/tjanczuk/iisnode/blob/master/src/samples/configuration/web.config
-->
<configuration>
<system.webServer>
<handlers>
<!-- Indicates that the server.js file is a node.js site to be handled by the iisnode module -->
<add name="iisnode" path="bin/www" verb="*" modules="iisnode" />
</handlers>
<rewrite>
<rules>
<rule name="Capture Origin Header">
<match url=".*" />
<conditions>
<add input="{HTTP_ORIGIN}" pattern=".+" />
</conditions>
<serverVariables>
<set name="CAPTURED_ORIGIN" value="{C:0}" />
</serverVariables>
<action type="None" />
</rule>
<!-- HTTP-to-HTTPS redirect -->
<rule name="Redirect to HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" ignoreCase="true" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="true">
<add input="{HTTPS}" pattern="^off$" />
<add input="{HTTP_HOST}" pattern="([^/:]*?):[^/]*?" />
</conditions>
<action type="Redirect" url="https://{C:1}:3443/{R:0}" appendQueryString="true" redirectType="Temporary" />
</rule>
<!-- First we consider whether the incoming URL matches a physical file in the /public folder -->
<rule name="StaticContent">
<action type="Rewrite" url="public{REQUEST_URI}" />
</rule>
<!-- All other URLs are mapped to the node.js site entry point -->
<rule name="DynamicContent">
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="True" />
</conditions>
<action type="Rewrite" url="bin/www" />
</rule>
</rules>
<outboundRules>
<rule name="Set-Access-Control-Allow-Origin for known origins">
<match serverVariable="RESPONSE_Access-Control-Allow-Origin" pattern=".+" negate="true" />
<action type="Rewrite" value="{CAPTURED_ORIGIN}" />
</rule>
</outboundRules>
</rewrite>
<!-- Make sure error responses are left untouched -->
<httpErrors existingResponse="PassThrough" />
</system.webServer>
<appSettings>
<add key="HTTPS_ENABLED" value="true" />
</appSettings>
</configuration>
The NodeJS application is also set up to handle CORS from localhost:8000, localhost:3000, localhost:3443 (local https), and "null" (converted to a string). (More on that, later.)
But if I use this configuration, then I get the following error in the front-end:
XMLHttpRequest cannot load
http://localhost:3000/foo/bar/
Response for preflight is invalid (redirect)
I suspect this is because IIS handled the redirect, but as a result it is handling the preflight check (HTTP OPTIONS) with an invalid response (redirect). However, according to this StackOverflow article, and the answer by #sideshowbarker, leads me to believe that the current version of Chrome, 59.0.3071.104, should be able to handle the HTTP redirect response from the CORS preflight OPTIONS request.
If I remove the server variables from the applicationHost.config and the HTTP-to-HTTPS rewrite and other rules and from the web.config, and then add code to allow the NodeJS application to handle the redirect to HTTPS, then the revised application looks like this:
Then it appears an unknown (NodeJS? IIS?) server error occurs because the request is cancelled:
You can see the cancellation in chrome://net-internals/#events even though the Origin in the request and the Access-Control-Allow-Origin in the response headers match:
There is no useful error message (even though one is being received by the client) which leads me to believe that it is IIS and not NodeJS that is cancelling the request and sending back no useful information.
I ended up adding a "null" entry to handle CORS when running under the NodeJS Lite Server (and not IIS as an experiment), but I need this to run under IIS/IISNode. However, there seems to be a problem with then IIS / IISNode / NodeJS combination.
I suspect that the Request Origin of "null" is most likely the result of a request, where the server performs a redirect, because you really have two requests:
- The original request from the browser
- The request that is the result of the redirect
When the redirect occurs, I am hypothesizing that the origin in the redirected request is not that same as the original URL, and for the reasons stated in https://www.w3.org/TR/cors/#generic-cross-origin-request-algorithms, the Origin request header within the redirect is null.
However, that doesn't explain, why, when I let NodeJS handle the redirect that the Origin request and the Access-Control-Allow-Origin response header values are both null and the request still gets cancelled. :-/
Finally, if I eliminate any attempt at HTTP-to-HTTPS redirect, then the application works without issue in my development environment.
The response to the preflight OPTIONS itself must always be a 2xx response—e.g., 200 or 204. The response to the preflight itself can never be a redirect—e.g., 302. The spec prohibits that.
But the response cited in the question shows a server responding with such a redirect; hence the error message cited. If a browser gets a 3xx response to a preflight OPTIONS request, the spec requires that the browser stop right there—to consider the preflight as failing.
So the only solution is to fix the server so it doesn’t give a redirect response for that OPTIONS.
There’s a different scenario with redirects and preflights that’s described in the question at CORS request with Preflight and redirect: disallowed. Workarounds?. In that scenario, this is what occurs:
OPTIONS /documents/123 --> 204 (everything okay, please proceed)
GET /documents/123 --> 303 redirect to `/documents/abc`
That is, the response to the OPTIONS request itself is a 2xx success, but the response to the subsequent actual request that the frontend code is sending is a 3xx.
For that case, the spec previously required browsers to stop and not allow the frontend code making the request to have access to the response, and browsers would respond with an error:
The request was redirected to 'http://localhost:3000/foo/bar/',
which is disallowed for cross-origin requests that require preflight.
Note that’s different than the error message cited for the scenario in the question, which is:
XMLHttpRequest cannot load http://localhost:3000/foo/bar/ Response
for preflight is invalid (redirect)
In that scenario (the one in the question), this is instead what occurs:
OPTIONS /documents/123 --> 307 redirect to `/documents/abc`
That is, the response to the OPTIONS is 3xx. The spec still requires a preflight failure for that.
But that other disallowed for cross-origin requests that require preflight case no longer requires failure, and that error should no longer occur in browsers; the spec changed in August 2016 to no longer require it, and all browser engines subsequently updated to match that change.
Chrome was the last browser to implement the update, but it was fixed in the Chrome sources in December 2016, and the fix shipped in Chrome 57.

URL Rewrite causes "This page can’t be displayed"

I have implemented URL Rewriting at the server level as I wanted to redirect all HTTP and HTTPS requests that matches a certain rule to my actual site, and redirection should only take place if the users are hitting my actual site. The rules works fine initially. However, triggering CTRL+R repeatedly on my actual site seems to render my site unaccessible. The error "This page can't be displayed" is then returned to the user. This test was done on IE 11 browser on Windows x64, and my web server is IIS 8.5 on Windows Server 2012 R2. The HTTP response code returned for redirect is configured as 307.
When I turn on Failed Request Routing on my IIS server, I see a warning message on REWRITE_DISABLED_KERNEL_CACHE in the Failed Request Logs. This was the time when the page returns "This page can't be displayed".
Disabling my URL Rewrite rule would immediately render both my HTTP and HTTPS sites accessible once again, and I've verified that redirect no longer works. Enabling the same rule thereafter but on my HTTPS site only would work.
As follows is my redirection rule
<system.webServer>
...
<rewrite>
<globalRules>
<clear />
<rule name="HTTPS to HTTP" enabled="true" stopProcessing="true">
<match url="^(downloads?/?)?$" />
<conditions logicalGrouping="MatchAll" trackAllCaptures="false">
<add input="{REQUEST_URI}" pattern="http://.*?/downloads/" negate="true" />
</conditions>
<action type="Redirect" url="http://{HTTP_HOST}/downloads/" appendQueryString="false" redirectType="Temporary" />
</rule>
</globalRules>
<outboundRules>
</outboundRules>
</rewrite>
...
</system.webServer>
Basically, if the request hits any of the following example URLs, I will redirect them:
1) http://fqdn/download
2) http://fqdn/download/
3) https://fqdn/downloads
4) https://fqdn/downloads/
5) https://fqdn/download
6) https://fqdn/download/
I will not redirect, if the request hits my site directly:
http://fqdn/downloads/
When I hit my actual site, I realise that the redirection rule is still being applied. So I suspect there could be 2 different issues over here.
1) An infinite redirection rule being applied when requests are sent to http://fqdn/downloads/
2) Some unknown problem with REWRITE_DISABLED_KERNEL_CACHE
You're in trouble with infinite redirects because of your wrong assumptation about REQUEST_URI and the lack of HTTPS check.
{REQUEST_URI} contains URL's path, including the query string with a leading slash (never been welldocumented), never contains uri scheme or hostname. So, you have a false positive.
http(s)://<host>:<port>/<path>?<querystring>
Here's a self-explanatory rule.
<rule name="Force Http downloads page" stopProcessing="true">
<!-- If the url starts with download or downloads with an optional trailing slash -->
<match url="^downloads?/?$" />
<!-- Redirect -->
<action type="Redirect" url="http://{HTTP_HOST}/downloads/" appendQueryString="false" redirectType="Temporary" />
<!-- When -->
<conditions logicalGrouping="MatchAny">
<!-- REQUEST_URI does not start with "/downloads/" -->
<add input="{REQUEST_URI}" pattern="^/downloads/" negate="true" />
<!-- Or -->
<!-- HTTPS is not off -->
<add input="{HTTPS}" pattern="^off$" negate="true" />
</conditions>
</rule>
Hope it helps.

IIS 8.5 Url Rewrite Issue - Redirect Location Includes IP Address

I create a URL Rewrite Rule to remove the WWW from incoming requests based on http://madskristensen.net/post/url-rewrite-and-the-www-subdomain
Here is the rule straight from my web.config:
<rewrite>
<rules>
<rule name="Remove WWW" patternSyntax="Wildcard" stopProcessing="true">
<match url="*" />
<conditions>
<add input="{CACHE_URL}" pattern="*://www.*" />
</conditions>
<action type="Redirect" url="{C:1}://{C:2}" redirectType="Permanent" />
</rule>
</rules>
</rewrite>
When I try to open www.mydomain.com, FireFox gives me a "Corrupted Content Error" message. If I try to open it in Chrome, nothing happens.
Here are the response headers via Fiddler:
HTTP/1.1 301 Moved Permanently
Content-Type: text/html; charset=UTF-8
Location: http://example.com:80:123.123.123.123/
Server: Microsoft-IIS/8.5
X-Powered-By: ASP.NET
Date: Mon, 07 Dec 2015 18:20:53 GMT
Content-Length: 167
Response body:
<head>
<title>Document Moved</title>
</head>
<body>
<h1>Object Moved</h1>This document may be found here
</body>
Notice how the port and IP address are included in the Location. (I have replaced the IP Address of my server with 123.123.123.123)
Is this causing the issue? If so, why is it including this information and how to I remove it?
I restarted IIS after installing URL Rewrite.
Not really a solution, but my workaround...
My site is setup to require SSL so I don't really need the benefit of removing WWW for both protocols.
I have updated my rule as follows:
<rule name="Remove WWW and Redirect to HTTPS" enabled="true" stopProcessing="true">
<match url="(.*)" />
<conditions>
<add input="{HTTP_HOST}" pattern="^(www\.)(.*)$" />
</conditions>
<action type="Redirect" url="https://{C:2}/{R:1}" />
</rule>

Resources