Blog

Building the C2 Blog: Form Posting with IIS Application Request Routing (ARR)

by |

When development goes well, the user does not see any of the underlying complexity of the technology they’re interacting with – it either works or it doesn’t. Development however, does not always follow a straight line path to reach this. Take this blog for example.

After our initial configuration, we found that it was relatively easy to set up a reverse proxy from IIS to our WordPress site without writing a line of code. However, once we started testing, we found that we were not able to post any comments without getting an HTTP 502.3 error. As we investigated, we discovered that the inability to post comments was a symptom of a deeper problem; we were not able to access any page using the HTTP POST method.

To find the underlying cause of the issue, we used Fiddler to act as a proxy between IIS and WordPress, we found that IIS was passing the headers along to WordPress, but was completely stripping out all form data. Apache was likely waiting on the form data as part of the request, was timing out, and IIS threw the 502.3 error. This let us know that the issue was somewhere on the Windows side.

After some further investigation, we found that form data gets completely stripped out of a request if the form data is accessed from a .NET application. The Sitecore.Nexus.Web.HttpModule module was accessing the form data behind an obfuscated DLL, which caused all the headaches. The DLL accesses this form data for every request, even if Sitecore is supposed to ignore it.

The Solution

Our solution was to create an additional module that puts this data back in:

[csharp]
public class FormModule : IHttpModule {
private string[] _prefixes;
public void Dispose() {
}
public void Init(HttpApplication context) {
string prefixes = ConfigurationManager.AppSettings["UrlPrefixesToAddFormData"];
if (!string.IsNullOrWhiteSpace(prefixes)) {
_prefixes = prefixes.Split(‘|’);
context.BeginRequest += Context_BeginRequest;
}
}
private void Context_BeginRequest(object sender, EventArgs e) {
HttpApplication application = (HttpApplication) sender;
HttpContext context = application.Context;
HttpRequest request = context.Request;
if (request.HttpMethod == "POST" &&
_prefixes.Any(p => request.FilePath.StartsWith(p, StringComparison.OrdinalIgnoreCase))) {
request.InsertEntityBody();
}
}
}
[/csharp]

As part of this module, we created a new appconfig key/value called “UrlPrefixesToAddFormData” containing a pipe-delimited list of URL prefixes. For consistency, we used the same format as Sitecore’s IgnoreUrlPrefix. When a request comes in, we check to see if the HttpMethod is “POST”, and the request path starts with any of the prefixes listed in the config. If the request matches these conditions, we call HttpRequest.InsertEntityBody(), which re-adds the form data; if the request does not match, we do nothing. Since very few requests match these conditions, the performance cost is negligent.

Once we put the code in place, we had to change the config to run this new module. First, we need to set runAllManagedModulesForAllRequests to true. This ensures that our new module will be run for all requests. Without this, HttpResponse.End() could be called prior to FormModule running, and our code would not get executed. Next, add FormModule as the last module in the list.

[xml]
<modules runAllManagedModulesForAllRequests="true">
<!–Some modules removed–>
<!–Some modules added–>
<add type="Sitecore.Nexus.Web.HttpModule,Sitecore.Nexus" name="SitecoreHttpModule"/>
<!–More modules added–>
<add name="FormModule" type="C2Website.Classes.FormModule, C2Website"/>
</modules>
[/xml]

This solved the issue for our blog, Fiddler did solid work in monitoring all proxy requests between IIS and the remote site. I’d recommend using it to find how things might be going wrong between requests and responses.

Be Competitive with Technology™ Today!

Learn More

We’re always looking for new talent and fresh ideas.

Explore Careers